Skip to content

Commit

Permalink
feat(model): improve shader selection logic (#57)
Browse files Browse the repository at this point in the history
  • Loading branch information
fallenoak authored Jan 22, 2024
1 parent 74e7764 commit b465b5c
Show file tree
Hide file tree
Showing 8 changed files with 68 additions and 148 deletions.
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
18 changes: 6 additions & 12 deletions src/lib/model/loader/ModelLoaderWorker.ts
Original file line number Diff line number Diff line change
@@ -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';

Expand Down Expand Up @@ -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,
};
}
}
Expand Down
12 changes: 8 additions & 4 deletions src/lib/model/loader/types.ts
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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;
};

Expand Down
51 changes: 1 addition & 50 deletions src/lib/model/loader/util.ts
Original file line number Diff line number Diff line change
@@ -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);

Expand All @@ -57,4 +8,4 @@ const getBoundsCenter = (extent: Float32Array) => {
return center;
};

export { getVertexShader, getFragmentShader, getBoundsCenter };
export { getBoundsCenter };
48 changes: 21 additions & 27 deletions src/lib/model/shader/fragment.ts
Original file line number Diff line number Diff line change
@@ -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';

Expand Down Expand Up @@ -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 = `
Expand Down Expand Up @@ -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 };
55 changes: 27 additions & 28 deletions src/lib/model/shader/vertex.ts
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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);
Expand Down Expand Up @@ -91,17 +102,15 @@ 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) {
main.push(`vTexCoord2 = texCoord1;`);
} 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);
Expand All @@ -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 };
22 changes: 0 additions & 22 deletions src/lib/model/types.ts

This file was deleted.

0 comments on commit b465b5c

Please sign in to comment.