From b465b5c13c6c4e1caf4f79e8ef027674c03a0bfa Mon Sep 17 00:00:00 2001 From: fallenoak Date: Sun, 21 Jan 2024 23:11:58 -0600 Subject: [PATCH] feat(model): improve shader selection logic (#57) --- package-lock.json | 8 ++-- package.json | 2 +- src/lib/model/loader/ModelLoaderWorker.ts | 18 +++----- src/lib/model/loader/types.ts | 12 +++-- src/lib/model/loader/util.ts | 51 +-------------------- src/lib/model/shader/fragment.ts | 48 +++++++++----------- src/lib/model/shader/vertex.ts | 55 +++++++++++------------ src/lib/model/types.ts | 22 --------- 8 files changed, 68 insertions(+), 148 deletions(-) delete mode 100644 src/lib/model/types.ts diff --git a/package-lock.json b/package-lock.json index 8aebb0c..175a37f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "license": "MIT", "dependencies": { "@tweenjs/tween.js": "^23.1.1", - "@wowserhq/format": "^0.18.0" + "@wowserhq/format": "^0.19.0" }, "devDependencies": { "@commitlint/config-conventional": "^18.4.4", @@ -2342,9 +2342,9 @@ } }, "node_modules/@wowserhq/format": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/@wowserhq/format/-/format-0.18.0.tgz", - "integrity": "sha512-51FlpmQFaahpNPaeWR0+LAqC3np+ms+hmUCrdwIM2yZInEq3mDMq7K3fm0YBvEHZT9bfxj65DxW1jtfhjm7+/A==", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/@wowserhq/format/-/format-0.19.0.tgz", + "integrity": "sha512-ZydthdlFhZsxCg9ftOx5X985yznRoKYcajvLz+6cuQUxSwpaC0Gm2LDjwaXyKD/OEJsui2OzS3liGwk2IjuZAw==", "dependencies": { "@wowserhq/io": "^2.0.2", "gl-matrix": "^3.4.3" diff --git a/package.json b/package.json index 116139d..607b52f 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ ], "dependencies": { "@tweenjs/tween.js": "^23.1.1", - "@wowserhq/format": "^0.18.0" + "@wowserhq/format": "^0.19.0" }, "peerDependencies": { "three": "^0.160.0" diff --git a/src/lib/model/loader/ModelLoaderWorker.ts b/src/lib/model/loader/ModelLoaderWorker.ts index 818c6f9..cebdeac 100644 --- a/src/lib/model/loader/ModelLoaderWorker.ts +++ b/src/lib/model/loader/ModelLoaderWorker.ts @@ -1,6 +1,6 @@ import { M2Batch, M2Model, M2SkinProfile } from '@wowserhq/format'; import { ModelSpec } from './types.js'; -import { getBoundsCenter, getFragmentShader, getVertexShader } from './util.js'; +import { getBoundsCenter } from './util.js'; import SceneWorker from '../../worker/SceneWorker.js'; import { AssetHost, loadAsset } from '../../asset.js'; @@ -87,23 +87,17 @@ class ModelLoaderWorker extends SceneWorker { #createMaterialSpec(batch: M2Batch) { const textures = batch.textures.map((texture) => ({ - flags: texture.texture.flags, - component: texture.texture.component, - path: texture.texture.filename, + flags: texture.flags, + component: texture.component, + path: texture.filename, })); - const coords = batch.textures.map((texture) => texture.textureCoord); - const vertexShader = getVertexShader(coords); - - const combiners = batch.textures.map((texture) => texture.textureCombiner); - const fragmentShader = getFragmentShader(combiners); - return { flags: batch.material.flags, blend: batch.material.blend, textures, - vertexShader, - fragmentShader, + vertexShader: batch.vertexShader, + fragmentShader: batch.fragmentShader, }; } } diff --git a/src/lib/model/loader/types.ts b/src/lib/model/loader/types.ts index 807e8bf..50d12da 100644 --- a/src/lib/model/loader/types.ts +++ b/src/lib/model/loader/types.ts @@ -1,5 +1,9 @@ -import { M2_MATERIAL_BLEND, M2_TEXTURE_COMPONENT } from '@wowserhq/format'; -import { MODEL_SHADER_FRAGMENT, MODEL_SHADER_VERTEX } from '../types.js'; +import { + M2_FRAGMENT_SHADER, + M2_MATERIAL_BLEND, + M2_TEXTURE_COMPONENT, + M2_VERTEX_SHADER, +} from '@wowserhq/format'; type TextureSpec = { flags: number; @@ -10,8 +14,8 @@ type TextureSpec = { type MaterialSpec = { flags: number; textures: TextureSpec[]; - vertexShader: MODEL_SHADER_VERTEX; - fragmentShader: MODEL_SHADER_FRAGMENT; + vertexShader: M2_VERTEX_SHADER; + fragmentShader: M2_FRAGMENT_SHADER; blend: M2_MATERIAL_BLEND; }; diff --git a/src/lib/model/loader/util.ts b/src/lib/model/loader/util.ts index bd23364..26eb99e 100644 --- a/src/lib/model/loader/util.ts +++ b/src/lib/model/loader/util.ts @@ -1,52 +1,3 @@ -import { M2_TEXTURE_COMBINER, M2_TEXTURE_COORD } from '@wowserhq/format'; -import { MODEL_SHADER_FRAGMENT, MODEL_SHADER_VERTEX } from '../types.js'; - -const getVertexShader = (coords: M2_TEXTURE_COORD[]): MODEL_SHADER_VERTEX => { - if (coords.length === 0) { - return MODEL_SHADER_VERTEX.VERTEX_UNKNOWN; - } - - if (coords.length === 1) { - switch (coords[0]) { - case M2_TEXTURE_COORD.COORD_T1: - return MODEL_SHADER_VERTEX.VERTEX_T1; - case M2_TEXTURE_COORD.COORD_T2: - return MODEL_SHADER_VERTEX.VERTEX_T2; - case M2_TEXTURE_COORD.COORD_ENV: - return MODEL_SHADER_VERTEX.VERTEX_ENV; - } - } - - return MODEL_SHADER_VERTEX.VERTEX_UNKNOWN; -}; - -const getFragmentShader = (combiners: M2_TEXTURE_COMBINER[]): MODEL_SHADER_FRAGMENT => { - if (combiners.length === 0) { - return MODEL_SHADER_FRAGMENT.FRAGMENT_UNKNOWN; - } - - if (combiners.length === 1) { - switch (combiners[0]) { - case M2_TEXTURE_COMBINER.COMBINER_OPAQUE: - return MODEL_SHADER_FRAGMENT.FRAGMENT_OPAQUE; - case M2_TEXTURE_COMBINER.COMBINER_MOD: - return MODEL_SHADER_FRAGMENT.FRAGMENT_MOD; - case M2_TEXTURE_COMBINER.COMBINER_DECAL: - return MODEL_SHADER_FRAGMENT.FRAGMENT_DECAL; - case M2_TEXTURE_COMBINER.COMBINER_ADD: - return MODEL_SHADER_FRAGMENT.FRAGMENT_ADD; - case M2_TEXTURE_COMBINER.COMBINER_MOD2X: - return MODEL_SHADER_FRAGMENT.FRAGMENT_MOD2X; - case M2_TEXTURE_COMBINER.COMBINER_FADE: - return MODEL_SHADER_FRAGMENT.FRAGMENT_FADE; - default: - return MODEL_SHADER_FRAGMENT.FRAGMENT_MOD; - } - } - - return MODEL_SHADER_FRAGMENT.FRAGMENT_UNKNOWN; -}; - const getBoundsCenter = (extent: Float32Array) => { const center = new Float32Array(3); @@ -57,4 +8,4 @@ const getBoundsCenter = (extent: Float32Array) => { return center; }; -export { getVertexShader, getFragmentShader, getBoundsCenter }; +export { getBoundsCenter }; diff --git a/src/lib/model/shader/fragment.ts b/src/lib/model/shader/fragment.ts index 1f0bbd3..7ff9b59 100644 --- a/src/lib/model/shader/fragment.ts +++ b/src/lib/model/shader/fragment.ts @@ -1,4 +1,4 @@ -import { MODEL_SHADER_FRAGMENT } from '../types.js'; +import { M2_FRAGMENT_SHADER } from '@wowserhq/format'; import { VARIABLE_FOG_FACTOR, FUNCTION_APPLY_FOG, UNIFORM_FOG_COLOR } from '../../shader/fog.js'; import { composeShader } from '../../shader/util.js'; @@ -73,6 +73,10 @@ void combineOpaqueMod2x(inout vec4 color, in vec4 tex0, in vec4 tex1) { color.rgb = (color.rgb * tex0.rgb) * tex1.rgb * 2.0; color.a = color.a * tex1.a * 2.0; } + +void combineOpaqueMod2xNa(inout vec4 color, in vec4 tex0, in vec4 tex1) { + color.rgb = (color.rgb * tex0.rgb) * tex1.rgb * 2.0; +} `; const FRAGMENT_SHADER_MAIN_ALPHATEST = ` @@ -158,33 +162,23 @@ const createFragmentShader = (textureCount: number, combineFunction: string) => }; const FRAGMENT_SHADER = { - COMBINER_OPAQUE: createFragmentShader(1, 'combineOpaque'), - COMBINER_MOD: createFragmentShader(1, 'combineMod'), - COMBINER_DECAL: createFragmentShader(1, 'combineDecal'), - COMBINER_ADD: createFragmentShader(1, 'combineAdd'), - COMBINER_MOD2X: createFragmentShader(1, 'combineMod2x'), - COMBINER_FADE: createFragmentShader(1, 'combineFade'), - DEFAULT: createFragmentShader(0, ''), + [M2_FRAGMENT_SHADER.FRAGMENT_OPAQUE]: createFragmentShader(1, 'combineOpaque'), + [M2_FRAGMENT_SHADER.FRAGMENT_MOD]: createFragmentShader(1, 'combineMod'), + [M2_FRAGMENT_SHADER.FRAGMENT_DECAL]: createFragmentShader(1, 'combineDecal'), + [M2_FRAGMENT_SHADER.FRAGMENT_ADD]: createFragmentShader(1, 'combineAdd'), + [M2_FRAGMENT_SHADER.FRAGMENT_MOD2X]: createFragmentShader(1, 'combineMod2x'), + [M2_FRAGMENT_SHADER.FRAGMENT_FADE]: createFragmentShader(1, 'combineFade'), + [M2_FRAGMENT_SHADER.FRAGMENT_OPAQUE_OPAQUE]: createFragmentShader(2, 'combineOpaqueOpaque'), + [M2_FRAGMENT_SHADER.FRAGMENT_OPAQUE_ADD]: createFragmentShader(2, 'combineOpaqueAdd'), + [M2_FRAGMENT_SHADER.FRAGMENT_OPAQUE_ADDALPHA]: createFragmentShader(2, 'combineOpaqueAddAlpha'), + [M2_FRAGMENT_SHADER.FRAGMENT_OPAQUE_MOD2X]: createFragmentShader(2, 'combineOpaqueMod2x'), + [M2_FRAGMENT_SHADER.FRAGMENT_OPAQUE_MOD2XNA]: createFragmentShader(2, 'combineOpaqueMod2xNa'), + [M2_FRAGMENT_SHADER.FRAGMENT_OPAQUE_ADDNA]: createFragmentShader(2, 'combineOpaqueAddNa'), + [M2_FRAGMENT_SHADER.FRAGMENT_OPAQUE_MOD]: createFragmentShader(2, 'combineOpaqueMod'), + [M2_FRAGMENT_SHADER.FRAGMENT_UNKNOWN]: createFragmentShader(0, ''), }; -const getFragmentShader = (shader: MODEL_SHADER_FRAGMENT) => { - if (shader === MODEL_SHADER_FRAGMENT.FRAGMENT_UNKNOWN) { - return FRAGMENT_SHADER.DEFAULT; - } else if (shader === MODEL_SHADER_FRAGMENT.FRAGMENT_OPAQUE) { - return FRAGMENT_SHADER.COMBINER_OPAQUE; - } else if (shader === MODEL_SHADER_FRAGMENT.FRAGMENT_MOD) { - return FRAGMENT_SHADER.COMBINER_MOD; - } else if (shader === MODEL_SHADER_FRAGMENT.FRAGMENT_DECAL) { - return FRAGMENT_SHADER.COMBINER_ADD; - } else if (shader === MODEL_SHADER_FRAGMENT.FRAGMENT_ADD) { - return FRAGMENT_SHADER.COMBINER_ADD; - } else if (shader === MODEL_SHADER_FRAGMENT.FRAGMENT_MOD2X) { - return FRAGMENT_SHADER.COMBINER_MOD2X; - } else if (shader === MODEL_SHADER_FRAGMENT.FRAGMENT_FADE) { - return FRAGMENT_SHADER.COMBINER_FADE; - } - - return FRAGMENT_SHADER.DEFAULT; -}; +const getFragmentShader = (shader: M2_FRAGMENT_SHADER) => + FRAGMENT_SHADER[shader] ?? FRAGMENT_SHADER[M2_FRAGMENT_SHADER.FRAGMENT_UNKNOWN]; export { getFragmentShader }; diff --git a/src/lib/model/shader/vertex.ts b/src/lib/model/shader/vertex.ts index f878fc8..bd3ff9b 100644 --- a/src/lib/model/shader/vertex.ts +++ b/src/lib/model/shader/vertex.ts @@ -1,5 +1,4 @@ -import { M2_TEXTURE_COORD } from '@wowserhq/format'; -import { MODEL_SHADER_VERTEX } from '../types.js'; +import { M2_TEXTURE_COORD, M2_VERTEX_SHADER } from '@wowserhq/format'; import { FUNCTION_CALCULATE_FOG_FACTOR, UNIFORM_FOG_PARAMS, @@ -25,7 +24,19 @@ const VERTEX_SHADER_INPUTS = [ const VERTEX_SHADER_OUTPUTS = [{ name: 'vLight', type: 'float' }]; -const VERTEX_SHADER_FUNCTIONS = []; +const VERTEX_SHADER_SPHERE_MAP = ` +vec2 sphereMap(vec3 position, vec3 normal) { + vec3 viewPosition = normalize(vec3(modelViewMatrix * vec4(position, 1.0))); + vec3 viewNormal = normalize(normalMatrix * normal); + + vec3 temp = (-viewPosition - (viewNormal * (2.0 * dot(-viewPosition, viewNormal)))); + temp = vec3(temp.x, temp.y, temp.z + 1.0); + + return (normalize(temp).xy * 0.5) + vec2(0.5); +} +`; + +const VERTEX_SHADER_FUNCTIONS = [VERTEX_SHADER_SPHERE_MAP]; const VERTEX_SHADER_MAIN_LIGHTING = ` vec3 viewNormal = normalize(normalMatrix * normal); @@ -91,8 +102,7 @@ const createVertexShader = (texCoord1?: M2_TEXTURE_COORD, texCoord2?: M2_TEXTURE } else if (texCoord1 === M2_TEXTURE_COORD.COORD_T2) { main.push(`vTexCoord1 = texCoord2;`); } else if (texCoord1 === M2_TEXTURE_COORD.COORD_ENV) { - // TODO - main.push(`vTexCoord1 = vec2(0.0, 0.0);`); + main.push(`vTexCoord1 = sphereMap(position, normal);`); } if (texCoord2 === M2_TEXTURE_COORD.COORD_T1) { @@ -100,8 +110,7 @@ const createVertexShader = (texCoord1?: M2_TEXTURE_COORD, texCoord2?: M2_TEXTURE } else if (texCoord2 === M2_TEXTURE_COORD.COORD_T2) { main.push(`vTexCoord2 = texCoord2;`); } else if (texCoord2 === M2_TEXTURE_COORD.COORD_ENV) { - // TODO - main.push(`vTexCoord2 = vec2(0.0, 0.0);`); + main.push(`vTexCoord2 = sphereMap(position, normal);`); } main.push(VERTEX_SHADER_MAIN_LIGHTING); @@ -111,29 +120,19 @@ const createVertexShader = (texCoord1?: M2_TEXTURE_COORD, texCoord2?: M2_TEXTURE return composeShader(precision, uniforms, inputs, outputs, functions, main); }; +// prettier-ignore const VERTEX_SHADER = { - T1: createVertexShader(M2_TEXTURE_COORD.COORD_T1), - T2: createVertexShader(M2_TEXTURE_COORD.COORD_T2), - ENV: createVertexShader(M2_TEXTURE_COORD.COORD_ENV), - T1_T2: createVertexShader(M2_TEXTURE_COORD.COORD_T1, M2_TEXTURE_COORD.COORD_T2), - T1_ENV: createVertexShader(M2_TEXTURE_COORD.COORD_T1, M2_TEXTURE_COORD.COORD_ENV), - ENV_T2: createVertexShader(M2_TEXTURE_COORD.COORD_ENV, M2_TEXTURE_COORD.COORD_T2), - ENV_ENV: createVertexShader(M2_TEXTURE_COORD.COORD_ENV, M2_TEXTURE_COORD.COORD_ENV), - DEFAULT: createVertexShader(), + [M2_VERTEX_SHADER.VERTEX_T1]: createVertexShader(M2_TEXTURE_COORD.COORD_T1), + [M2_VERTEX_SHADER.VERTEX_T2]: createVertexShader(M2_TEXTURE_COORD.COORD_T2), + [M2_VERTEX_SHADER.VERTEX_ENV]: createVertexShader(M2_TEXTURE_COORD.COORD_ENV), + [M2_VERTEX_SHADER.VERTEX_T1_T2]: createVertexShader(M2_TEXTURE_COORD.COORD_T1, M2_TEXTURE_COORD.COORD_T2), + [M2_VERTEX_SHADER.VERTEX_T1_ENV]: createVertexShader(M2_TEXTURE_COORD.COORD_T1, M2_TEXTURE_COORD.COORD_ENV), + [M2_VERTEX_SHADER.VERTEX_ENV_T2]: createVertexShader(M2_TEXTURE_COORD.COORD_ENV, M2_TEXTURE_COORD.COORD_T2), + [M2_VERTEX_SHADER.VERTEX_ENV_ENV]: createVertexShader(M2_TEXTURE_COORD.COORD_ENV, M2_TEXTURE_COORD.COORD_ENV), + [M2_VERTEX_SHADER.VERTEX_UNKNOWN]: createVertexShader(), }; -const getVertexShader = (shader: MODEL_SHADER_VERTEX) => { - if (shader === MODEL_SHADER_VERTEX.VERTEX_UNKNOWN) { - return VERTEX_SHADER.DEFAULT; - } else if (shader === MODEL_SHADER_VERTEX.VERTEX_T1) { - return VERTEX_SHADER.T1; - } else if (shader === MODEL_SHADER_VERTEX.VERTEX_T2) { - return VERTEX_SHADER.T2; - } else if (shader === MODEL_SHADER_VERTEX.VERTEX_ENV) { - return VERTEX_SHADER.ENV; - } - - return VERTEX_SHADER.DEFAULT; -}; +const getVertexShader = (shader: M2_VERTEX_SHADER) => + VERTEX_SHADER[shader] ?? VERTEX_SHADER[M2_VERTEX_SHADER.VERTEX_UNKNOWN]; export { getVertexShader }; diff --git a/src/lib/model/types.ts b/src/lib/model/types.ts deleted file mode 100644 index 4f550f7..0000000 --- a/src/lib/model/types.ts +++ /dev/null @@ -1,22 +0,0 @@ -enum MODEL_SHADER_VERTEX { - VERTEX_T1 = 0, - VERTEX_T2, - VERTEX_ENV, - VERTEX_T1_T2, - VERTEX_T1_ENV, - VERTEX_ENV_T2, - VERTEX_ENV_ENV, - VERTEX_UNKNOWN, -} - -enum MODEL_SHADER_FRAGMENT { - FRAGMENT_OPAQUE = 0, - FRAGMENT_MOD, - FRAGMENT_DECAL, - FRAGMENT_ADD, - FRAGMENT_MOD2X, - FRAGMENT_FADE, - FRAGMENT_UNKNOWN, -} - -export { MODEL_SHADER_FRAGMENT, MODEL_SHADER_VERTEX };