Does ShadowMaterial work with skinned mesh?

I am using three.js 131. I am loading a GLTF file using GLTFLoader.js.

When loading the scene, I iterate through the scene nodes and check to see whether a mesh’s material name contains the string “shadowmat”. If so I replace this with a new instance of THREE.ShadowMaterial. This naming convention scheme is part of our export and loading pipeline. This code looks like this:

if (node.isMesh) {
            if (node.material.name.includes("shadowmat")) {
                node.material = new THREE.ShadowMaterial();
                node.castShadow = false;
                node.receiveShadow = true;
            }

I find that this scheme works well, unless the mesh is skinned geometry. Then I get this runtime error in the browser when the mesh is rendered:

THREE.WebGLProgram: shader error:  0 35715 false gl.getProgramInfoLog Vertex shader is not compiled.
ERROR: 0:211: 'getBoneMatrix' : no matching overloaded function found
ERROR: 0:211: '=' : dimension mismatch
ERROR: 0:211: '=' : cannot convert from 'const mediump float' to 'highp 4X4 matrix of float'

The error refer to this shader chunk (included from skinbase_vertex.glsl.js)

210: #ifdef USE_SKINNING
211: 	mat4 boneMatX = getBoneMatrix( skinIndex.x );
212: 	mat4 boneMatY = getBoneMatrix( skinIndex.y );
213: 	mat4 boneMatZ = getBoneMatrix( skinIndex.z );
214: 	mat4 boneMatW = getBoneMatrix( skinIndex.w );
215: #endif

When I look at the full listing of the vertex shader in the Chrome browser console log, both USE_SKINNING and BONE_TEXTURE are defined. However, I don’t see a definition for getBoneMatrix. I believe this should have been included from skinning_pars_vertex.glsl.js.

I suppose this might be a bug in ShadowMaterial.js, in that somehow skinning_pars_vertex.glsl.js is not getting included, or maybe I am not understanding how to set up ShadowMaterial to work properly with skinned geometry.

Below is the vertex shader output from the console log.

1: #version 300 es
2: #define attribute in
3: #define varying out
4: #define texture2D texture
5: precision highp float;
6: precision highp int;
7: #define HIGH_PRECISION
8: #define SHADER_NAME ShadowMaterial
9: #define USE_SKINNING true
10: #define VERTEX_TEXTURES
11: #define GAMMA_FACTOR 2
12: #define MAX_BONES 1024
13: #define USE_SKINNING
14: #define BONE_TEXTURE
15: #define USE_SHADOWMAP
16: #define SHADOWMAP_TYPE_PCF_SOFT
17: uniform mat4 modelMatrix;
18: uniform mat4 modelViewMatrix;
19: uniform mat4 projectionMatrix;
20: uniform mat4 viewMatrix;
21: uniform mat3 normalMatrix;
22: uniform vec3 cameraPosition;
23: uniform bool isOrthographic;
24: #ifdef USE_INSTANCING
25: 	attribute mat4 instanceMatrix;
26: #endif
27: #ifdef USE_INSTANCING_COLOR
28: 	attribute vec3 instanceColor;
29: #endif
30: attribute vec3 position;
31: attribute vec3 normal;
32: attribute vec2 uv;
33: #ifdef USE_TANGENT
34: 	attribute vec4 tangent;
35: #endif
36: #if defined( USE_COLOR_ALPHA )
37: 	attribute vec4 color;
38: #elif defined( USE_COLOR )
39: 	attribute vec3 color;
40: #endif
41: #ifdef USE_MORPHTARGETS
42: 	attribute vec3 morphTarget0;
43: 	attribute vec3 morphTarget1;
44: 	attribute vec3 morphTarget2;
45: 	attribute vec3 morphTarget3;
46: 	#ifdef USE_MORPHNORMALS
47: 		attribute vec3 morphNormal0;
48: 		attribute vec3 morphNormal1;
49: 		attribute vec3 morphNormal2;
50: 		attribute vec3 morphNormal3;
51: 	#else
52: 		attribute vec3 morphTarget4;
53: 		attribute vec3 morphTarget5;
54: 		attribute vec3 morphTarget6;
55: 		attribute vec3 morphTarget7;
56: 	#endif
57: #endif
58: #ifdef USE_SKINNING
59: 	attribute vec4 skinIndex;
60: 	attribute vec4 skinWeight;
61: #endif
62: 
63: #define PI 3.141592653589793
64: #define PI2 6.283185307179586
65: #define PI_HALF 1.5707963267948966
66: #define RECIPROCAL_PI 0.3183098861837907
67: #define RECIPROCAL_PI2 0.15915494309189535
68: #define EPSILON 1e-6
69: #ifndef saturate
70: #define saturate(a) clamp( a, 0.0, 1.0 )
71: #endif
72: #define whiteComplement(a) ( 1.0 - saturate( a ) )
73: float pow2( const in float x ) { return x*x; }
74: float pow3( const in float x ) { return x*x*x; }
75: float pow4( const in float x ) { float x2 = x*x; return x2*x2; }
76: float average( const in vec3 color ) { return dot( color, vec3( 0.3333 ) ); }
77: highp float rand( const in vec2 uv ) {
78: 	const highp float a = 12.9898, b = 78.233, c = 43758.5453;
79: 	highp float dt = dot( uv.xy, vec2( a,b ) ), sn = mod( dt, PI );
80: 	return fract(sin(sn) * c);
81: }
82: #ifdef HIGH_PRECISION
83: 	float precisionSafeLength( vec3 v ) { return length( v ); }
84: #else
85: 	float max3( vec3 v ) { return max( max( v.x, v.y ), v.z ); }
86: 	float precisionSafeLength( vec3 v ) {
87: 		float maxComponent = max3( abs( v ) );
88: 		return length( v / maxComponent ) * maxComponent;
89: 	}
90: #endif
91: struct IncidentLight {
92: 	vec3 color;
93: 	vec3 direction;
94: 	bool visible;
95: };
96: struct ReflectedLight {
97: 	vec3 directDiffuse;
98: 	vec3 directSpecular;
99: 	vec3 indirectDiffuse;
100: 	vec3 indirectSpecular;
101: };
102: struct GeometricContext {
103: 	vec3 position;
104: 	vec3 normal;
105: 	vec3 viewDir;
106: #ifdef CLEARCOAT
107: 	vec3 clearcoatNormal;
108: #endif
109: };
110: vec3 transformDirection( in vec3 dir, in mat4 matrix ) {
111: 	return normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );
112: }
113: vec3 inverseTransformDirection( in vec3 dir, in mat4 matrix ) {
114: 	return normalize( ( vec4( dir, 0.0 ) * matrix ).xyz );
115: }
116: vec3 projectOnPlane(in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {
117: 	float distance = dot( planeNormal, point - pointOnPlane );
118: 	return - distance * planeNormal + point;
119: }
120: float sideOfPlane( in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {
121: 	return sign( dot( point - pointOnPlane, planeNormal ) );
122: }
123: vec3 linePlaneIntersect( in vec3 pointOnLine, in vec3 lineDirection, in vec3 pointOnPlane, in vec3 planeNormal ) {
124: 	return lineDirection * ( dot( planeNormal, pointOnPlane - pointOnLine ) / dot( planeNormal, lineDirection ) ) + pointOnLine;
125: }
126: mat3 transposeMat3( const in mat3 m ) {
127: 	mat3 tmp;
128: 	tmp[ 0 ] = vec3( m[ 0 ].x, m[ 1 ].x, m[ 2 ].x );
129: 	tmp[ 1 ] = vec3( m[ 0 ].y, m[ 1 ].y, m[ 2 ].y );
130: 	tmp[ 2 ] = vec3( m[ 0 ].z, m[ 1 ].z, m[ 2 ].z );
131: 	return tmp;
132: }
133: float linearToRelativeLuminance( const in vec3 color ) {
134: 	vec3 weights = vec3( 0.2126, 0.7152, 0.0722 );
135: 	return dot( weights, color.rgb );
136: }
137: bool isPerspectiveMatrix( mat4 m ) {
138: 	return m[ 2 ][ 3 ] == - 1.0;
139: }
140: vec2 equirectUv( in vec3 dir ) {
141: 	float u = atan( dir.z, dir.x ) * RECIPROCAL_PI2 + 0.5;
142: 	float v = asin( clamp( dir.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5;
143: 	return vec2( u, v );
144: }
145: #ifdef USE_FOG
146: 	varying float fogDepth;
147: #endif
148: #ifdef USE_SHADOWMAP
149: 	#if 1 > 0
150: 		uniform mat4 directionalShadowMatrix[ 1 ];
151: 		varying vec4 vDirectionalShadowCoord[ 1 ];
152: 		struct DirectionalLightShadow {
153: 			float shadowBias;
154: 			float shadowNormalBias;
155: 			float shadowRadius;
156: 			vec2 shadowMapSize;
157: 		};
158: 		uniform DirectionalLightShadow directionalLightShadows[ 1 ];
159: 	#endif
160: 	#if 0 > 0
161: 		uniform mat4 spotShadowMatrix[ 0 ];
162: 		varying vec4 vSpotShadowCoord[ 0 ];
163: 		struct SpotLightShadow {
164: 			float shadowBias;
165: 			float shadowNormalBias;
166: 			float shadowRadius;
167: 			vec2 shadowMapSize;
168: 		};
169: 		uniform SpotLightShadow spotLightShadows[ 0 ];
170: 	#endif
171: 	#if 0 > 0
172: 		uniform mat4 pointShadowMatrix[ 0 ];
173: 		varying vec4 vPointShadowCoord[ 0 ];
174: 		struct PointLightShadow {
175: 			float shadowBias;
176: 			float shadowNormalBias;
177: 			float shadowRadius;
178: 			vec2 shadowMapSize;
179: 			float shadowCameraNear;
180: 			float shadowCameraFar;
181: 		};
182: 		uniform PointLightShadow pointLightShadows[ 0 ];
183: 	#endif
184: #endif
185: void main() {
186: vec3 transformed = vec3( position );
187: vec4 mvPosition = vec4( transformed, 1.0 );
188: #ifdef USE_INSTANCING
189: 	mvPosition = instanceMatrix * mvPosition;
190: #endif
191: mvPosition = modelViewMatrix * mvPosition;
192: gl_Position = projectionMatrix * mvPosition;
193: #if defined( USE_ENVMAP ) || defined( DISTANCE ) || defined ( USE_SHADOWMAP ) || defined ( USE_TRANSMISSION )
194: 	vec4 worldPosition = vec4( transformed, 1.0 );
195: 	#ifdef USE_INSTANCING
196: 		worldPosition = instanceMatrix * worldPosition;
197: 	#endif
198: 	worldPosition = modelMatrix * worldPosition;
199: #endif
200: vec3 objectNormal = vec3( normal );
201: #ifdef USE_TANGENT
202: 	vec3 objectTangent = vec3( tangent.xyz );
203: #endif
204: #ifdef USE_MORPHNORMALS
205: 	objectNormal *= morphTargetBaseInfluence;
206: 	objectNormal += morphNormal0 * morphTargetInfluences[ 0 ];
207: 	objectNormal += morphNormal1 * morphTargetInfluences[ 1 ];
208: 	objectNormal += morphNormal2 * morphTargetInfluences[ 2 ];
209: 	objectNormal += morphNormal3 * morphTargetInfluences[ 3 ];
210: #endif
211: #ifdef USE_SKINNING
212: 	mat4 boneMatX = getBoneMatrix( skinIndex.x );
213: 	mat4 boneMatY = getBoneMatrix( skinIndex.y );
214: 	mat4 boneMatZ = getBoneMatrix( skinIndex.z );
215: 	mat4 boneMatW = getBoneMatrix( skinIndex.w );
216: #endif
217: #ifdef USE_SKINNING
218: 	mat4 skinMatrix = mat4( 0.0 );
219: 	skinMatrix += skinWeight.x * boneMatX;
220: 	skinMatrix += skinWeight.y * boneMatY;
221: 	skinMatrix += skinWeight.z * boneMatZ;
222: 	skinMatrix += skinWeight.w * boneMatW;
223: 	skinMatrix = bindMatrixInverse * skinMatrix * bindMatrix;
224: 	objectNormal = vec4( skinMatrix * vec4( objectNormal, 0.0 ) ).xyz;
225: 	#ifdef USE_TANGENT
226: 		objectTangent = vec4( skinMatrix * vec4( objectTangent, 0.0 ) ).xyz;
227: 	#endif
228: #endif
229: vec3 transformedNormal = objectNormal;
230: #ifdef USE_INSTANCING
231: 	mat3 m = mat3( instanceMatrix );
232: 	transformedNormal /= vec3( dot( m[ 0 ], m[ 0 ] ), dot( m[ 1 ], m[ 1 ] ), dot( m[ 2 ], m[ 2 ] ) );
233: 	transformedNormal = m * transformedNormal;
234: #endif
235: transformedNormal = normalMatrix * transformedNormal;
236: #ifdef FLIP_SIDED
237: 	transformedNormal = - transformedNormal;
238: #endif
239: #ifdef USE_TANGENT
240: 	vec3 transformedTangent = ( modelViewMatrix * vec4( objectTangent, 0.0 ) ).xyz;
241: 	#ifdef FLIP_SIDED
242: 		transformedTangent = - transformedTangent;
243: 	#endif
244: #endif
245: #ifdef USE_SHADOWMAP
246: 	#if 1 > 0 || 0 > 0 || 0 > 0
247: 		vec3 shadowWorldNormal = inverseTransformDirection( transformedNormal, viewMatrix );
248: 		vec4 shadowWorldPosition;
249: 	#endif
250: 	#if 1 > 0
251: 	
252: 		shadowWorldPosition = worldPosition + vec4( shadowWorldNormal * directionalLightShadows[ 0 ].shadowNormalBias, 0 );
253: 		vDirectionalShadowCoord[ 0 ] = directionalShadowMatrix[ 0 ] * shadowWorldPosition;
254: 	
255: 	#endif
256: 	#if 0 > 0
257: 	
258: 	#endif
259: 	#if 0 > 0
260: 	
261: 	#endif
262: #endif
263: #ifdef USE_FOG
264: 	fogDepth = - mvPosition.z;
265: #endif
266: }

That looks like a bug. Let me file a PR.

This will be fixed with the next release r133.

1 Like