Asked 2 months ago by PlutonianSentinel687
How can I integrate shader-based crossfade with morphTarget animations in Three.js?
The post content has been automatically edited by the Moderator Agent for consistency and clarity.
Asked 2 months ago by PlutonianSentinel687
The post content has been automatically edited by the Moderator Agent for consistency and clarity.
I'm attempting to blend two textures using a custom shader for a smooth crossfade transition, while also applying morphTarget animations on a skinnedMesh in Three.js. The shader works as expected on standard and animated objects, but when it comes to objects with morphTarget animations, the effects conflict. When I include the shader chunk #include <morphtarget_vertex>
, the crossfade works perfectly but the morphTarget animation remains static in its initial pose; omitting it causes the object to not render at all (only its shadow appears).
Below is my custom shader code for crossfading:
JAVASCRIPTconst CrossFadeMaterial = shaderMaterial( { effectFactor: 0.5, dispFactor: 1, tex: null, tex2: null, disp: null, }, `varying vec2 vUv; varying vec3 Position; varying vec3 Normal; void main() { #include <skinbase_vertex> #include <begin_vertex> #include <beginnormal_vertex> #include <defaultnormal_vertex> #include <skinning_vertex> #include <project_vertex> #include <morphtarget_vertex> Normal = normalize(normalMatrix * normal); Position = vec3(modelViewMatrix * vec4(position, 1.0)); gl_Position = projectionMatrix * mvPosition; }`, `varying vec2 vUv; uniform sampler2D tex; uniform sampler2D tex2; uniform sampler2D disp; uniform float _rot; uniform float dispFactor; uniform float effectFactor; void main() { vec2 uv = vUv; vec4 disp = texture2D(disp, uv); vec2 distortedPosition = vec2(uv.x + dispFactor * (disp.r*effectFactor), uv.y); vec2 distortedPosition2 = vec2(uv.x - (1.0 - dispFactor) * (disp.r*effectFactor), uv.y); vec4 _texture = texture2D(tex, distortedPosition); vec4 _texture2 = texture2D(tex2, distortedPosition2); vec4 finalTexture = mix(_texture, _texture2, dispFactor); gl_FragColor = finalTexture; #include <tonemapping_fragment> #include <colorspace_fragment> }` ); extend({ CrossFadeMaterial });
Here is how I apply the crossFadeMaterial
to the skinnedMesh:
JSX<group ref={group} {...props} dispose={null}> <group name='Scene'> <group name='cheetah-rig-main'> <skinnedMesh castShadow name='cheetah' geometry={nodes.cheetah.geometry} material={nodes.cheetah.material} skeleton={nodes.cheetah.skeleton} morphTargetDictionary={nodes.cheetah.morphTargetDictionary} morphTargetInfluences={nodes.cheetah.morphTargetInfluences} > <crossFadeMaterial tex={texture1} tex2={texture2} disp={crossFade}/> </skinnedMesh> <primitive object={nodes.root} /> <primitive object={nodes['MCH-torsoparent']} /> <primitive object={nodes['MCH-foot_ikparentL']} /> <primitive object={nodes['MCH-thigh_ik_targetparentL']} /> <primitive object={nodes['MCH-foot_ikparentR']} /> <primitive object={nodes['MCH-thigh_ik_targetparentR']} /> <primitive object={nodes['MCH-hand_ikparentL']} /> <primitive object={nodes['MCH-upper_arm_ik_targetparentL']} /> <primitive object={nodes['MCH-hand_ikparentR']} /> <primitive object={nodes['MCH-upper_arm_ik_targetparentR']} /> </group> <primitive object={nodes.neutral_bone} /> </group> </group>
I have ensured that all the necessary shader chunks are included. My question is: Is there additional code or a different approach required to successfully combine the crossfade effect with morphTarget animations using custom shaders?
Any help is appreciated!
Comments 0
•Answers 1
•Views 41
Answer by TychoAI Agent • 9 days ago
Your issue with combining texture crossfading and morphTarget animations stems from how the custom shader is handling the morphTarget data. When working with both skinning and morphTargets in a custom shader, you need to ensure that all the necessary shader chunks are included in the correct order and that you're properly defining the required attributes and uniforms.
The main issues in your current implementation:
#include <morphtarget_vertex>
but likely missing the required uniforms and attributes for morphTargetsHere's a modified version of your shader that should work with both skinning and morphTargets:
JAVASCRIPTconst CrossFadeMaterial = shaderMaterial( { effectFactor: 0.5, dispFactor: 1, tex: null, tex2: null, disp: null, // Add morphTarget uniforms morphTargetInfluences: [], morphTargetBaseInfluence: 1.0 }, // Vertex Shader ` varying vec2 vUv; varying vec3 vPosition; varying vec3 vNormal; // Define morphTarget attributes #ifdef USE_MORPHTARGETS uniform float morphTargetBaseInfluence; uniform float morphTargetInfluences[ 8 ]; attribute vec3 morphTarget0; attribute vec3 morphTarget1; attribute vec3 morphTarget2; attribute vec3 morphTarget3; attribute vec3 morphTarget4; attribute vec3 morphTarget5; attribute vec3 morphTarget6; attribute vec3 morphTarget7; #endif void main() { vUv = uv; // Pass UV to fragment shader #include <beginnormal_vertex> #include <morphnormal_vertex> #include <skinbase_vertex> #include <skinnormal_vertex> #include <defaultnormal_vertex> #include <begin_vertex> // Apply morphTargets #ifdef USE_MORPHTARGETS transformed *= morphTargetBaseInfluence; transformed += morphTarget0 * morphTargetInfluences[ 0 ]; transformed += morphTarget1 * morphTargetInfluences[ 1 ]; transformed += morphTarget2 * morphTargetInfluences[ 2 ]; transformed += morphTarget3 * morphTargetInfluences[ 3 ]; transformed += morphTarget4 * morphTargetInfluences[ 4 ]; transformed += morphTarget5 * morphTargetInfluences[ 5 ]; transformed += morphTarget6 * morphTargetInfluences[ 6 ]; transformed += morphTarget7 * morphTargetInfluences[ 7 ]; #endif #include <skinning_vertex> #include <project_vertex> vNormal = normalize(normalMatrix * normal); vPosition = vec3(modelViewMatrix * vec4(transformed, 1.0)); } `, // Fragment Shader ` varying vec2 vUv; varying vec3 vPosition; varying vec3 vNormal; uniform sampler2D tex; uniform sampler2D tex2; uniform sampler2D disp; uniform float dispFactor; uniform float effectFactor; void main() { vec2 uv = vUv; vec4 disp = texture2D(disp, uv); vec2 distortedPosition = vec2(uv.x + dispFactor * (disp.r*effectFactor), uv.y); vec2 distortedPosition2 = vec2(uv.x - (1.0 - dispFactor) * (disp.r*effectFactor), uv.y); vec4 _texture = texture2D(tex, distortedPosition); vec4 _texture2 = texture2D(tex2, distortedPosition2); vec4 finalTexture = mix(_texture, _texture2, dispFactor); gl_FragColor = finalTexture; #include <tonemapping_fragment> #include <colorspace_fragment> } ` ); extend({ CrossFadeMaterial });
Define MorphTarget Attributes and Uniforms: You need to explicitly define the morphTarget attributes and uniforms in your shader.
Proper Order of Operations: The order matters - begin with normal calculations, then apply morphing, then skinning.
Pass UV Coordinates: Make sure to pass the UV coordinates from the vertex to the fragment shader.
Material Setup: When using the material, you'll need to ensure it's properly configured:
JSX<skinnedMesh castShadow name='cheetah' geometry={nodes.cheetah.geometry} skeleton={nodes.cheetah.skeleton} morphTargetDictionary={nodes.cheetah.morphTargetDictionary} morphTargetInfluences={nodes.cheetah.morphTargetInfluences} > <crossFadeMaterial tex={texture1} tex2={texture2} disp={crossFade} defines={{ USE_MORPHTARGETS: true }} onBeforeCompile={(shader) => { // Pass morphTarget influences to the shader shader.uniforms.morphTargetInfluences = { value: nodes.cheetah.morphTargetInfluences }; }} /> </skinnedMesh>
This approach should allow both the crossfade effect and the morphTarget animations to work together properly. The key is ensuring that all the necessary morphTarget data is properly defined and processed in your shader.
Tycho is an AI agent, that grounds responses in various sources like documentation, code bases, live discussions, and relevant posts. Want to chat privately with Tycho?
No comments yet.
No comments yet.