Skip to content

Commit

Permalink
fix!: Migrate TSL functions from three/webgpu to three/tsl
Browse files Browse the repository at this point in the history
mrdoob/three.js#29644 moves TSL functions into `three/tsl`

The users have to modify the import map or bundler config because of this change
See: #1548 (comment)
  • Loading branch information
0b5vr committed Dec 5, 2024
1 parent 63e146e commit cd5d067
Show file tree
Hide file tree
Showing 10 changed files with 107 additions and 88 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"imports": {
"three": "https://cdn.jsdelivr.net/npm/three@0.171.0/build/three.webgpu.js",
"three/webgpu": "https://cdn.jsdelivr.net/npm/three@0.171.0/build/three.webgpu.js",
"three/tsl": "https://cdn.jsdelivr.net/npm/three@0.171.0/build/three.tsl.js",
"three/addons/": "https://cdn.jsdelivr.net/npm/three@0.171.0/examples/jsm/",
"@pixiv/three-vrm-materials-mtoon": "../lib/three-vrm-materials-mtoon.module.js",
"@pixiv/three-vrm-materials-mtoon/nodes": "../lib/nodes/index.module.js"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"imports": {
"three": "https://cdn.jsdelivr.net/npm/three@0.171.0/build/three.webgpu.js",
"three/webgpu": "https://cdn.jsdelivr.net/npm/three@0.171.0/build/three.webgpu.js",
"three/tsl": "https://cdn.jsdelivr.net/npm/three@0.171.0/build/three.tsl.js",
"three/addons/": "https://cdn.jsdelivr.net/npm/three@0.171.0/examples/jsm/",
"@pixiv/three-vrm-materials-mtoon": "../lib/three-vrm-materials-mtoon.module.js",
"@pixiv/three-vrm-materials-mtoon/nodes": "../lib/nodes/index.module.js"
Expand Down
23 changes: 12 additions & 11 deletions packages/three-vrm-materials-mtoon/src/nodes/MToonAnimatedUVNode.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as THREE from 'three/webgpu';
import { cos, mat2, sin, uv, vec2, vec4 } from 'three/tsl';
import {
refUVAnimationMaskTexture,
refUVAnimationRotationPhase,
Expand All @@ -19,28 +20,28 @@ export class MToonAnimatedUVNode extends THREE.TempNode {
let uvAnimationMask: THREE.NodeRepresentation = 1.0;

if (this.hasMaskTexture) {
uvAnimationMask = THREE.vec4(refUVAnimationMaskTexture).context({ getUV: () => THREE.uv() }).r;
uvAnimationMask = vec4(refUVAnimationMaskTexture).context({ getUV: () => uv() }).r;
}

let uv: THREE.ShaderNodeObject<THREE.Swizzable> = THREE.uv();
let animatedUv: THREE.ShaderNodeObject<THREE.Swizzable> = uv();

// rotate
const phase = refUVAnimationRotationPhase.mul(uvAnimationMask);

// WORKAROUND: THREE.rotateUV causes an issue with the mask texture
// We are going to spin using a 100% organic handmade rotation matrix
// uv = THREE.rotateUV(uv, phase, THREE.vec2(0.5, 0.5));
// animatedUv = THREE.rotateUV(animatedUv, phase, THREE.vec2(0.5, 0.5));

const c = THREE.cos(phase);
const s = THREE.sin(phase);
uv = uv.sub(THREE.vec2(0.5, 0.5));
uv = uv.mul(THREE.mat2(c, s, s.negate(), c));
uv = uv.add(THREE.vec2(0.5, 0.5));
const c = cos(phase);
const s = sin(phase);
animatedUv = animatedUv.sub(vec2(0.5, 0.5));
animatedUv = animatedUv.mul(mat2(c, s, s.negate(), c));
animatedUv = animatedUv.add(vec2(0.5, 0.5));

// scroll
const scroll = THREE.vec2(refUVAnimationScrollXOffset, refUVAnimationScrollYOffset).mul(uvAnimationMask);
uv = uv.add(scroll);
const scroll = vec2(refUVAnimationScrollXOffset, refUVAnimationScrollYOffset).mul(uvAnimationMask);
animatedUv = animatedUv.add(scroll);

return uv.toVar('AnimatedUV');
return animatedUv.toVar('AnimatedUV');
}
}
19 changes: 8 additions & 11 deletions packages/three-vrm-materials-mtoon/src/nodes/MToonLightingModel.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as THREE from 'three/webgpu';
import { BRDF_Lambert, diffuseColor, float, mix, transformedNormalView, vec3 } from 'three/tsl';
import {
matcap,
parametricRim,
Expand Down Expand Up @@ -34,7 +35,7 @@ const linearstep = FnCompat(
const getShading = FnCompat(({ dotNL }: { dotNL: THREE.ShaderNodeObject<THREE.Node> }) => {
const shadow = 1.0; // TODO

const feather = THREE.float(1.0).sub(shadingToony);
const feather = float(1.0).sub(shadingToony);

let shading: THREE.ShaderNodeObject<THREE.Node> = dotNL.add(shadingShift);
shading = linearstep({
Expand All @@ -57,8 +58,8 @@ const getDiffuse = FnCompat(
shading: THREE.ShaderNodeObject<THREE.Node>;
lightColor: THREE.ShaderNodeObject<THREE.Node>;
}) => {
const diffuseColor = THREE.mix(shadeColor, THREE.diffuseColor, shading);
const col = lightColor.mul(THREE.BRDF_Lambert({ diffuseColor }));
const feathered = mix(shadeColor, diffuseColor, shading);
const col = lightColor.mul(BRDF_Lambert({ diffuseColor: feathered }));

return col;
},
Expand All @@ -70,7 +71,7 @@ export class MToonLightingModel extends THREE.LightingModel {
}

direct({ lightDirection, lightColor, reflectedLight }: THREE.LightingModelDirectInput) {
const dotNL = THREE.transformedNormalView.dot(lightDirection).clamp(-1.0, 1.0);
const dotNL = transformedNormalView.dot(lightDirection).clamp(-1.0, 1.0);

// toon diffuse
const shading = getShading({
Expand All @@ -95,7 +96,7 @@ export class MToonLightingModel extends THREE.LightingModel {
parametricRim
.add(matcap)
.mul(rimMultiply)
.mul(THREE.mix(THREE.vec3(0.0), THREE.BRDF_Lambert({ diffuseColor: lightColor }), rimLightingMix)),
.mul(mix(vec3(0.0), BRDF_Lambert({ diffuseColor: lightColor }), rimLightingMix)),
),
);
}
Expand All @@ -109,11 +110,7 @@ export class MToonLightingModel extends THREE.LightingModel {
// indirect irradiance
(reflectedLight.indirectDiffuse as THREE.ShaderNodeObject<THREE.Node>).assign(
(reflectedLight.indirectDiffuse as THREE.ShaderNodeObject<THREE.Node>).add(
(irradiance as THREE.ShaderNodeObject<THREE.Node>).mul(
THREE.BRDF_Lambert({
diffuseColor: THREE.diffuseColor,
}),
),
(irradiance as THREE.ShaderNodeObject<THREE.Node>).mul(BRDF_Lambert({ diffuseColor })),
),
);
}
Expand All @@ -125,7 +122,7 @@ export class MToonLightingModel extends THREE.LightingModel {
parametricRim
.add(matcap)
.mul(rimMultiply)
.mul(THREE.mix(THREE.vec3(1.0), THREE.vec3(0.0), rimLightingMix)),
.mul(mix(vec3(1.0), vec3(0.0), rimLightingMix)),
),
);
}
Expand Down
61 changes: 38 additions & 23 deletions packages/three-vrm-materials-mtoon/src/nodes/MToonNodeMaterial.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,19 @@
import * as THREE from 'three/webgpu';
import {
cameraProjectionMatrix,
float,
length,
matcapUV,
materialNormal,
mix,
modelNormalMatrix,
normalLocal,
normalMap,
positionLocal,
positionView,
vec3,
vec4,
} from 'three/tsl';

import type { MToonMaterial } from '../MToonMaterial';
import { MToonLightingModel } from './MToonLightingModel';
Expand Down Expand Up @@ -258,11 +273,11 @@ export class MToonNodeMaterial extends THREE.NodeMaterial {
const tempNormalNode = this.normalNode;

if (this.normalNode == null) {
this.normalNode = THREE.materialNormal;
this.normalNode = materialNormal;

if (this.normalMap && this.normalMap.isTexture === true) {
const map = refNormalMap.context({ getUV: () => this._animatedUVNode });
this.normalNode = THREE.normalMap(map, refNormalScale);
this.normalNode = normalMap(map, refNormalScale);
}

if (this.isOutline) {
Expand Down Expand Up @@ -329,8 +344,8 @@ export class MToonNodeMaterial extends THREE.NodeMaterial {
): THREE.ShaderNodeObject<THREE.Node> {
// mix or set outline color
if (this.isOutline && this.outlineWidthMode !== MToonMaterialOutlineWidthMode.None) {
outputNode = THREE.vec4(
THREE.mix(refOutlineColorFactor, outputNode.xyz.mul(refOutlineColorFactor), refOutlineLightingMixFactor),
outputNode = vec4(
mix(refOutlineColorFactor, outputNode.xyz.mul(refOutlineColorFactor), refOutlineLightingMixFactor),
outputNode.w,
);
}
Expand All @@ -345,9 +360,9 @@ export class MToonNodeMaterial extends THREE.NodeMaterial {
const tempPositionNode = this.positionNode;

if (this.isOutline && this.outlineWidthMode !== MToonMaterialOutlineWidthMode.None) {
this.positionNode ??= THREE.positionLocal;
this.positionNode ??= positionLocal;

const normalLocal = THREE.normalLocal.normalize();
const normalLocalNormalized = normalLocal.normalize();

let width: THREE.ShaderNodeObject<THREE.Node> = refOutlineWidthFactor;

Expand All @@ -356,22 +371,22 @@ export class MToonNodeMaterial extends THREE.NodeMaterial {
width = width.mul(map);
}

const worldNormalLength = THREE.length(THREE.modelNormalMatrix.mul(normalLocal));
const outlineOffset = width.mul(worldNormalLength).mul(normalLocal);
const worldNormalLength = length(modelNormalMatrix.mul(normalLocalNormalized));
const outlineOffset = width.mul(worldNormalLength).mul(normalLocalNormalized);

if (this.outlineWidthMode === MToonMaterialOutlineWidthMode.WorldCoordinates) {
// See about the type assertion: https://github.com/three-types/three-ts-types/pull/1123
this.positionNode = (this.positionNode as THREE.ShaderNodeObject<THREE.Node>).add(outlineOffset);
} else if (this.outlineWidthMode === MToonMaterialOutlineWidthMode.ScreenCoordinates) {
const clipScale = THREE.cameraProjectionMatrix.element(1).element(1);
const clipScale = cameraProjectionMatrix.element(1).element(1);

// See about the type assertion: https://github.com/three-types/three-ts-types/pull/1123
this.positionNode = (this.positionNode as THREE.ShaderNodeObject<THREE.Node>).add(
outlineOffset.div(clipScale).mul(THREE.positionView.z.negate()),
outlineOffset.div(clipScale).mul(positionView.z.negate()),
);
}

this.positionNode ??= THREE.positionLocal;
this.positionNode ??= positionLocal;
}

// the ordinary position setup
Expand Down Expand Up @@ -442,7 +457,7 @@ export class MToonNodeMaterial extends THREE.NodeMaterial {

private _setupShadeColorNode(): THREE.Swizzable {
if (this.shadeColorNode != null) {
return THREE.vec3(this.shadeColorNode);
return vec3(this.shadeColorNode);
}

let shadeColorNode: THREE.ShaderNodeObject<THREE.Node> = refShadeColorFactor;
Expand All @@ -457,7 +472,7 @@ export class MToonNodeMaterial extends THREE.NodeMaterial {

private _setupShadingShiftNode(): THREE.Node {
if (this.shadingShiftNode != null) {
return THREE.float(this.shadingShiftNode);
return float(this.shadingShiftNode);
}

let shadingShiftNode: THREE.ShaderNodeObject<THREE.Node> = refShadingShiftFactor;
Expand All @@ -472,56 +487,56 @@ export class MToonNodeMaterial extends THREE.NodeMaterial {

private _setupShadingToonyNode(): THREE.Node {
if (this.shadingToonyNode != null) {
return THREE.float(this.shadingToonyNode);
return float(this.shadingToonyNode);
}

return refShadingToonyFactor;
}

private _setupRimLightingMixNode(): THREE.Node {
if (this.rimLightingMixNode != null) {
return THREE.float(this.rimLightingMixNode);
return float(this.rimLightingMixNode);
}

return refRimLightingMixFactor;
}

private _setupRimMultiplyNode(): THREE.Swizzable {
if (this.rimMultiplyNode != null) {
return THREE.vec3(this.rimMultiplyNode);
return vec3(this.rimMultiplyNode);
}

if (this.rimMultiplyTexture && this.rimMultiplyTexture.isTexture === true) {
const map = refRimMultiplyTexture.context({ getUV: () => this._animatedUVNode });
return map;
}

return THREE.vec3(1.0);
return vec3(1.0);
}

private _setupMatcapNode(): THREE.Swizzable {
if (this.matcapNode != null) {
return THREE.vec3(this.matcapNode);
return vec3(this.matcapNode);
}

if (this.matcapTexture && this.matcapTexture.isTexture === true) {
const map = refMatcapTexture.context({ getUV: () => THREE.matcapUV.mul(1.0, -1.0).add(0.0, 1.0) });
const map = refMatcapTexture.context({ getUV: () => matcapUV.mul(1.0, -1.0).add(0.0, 1.0) });
return map.mul(refMatcapFactor);
}

return THREE.vec3(0.0);
return vec3(0.0);
}

private _setupParametricRimNode(): THREE.Swizzable {
const parametricRimColor =
this.parametricRimColorNode != null ? THREE.vec3(this.parametricRimColorNode) : refParametricRimColorFactor;
this.parametricRimColorNode != null ? vec3(this.parametricRimColorNode) : refParametricRimColorFactor;

const parametricRimLift =
this.parametricRimLiftNode != null ? THREE.float(this.parametricRimLiftNode) : refParametricRimLiftFactor;
this.parametricRimLiftNode != null ? float(this.parametricRimLiftNode) : refParametricRimLiftFactor;

const parametricRimFresnelPower =
this.parametricRimFresnelPowerNode != null
? THREE.float(this.parametricRimFresnelPowerNode)
? float(this.parametricRimFresnelPowerNode)
: refParametricRimFresnelPowerFactor;

return mtoonParametricRim({
Expand Down
15 changes: 8 additions & 7 deletions packages/three-vrm-materials-mtoon/src/nodes/immutableNodes.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import * as THREE from 'three/webgpu';
import { nodeImmutable } from 'three/tsl';

export const shadeColor = THREE.nodeImmutable(THREE.PropertyNode, 'vec3').toVar('ShadeColor');
export const shadingShift = THREE.nodeImmutable(THREE.PropertyNode, 'float').toVar('ShadingShift');
export const shadingToony = THREE.nodeImmutable(THREE.PropertyNode, 'float').toVar('ShadingToony');
export const rimLightingMix = THREE.nodeImmutable(THREE.PropertyNode, 'float').toVar('RimLightingMix');
export const rimMultiply = THREE.nodeImmutable(THREE.PropertyNode, 'vec3').toVar('RimMultiply');
export const matcap = THREE.nodeImmutable(THREE.PropertyNode, 'vec3').toVar('matcap');
export const parametricRim = THREE.nodeImmutable(THREE.PropertyNode, 'vec3').toVar('ParametricRim');
export const shadeColor = nodeImmutable(THREE.PropertyNode, 'vec3').toVar('ShadeColor');
export const shadingShift = nodeImmutable(THREE.PropertyNode, 'float').toVar('ShadingShift');
export const shadingToony = nodeImmutable(THREE.PropertyNode, 'float').toVar('ShadingToony');
export const rimLightingMix = nodeImmutable(THREE.PropertyNode, 'float').toVar('RimLightingMix');
export const rimMultiply = nodeImmutable(THREE.PropertyNode, 'vec3').toVar('RimMultiply');
export const matcap = nodeImmutable(THREE.PropertyNode, 'vec3').toVar('matcap');
export const parametricRim = nodeImmutable(THREE.PropertyNode, 'vec3').toVar('ParametricRim');
56 changes: 28 additions & 28 deletions packages/three-vrm-materials-mtoon/src/nodes/materialReferences.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,31 @@
import * as THREE from 'three/webgpu';
import { materialReference } from 'three/tsl';

export const refColor = THREE.materialReference('color', 'color');
export const refMap = THREE.materialReference('map', 'texture');
export const refNormalMap = THREE.materialReference('normalMap', 'texture');
export const refNormalScale = THREE.materialReference('normalScale', 'vec2');
export const refEmissive = THREE.materialReference('emissive', 'color');
export const refEmissiveIntensity = THREE.materialReference('emissiveIntensity', 'float');
export const refEmissiveMap = THREE.materialReference('emissiveMap', 'texture');
export const refColor = materialReference('color', 'color');
export const refMap = materialReference('map', 'texture');
export const refNormalMap = materialReference('normalMap', 'texture');
export const refNormalScale = materialReference('normalScale', 'vec2');
export const refEmissive = materialReference('emissive', 'color');
export const refEmissiveIntensity = materialReference('emissiveIntensity', 'float');
export const refEmissiveMap = materialReference('emissiveMap', 'texture');

export const refShadeColorFactor = THREE.materialReference('shadeColorFactor', 'color');
export const refShadingShiftFactor = THREE.materialReference('shadingShiftFactor', 'float');
export const refShadeMultiplyTexture = THREE.materialReference('shadeMultiplyTexture', 'texture');
export const refShadeMultiplyTextureScale = THREE.materialReference('shadeMultiplyTextureScale', 'float');
export const refShadingToonyFactor = THREE.materialReference('shadingToonyFactor', 'float');
export const refRimLightingMixFactor = THREE.materialReference('rimLightingMixFactor', 'float');
export const refRimMultiplyTexture = THREE.materialReference('rimMultiplyTexture', 'texture');
export const refMatcapFactor = THREE.materialReference('matcapFactor', 'color');
export const refMatcapTexture = THREE.materialReference('matcapTexture', 'texture');
export const refParametricRimColorFactor = THREE.materialReference('parametricRimColorFactor', 'color');
export const refParametricRimLiftFactor = THREE.materialReference('parametricRimLiftFactor', 'float');
export const refParametricRimFresnelPowerFactor = THREE.materialReference('parametricRimFresnelPowerFactor', 'float');
export const refOutlineWidthMultiplyTexture = THREE.materialReference('outlineWidthMultiplyTexture', 'texture');
export const refOutlineWidthFactor = THREE.materialReference('outlineWidthFactor', 'float');
export const refOutlineColorFactor = THREE.materialReference('outlineColorFactor', 'color');
export const refOutlineLightingMixFactor = THREE.materialReference('outlineLightingMixFactor', 'float');
export const refUVAnimationMaskTexture = THREE.materialReference('uvAnimationMaskTexture', 'texture');
export const refShadeColorFactor = materialReference('shadeColorFactor', 'color');
export const refShadingShiftFactor = materialReference('shadingShiftFactor', 'float');
export const refShadeMultiplyTexture = materialReference('shadeMultiplyTexture', 'texture');
export const refShadeMultiplyTextureScale = materialReference('shadeMultiplyTextureScale', 'float');
export const refShadingToonyFactor = materialReference('shadingToonyFactor', 'float');
export const refRimLightingMixFactor = materialReference('rimLightingMixFactor', 'float');
export const refRimMultiplyTexture = materialReference('rimMultiplyTexture', 'texture');
export const refMatcapFactor = materialReference('matcapFactor', 'color');
export const refMatcapTexture = materialReference('matcapTexture', 'texture');
export const refParametricRimColorFactor = materialReference('parametricRimColorFactor', 'color');
export const refParametricRimLiftFactor = materialReference('parametricRimLiftFactor', 'float');
export const refParametricRimFresnelPowerFactor = materialReference('parametricRimFresnelPowerFactor', 'float');
export const refOutlineWidthMultiplyTexture = materialReference('outlineWidthMultiplyTexture', 'texture');
export const refOutlineWidthFactor = materialReference('outlineWidthFactor', 'float');
export const refOutlineColorFactor = materialReference('outlineColorFactor', 'color');
export const refOutlineLightingMixFactor = materialReference('outlineLightingMixFactor', 'float');
export const refUVAnimationMaskTexture = materialReference('uvAnimationMaskTexture', 'texture');

export const refUVAnimationScrollXOffset = THREE.materialReference('uvAnimationScrollXOffset', 'float');
export const refUVAnimationScrollYOffset = THREE.materialReference('uvAnimationScrollYOffset', 'float');
export const refUVAnimationRotationPhase = THREE.materialReference('uvAnimationRotationPhase', 'float');
export const refUVAnimationScrollXOffset = materialReference('uvAnimationScrollXOffset', 'float');
export const refUVAnimationScrollYOffset = materialReference('uvAnimationScrollYOffset', 'float');
export const refUVAnimationRotationPhase = materialReference('uvAnimationRotationPhase', 'float');
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as THREE from 'three/webgpu';
import { float, modelViewPosition, transformedNormalView } from 'three/tsl';
import { FnCompat } from './utils/FnCompat';

export const mtoonParametricRim = FnCompat(
Expand All @@ -11,10 +12,10 @@ export const mtoonParametricRim = FnCompat(
parametricRimFresnelPower: THREE.NodeRepresentation;
parametricRimColor: THREE.NodeRepresentation;
}) => {
const viewDir = THREE.modelViewPosition.normalize();
const dotNV = THREE.transformedNormalView.dot(viewDir.negate());
const viewDir = modelViewPosition.normalize();
const dotNV = transformedNormalView.dot(viewDir.negate());

const rim = THREE.float(1.0).sub(dotNV).add(parametricRimLift).clamp().pow(parametricRimFresnelPower);
const rim = float(1.0).sub(dotNV).add(parametricRimLift).clamp().pow(parametricRimFresnelPower);

return rim.mul(parametricRimColor);
},
Expand Down
Loading

0 comments on commit cd5d067

Please sign in to comment.