Skip to content

Commit

Permalink
feat(model): improve alpha test handling in model materials
Browse files Browse the repository at this point in the history
  • Loading branch information
fallenoak committed Jan 4, 2024
1 parent 2e2c3e0 commit 8a9bdc6
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 38 deletions.
20 changes: 10 additions & 10 deletions src/lib/blend.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as THREE from 'three';

enum BLEND_MODE {
enum THREE_BLEND_MODE {
BLEND_OPAQUE = 0,
BLEND_ALPHA_KEY,
BLEND_ALPHA,
Expand All @@ -10,50 +10,50 @@ enum BLEND_MODE {
BLEND_MOD2X,
}

const BLEND_STATE = {
[BLEND_MODE.BLEND_OPAQUE]: {
const THREE_BLEND_STATE = {
[THREE_BLEND_MODE.BLEND_OPAQUE]: {
blending: THREE.NoBlending,
blendSrc: THREE.OneFactor,
blendSrcAlpha: THREE.OneFactor,
blendDst: THREE.ZeroFactor,
blendDstAlpha: THREE.ZeroFactor,
},
[BLEND_MODE.BLEND_ALPHA_KEY]: {
[THREE_BLEND_MODE.BLEND_ALPHA_KEY]: {
blending: THREE.NoBlending,
blendSrc: THREE.OneFactor,
blendSrcAlpha: THREE.OneFactor,
blendDst: THREE.ZeroFactor,
blendDstAlpha: THREE.ZeroFactor,
},
[BLEND_MODE.BLEND_ALPHA]: {
[THREE_BLEND_MODE.BLEND_ALPHA]: {
blending: THREE.CustomBlending,
blendSrc: THREE.SrcAlphaFactor,
blendSrcAlpha: THREE.OneFactor,
blendDst: THREE.OneMinusSrcAlphaFactor,
blendDstAlpha: THREE.OneMinusSrcAlphaFactor,
},
[BLEND_MODE.BLEND_NO_ALPHA_ADD]: {
[THREE_BLEND_MODE.BLEND_NO_ALPHA_ADD]: {
blending: THREE.CustomBlending,
blendSrc: THREE.OneFactor,
blendSrcAlpha: THREE.ZeroFactor,
blendDst: THREE.OneFactor,
blendDstAlpha: THREE.OneFactor,
},
[BLEND_MODE.BLEND_ADD]: {
[THREE_BLEND_MODE.BLEND_ADD]: {
blending: THREE.CustomBlending,
blendSrc: THREE.SrcAlphaFactor,
blendSrcAlpha: THREE.ZeroFactor,
blendDst: THREE.OneFactor,
blendDstAlpha: THREE.OneFactor,
},
[BLEND_MODE.BLEND_MOD]: {
[THREE_BLEND_MODE.BLEND_MOD]: {
blending: THREE.CustomBlending,
blendSrc: THREE.DstColorFactor,
blendSrcAlpha: THREE.DstAlphaFactor,
blendDst: THREE.ZeroFactor,
blendDstAlpha: THREE.ZeroFactor,
},
[BLEND_MODE.BLEND_MOD2X]: {
[THREE_BLEND_MODE.BLEND_MOD2X]: {
blending: THREE.CustomBlending,
blendSrc: THREE.DstColorFactor,
blendSrcAlpha: THREE.DstAlphaFactor,
Expand All @@ -62,4 +62,4 @@ const BLEND_STATE = {
},
};

export { BLEND_MODE, BLEND_STATE };
export { THREE_BLEND_MODE, THREE_BLEND_STATE };
13 changes: 9 additions & 4 deletions src/lib/model/ModelManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import ModelMesh from './ModelMesh.js';
import ModelMaterial from './ModelMaterial.js';
import { getVertexShader } from './shader/vertex.js';
import { getFragmentShader } from './shader/fragment.js';
import { M2_MATERIAL_BLEND_MODE, M2_MATERIAL_PASS } from './const.js';
import { M2_MATERIAL_PASS } from './const.js';

type ModelResources = {
name: string;
Expand Down Expand Up @@ -157,12 +157,17 @@ class ModelManager {
const textures = await Promise.all(
m2Textures.map((m2Texture) => this.#createTexture(m2Texture)),
);
const blendMode = M2_MATERIAL_BLEND_MODE[M2_MATERIAL_PASS.PASS_0][batch.material.blend];

const side =
batch.material.flags & M2_MATERIAL_FLAG.FLAG_TWO_SIDED ? THREE.DoubleSide : THREE.FrontSide;

return new ModelMaterial(vertexShader, fragmentShader, textures, blendMode, side);
return new ModelMaterial(
vertexShader,
fragmentShader,
textures,
batch.material.blend,
M2_MATERIAL_PASS.PASS_0,
side,
);
}

async #createTexture(m2Texture: M2Texture) {
Expand Down
59 changes: 52 additions & 7 deletions src/lib/model/ModelMaterial.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,41 @@
import * as THREE from 'three';
import { BLEND_MODE, BLEND_STATE } from '../blend.js';
import { M2_MATERIAL_BLEND } from '@wowserhq/format';
import { M2_MATERIAL_TO_THREE_BLEND_MODE, M2_MATERIAL_PASS } from './const.js';
import { THREE_BLEND_STATE } from '../blend.js';

const DEFAULT_BLEND: M2_MATERIAL_BLEND = M2_MATERIAL_BLEND.BLEND_OPAQUE;
const DEFAULT_PASS: M2_MATERIAL_PASS = M2_MATERIAL_PASS.PASS_0;
const DEFAULT_SIDE: THREE.Side = THREE.FrontSide;
const DEFAULT_ALPHA: number = 1.0;

const getThreeBlendState = (blendMode: M2_MATERIAL_BLEND, pass: M2_MATERIAL_PASS) =>
THREE_BLEND_STATE[M2_MATERIAL_TO_THREE_BLEND_MODE[pass][blendMode]];

class ModelMaterial extends THREE.RawShaderMaterial {
#blend: M2_MATERIAL_BLEND;
#pass: M2_MATERIAL_PASS;

#alphaRef: number;
#alpha: number;

constructor(
vertexShader: string,
fragmentShader: string,
textures: THREE.Texture[],
blendMode: BLEND_MODE = BLEND_MODE.BLEND_OPAQUE,
side: THREE.Side = THREE.FrontSide,
blend = DEFAULT_BLEND,
pass = DEFAULT_PASS,
side = DEFAULT_SIDE,
) {
super();

const alphaRef = blendMode === BLEND_MODE.BLEND_ALPHA_KEY ? 224 / 255 : 1 / 255;
this.#blend = blend;
this.#pass = pass;

this.alpha = DEFAULT_ALPHA;

this.uniforms = {
textures: { value: textures },
alphaRef: { value: alphaRef },
alphaRef: { value: this.#alphaRef },
fogColor: { value: new THREE.Color(0.25, 0.5, 0.8) },
fogParams: { value: new THREE.Vector3(0.0, 1066.0, 1.0) },
};
Expand All @@ -24,14 +44,39 @@ class ModelMaterial extends THREE.RawShaderMaterial {
this.vertexShader = vertexShader;
this.fragmentShader = fragmentShader;

const { blending, blendSrc, blendSrcAlpha, blendDst, blendDstAlpha } = BLEND_STATE[blendMode];
this.side = side;

const threeBlendState = getThreeBlendState(this.#blend, this.#pass);
const { blending, blendSrc, blendSrcAlpha, blendDst, blendDstAlpha } = threeBlendState;

this.blending = blending;
this.blendSrc = blendSrc;
this.blendSrcAlpha = blendSrcAlpha;
this.blendDst = blendDst;
this.blendDstAlpha = blendDstAlpha;
}

this.side = side;
get alphaRef() {
return this.#alphaRef;
}

get alpha() {
return this.#alpha;
}

set alpha(alpha: number) {
this.#alpha = alpha;

// Opaque - keep all pixels, regardless of alpha
// Alpha key - scale pixel test by alpha
// Other - keep all pixels that aren't fully transparent
if (this.#blend === M2_MATERIAL_BLEND.BLEND_OPAQUE) {
this.#alphaRef = 0.0;
} else if (this.#blend === M2_MATERIAL_BLEND.BLEND_ALPHA_KEY) {
this.#alphaRef = alpha * (224.0 / 255.0);
} else {
this.#alphaRef = 1.0 / 255.0;
}
}
}

Expand Down
34 changes: 17 additions & 17 deletions src/lib/model/const.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,30 @@
import { BLEND_MODE } from '../blend.js';
import { THREE_BLEND_MODE } from '../blend.js';

enum M2_MATERIAL_PASS {
PASS_0 = 0,
PASS_1,
PASS_COUNT,
}

const M2_MATERIAL_BLEND_MODE = {
const M2_MATERIAL_TO_THREE_BLEND_MODE = {
[M2_MATERIAL_PASS.PASS_0]: [
BLEND_MODE.BLEND_OPAQUE,
BLEND_MODE.BLEND_ALPHA_KEY,
BLEND_MODE.BLEND_ALPHA,
BLEND_MODE.BLEND_NO_ALPHA_ADD,
BLEND_MODE.BLEND_ADD,
BLEND_MODE.BLEND_MOD,
BLEND_MODE.BLEND_MOD2X,
THREE_BLEND_MODE.BLEND_OPAQUE,
THREE_BLEND_MODE.BLEND_ALPHA_KEY,
THREE_BLEND_MODE.BLEND_ALPHA,
THREE_BLEND_MODE.BLEND_NO_ALPHA_ADD,
THREE_BLEND_MODE.BLEND_ADD,
THREE_BLEND_MODE.BLEND_MOD,
THREE_BLEND_MODE.BLEND_MOD2X,
],
[M2_MATERIAL_PASS.PASS_1]: [
BLEND_MODE.BLEND_ALPHA,
BLEND_MODE.BLEND_ALPHA,
BLEND_MODE.BLEND_ALPHA,
BLEND_MODE.BLEND_NO_ALPHA_ADD,
BLEND_MODE.BLEND_ADD,
BLEND_MODE.BLEND_MOD,
BLEND_MODE.BLEND_MOD2X,
THREE_BLEND_MODE.BLEND_ALPHA,
THREE_BLEND_MODE.BLEND_ALPHA,
THREE_BLEND_MODE.BLEND_ALPHA,
THREE_BLEND_MODE.BLEND_NO_ALPHA_ADD,
THREE_BLEND_MODE.BLEND_ADD,
THREE_BLEND_MODE.BLEND_MOD,
THREE_BLEND_MODE.BLEND_MOD2X,
],
};

export { M2_MATERIAL_PASS, M2_MATERIAL_BLEND_MODE };
export { M2_MATERIAL_PASS, M2_MATERIAL_TO_THREE_BLEND_MODE };

0 comments on commit 8a9bdc6

Please sign in to comment.