From ea1e9468337a950618039d21e8912dde790f27a4 Mon Sep 17 00:00:00 2001 From: 0b5vr <0b5vr@0b5vr.com> Date: Fri, 13 Sep 2024 19:24:16 +0900 Subject: [PATCH 1/3] examples: MToon, Add materials with outline to feature-test.html I suspect that we will have an issue that outline does not appear in r169 WebGPURenderer Also I spotted a bug in WebGL outline when the mode is screenCoordinates --- .../examples/feature-test.html | 61 ++++++++++++++++++- .../examples/webgpu-feature-test.html | 59 +++++++++++++++++- 2 files changed, 118 insertions(+), 2 deletions(-) diff --git a/packages/three-vrm-materials-mtoon/examples/feature-test.html b/packages/three-vrm-materials-mtoon/examples/feature-test.html index dd3b29f3..ba7d447a 100644 --- a/packages/three-vrm-materials-mtoon/examples/feature-test.html +++ b/packages/three-vrm-materials-mtoon/examples/feature-test.html @@ -270,11 +270,57 @@ }, + // outline world + { + map: textureUVGrid, + outlineWidthMode: 'worldCoordinates', + outlineWidthFactor: 0.05, + outlineColorFactor: 0x00ff00, + }, + + // outline world, masked, unlit + { + map: textureUVGrid, + outlineWidthMode: 'worldCoordinates', + outlineWidthFactor: 0.05, + outlineColorFactor: 0x00ff00, + outlineWidthMultiplyTexture: textureBinaryHalf, + outlineLightingMixFactor: 0.0, + }, + + // outline screen + { + map: textureUVGrid, + outlineWidthMode: 'screenCoordinates', + outlineWidthFactor: 0.05, + outlineColorFactor: 0xff0000, + }, + ].map( ( params, i ) => { const material = new MToonMaterial( params ); const mesh = new THREE.Mesh( geometrySphere, material ); + // if outline is enabled we need to duplicate the material and assign it to the mesh + if ( material.outlineWidthMode !== 'none' ) { + + // duplicate the material for outline use + const materialOutline = mesh.material.clone(); + materialOutline.isOutline = true; + materialOutline.side = THREE.BackSide; + + mesh.material = [ mesh.material, materialOutline ]; + + // make two geometry groups out of a same buffer + const geometry = mesh.geometry; // mesh.geometry is guaranteed to be a BufferGeometry in GLTFLoader + const primitiveVertices = geometry.index ? geometry.index.count : geometry.attributes.position.count / 3; + geometry.addGroup( 0, primitiveVertices, 0 ); + geometry.addGroup( 0, primitiveVertices, 1 ); + + } + + console.log( mesh.material ); + const x = ( i % 5 ) - 2.0; const y = Math.floor( i / 5 ) - 2.0; mesh.position.set( x, y, 0 ); @@ -309,7 +355,20 @@ for ( const mesh of meshes ) { - mesh.material.update( delta ); + // mesh.material can be either array or single material + if ( Array.isArray( mesh.material ) ) { + + for ( const material of mesh.material ) { + + material.update( delta ); + + } + + } else { + + mesh.material.update( delta ); + + } } diff --git a/packages/three-vrm-materials-mtoon/examples/webgpu-feature-test.html b/packages/three-vrm-materials-mtoon/examples/webgpu-feature-test.html index f8c54005..e884a8b9 100644 --- a/packages/three-vrm-materials-mtoon/examples/webgpu-feature-test.html +++ b/packages/three-vrm-materials-mtoon/examples/webgpu-feature-test.html @@ -273,11 +273,55 @@ }, + // outline world + { + map: textureUVGrid, + outlineWidthMode: 'worldCoordinates', + outlineWidthFactor: 0.05, + outlineColorFactor: 0x00ff00, + }, + + // outline world, masked, unlit + { + map: textureUVGrid, + outlineWidthMode: 'worldCoordinates', + outlineWidthFactor: 0.05, + outlineColorFactor: 0x00ff00, + outlineWidthMultiplyTexture: textureBinaryHalf, + outlineLightingMixFactor: 0.0, + }, + + // outline screen + { + map: textureUVGrid, + outlineWidthMode: 'screenCoordinates', + outlineWidthFactor: 0.05, + outlineColorFactor: 0xff0000, + }, + ].map( ( params, i ) => { const material = new MToonNodeMaterial( params ); const mesh = new THREE.Mesh( geometrySphere, material ); + // if outline is enabled we need to duplicate the material and assign it to the mesh + if ( params.outlineWidthMode !== 'none' ) { + + // duplicate the material for outline use + const materialOutline = mesh.material.clone(); + materialOutline.isOutline = true; + materialOutline.side = THREE.BackSide; + + mesh.material = [ mesh.material, materialOutline ]; + + // make two geometry groups out of a same buffer + const geometry = mesh.geometry; // mesh.geometry is guaranteed to be a BufferGeometry in GLTFLoader + const primitiveVertices = geometry.index ? geometry.index.count : geometry.attributes.position.count / 3; + geometry.addGroup( 0, primitiveVertices, 0 ); + geometry.addGroup( 0, primitiveVertices, 1 ); + + } + const x = ( i % 5 ) - 2.0; const y = Math.floor( i / 5 ) - 2.0; mesh.position.set( x, y, 0 ); @@ -312,7 +356,20 @@ for ( const mesh of meshes ) { - mesh.material.update( delta ); + // mesh.material can be either array or single material + if ( Array.isArray( mesh.material ) ) { + + for ( const material of mesh.material ) { + + material.update( delta ); + + } + + } else { + + mesh.material.update( delta ); + + } } From cd6c501ea829816e46f9b5cf00f26a7487eaef40 Mon Sep 17 00:00:00 2001 From: 0b5vr <0b5vr@0b5vr.com> Date: Fri, 13 Sep 2024 19:39:08 +0900 Subject: [PATCH 2/3] fix: Fix screenCoordinates outline rendering in WebGL Ref, the same logic in WebGPU: https://github.com/pixiv/three-vrm/blob/c30792c30865de5af7408fd8d0145cc7bc06c716/packages/three-vrm-materials-mtoon/src/nodes/MToonNodeMaterial.ts#L370 --- .../src/shaders/mtoon.vert | 21 +++++++------------ 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/packages/three-vrm-materials-mtoon/src/shaders/mtoon.vert b/packages/three-vrm-materials-mtoon/src/shaders/mtoon.vert index 72664cfa..f1815e97 100644 --- a/packages/three-vrm-materials-mtoon/src/shaders/mtoon.vert +++ b/packages/three-vrm-materials-mtoon/src/shaders/mtoon.vert @@ -92,27 +92,22 @@ void main() { vViewPosition = - mvPosition.xyz; - float outlineTex = 1.0; - #ifdef OUTLINE + float worldNormalLength = length( transformedNormal ); + vec3 outlineOffset = outlineWidthFactor * worldNormalLength * objectNormal; + #ifdef USE_OUTLINEWIDTHMULTIPLYTEXTURE vec2 outlineWidthMultiplyTextureUv = ( outlineWidthMultiplyTextureUvTransform * vec3( vUv, 1 ) ).xy; - outlineTex = texture2D( outlineWidthMultiplyTexture, outlineWidthMultiplyTextureUv ).g; - #endif - - #ifdef OUTLINE_WIDTH_WORLD - float worldNormalLength = length( transformedNormal ); - vec3 outlineOffset = outlineWidthFactor * outlineTex * worldNormalLength * objectNormal; - gl_Position = projectionMatrix * modelViewMatrix * vec4( outlineOffset + transformed, 1.0 ); + float outlineTex = texture2D( outlineWidthMultiplyTexture, outlineWidthMultiplyTextureUv ).g; + outlineOffset *= outlineTex; #endif #ifdef OUTLINE_WIDTH_SCREEN - vec3 clipNormal = ( projectionMatrix * modelViewMatrix * vec4( objectNormal, 0.0 ) ).xyz; - vec2 projectedNormal = normalize( clipNormal.xy ); - projectedNormal.x *= projectionMatrix[ 0 ].x / projectionMatrix[ 1 ].y; - gl_Position.xy += 2.0 * outlineWidthFactor * outlineTex * projectedNormal.xy; + outlineOffset *= vViewPosition.z / projectionMatrix[ 1 ].y; #endif + gl_Position = projectionMatrix * modelViewMatrix * vec4( outlineOffset + transformed, 1.0 ); + gl_Position.z += 1E-6 * gl_Position.w; // anti-artifact magic #endif From 1426a6107b5dfa604203537f0aa6346539ecc96d Mon Sep 17 00:00:00 2001 From: 0b5vr <0b5vr@0b5vr.com> Date: Tue, 24 Sep 2024 12:48:55 +0900 Subject: [PATCH 3/3] refactor: We no longer use OUTLINE_WIDTH_WORLD in MToonMaterial, delete the line See: https://github.com/pixiv/three-vrm/pull/1492#discussion_r1764468886 --- packages/three-vrm-materials-mtoon/src/MToonMaterial.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/three-vrm-materials-mtoon/src/MToonMaterial.ts b/packages/three-vrm-materials-mtoon/src/MToonMaterial.ts index 5ec1fb16..76774ac8 100644 --- a/packages/three-vrm-materials-mtoon/src/MToonMaterial.ts +++ b/packages/three-vrm-materials-mtoon/src/MToonMaterial.ts @@ -606,7 +606,6 @@ export class MToonMaterial extends THREE.ShaderMaterial { DEBUG_NORMAL: this._debugMode === 'normal', DEBUG_LITSHADERATE: this._debugMode === 'litShadeRate', DEBUG_UV: this._debugMode === 'uv', - OUTLINE_WIDTH_WORLD: this._isOutline && this._outlineWidthMode === MToonMaterialOutlineWidthMode.WorldCoordinates, OUTLINE_WIDTH_SCREEN: this._isOutline && this._outlineWidthMode === MToonMaterialOutlineWidthMode.ScreenCoordinates, };