Skip to content

Commit

Permalink
Merge pull request #1492 from pixiv/examples-outline
Browse files Browse the repository at this point in the history
fix: Fix screenCoordinates outline rendering in WebGL
  • Loading branch information
0b5vr authored Sep 24, 2024
2 parents c30792c + 1426a61 commit a1df947
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 16 deletions.
61 changes: 60 additions & 1 deletion packages/three-vrm-materials-mtoon/examples/feature-test.html
Original file line number Diff line number Diff line change
Expand Up @@ -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 );
Expand Down Expand Up @@ -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 );

}

}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 );
Expand Down Expand Up @@ -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 );

}

}

Expand Down
1 change: 0 additions & 1 deletion packages/three-vrm-materials-mtoon/src/MToonMaterial.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
Expand Down
21 changes: 8 additions & 13 deletions packages/three-vrm-materials-mtoon/src/shaders/mtoon.vert
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down

0 comments on commit a1df947

Please sign in to comment.