Custom shader works for SkinnedMesh

Hey guys,
I’m really new to three.js but I’m a game developer (With Unity).
I want to add my character showcase into my website so I thought to use three.js for it.
I’ve written a shader to apply to my character model but it doesn’t look good in my animated character model so after some researching I figure out I should add skinning support to my shader and it happens by using those skinning ShaderChunk(s).

This is my shader:

<script id='vertexShader' type="x-shader/x-vertex">
    varying vec2 vUv;
    
	void main() 
	{ 
        vUv = uv;
		gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
	}
</script>
<script id='fragmentShader' type="x-shader/x-fragment">
	uniform sampler2D grayScaleTexture;
	uniform sampler2D maskTexture;
	uniform vec3 bottomRedChannelColor, topRedChannelColor,
				 bottomGreenChannelColor, topGreenChannelColor,
				 bottomBlueChannelColor, topBlueChannelColor;
	varying vec2 vUv;
	
	void main() 
	{
		vec4 c = texture2D(grayScaleTexture, vUv);
		vec4 m = texture2D(maskTexture, vUv);
		float grayscale = c.r;
		vec3 redChannelColor = mix(bottomRedChannelColor, topRedChannelColor, grayscale) * m.r;
		vec3 greenChannelColor = mix(bottomGreenChannelColor, topGreenChannelColor, grayscale) * m.g;
		vec3 blueChannelColor = mix(bottomBlueChannelColor, topBlueChannelColor, grayscale) * m.b;
		gl_FragColor = vec4(redChannelColor + greenChannelColor + blueChannelColor, 1.0);
	}  
</script>


var uniforms = {
    grayScaleTexture: {
        type: "t", value: textureLoader.load("textures/cube/Cube_Skin0.png", function (texture) {
            texture.encoding = THREE.sRGBEncoding;
            texture.flipY = false;
        })
    },
    maskTexture: {
        type: "t", value: textureLoader.load("textures/cube/Cube_Skin0_mask.png", function (texture) {
            texture.encoding = THREE.sRGBEncoding;
            texture.flipY = false;
        })
    },
    bottomRedChannelColor: { type: 'c', value: new THREE.Color("rgb(255, 0, 0)") },
    topRedChannelColor: { type: 'c', value: new THREE.Color("rgb(255, 128, 128)") },
    bottomGreenChannelColor: { type: 'c', value: new THREE.Color("rgb(0, 255, 0)") },
    topGreenChannelColor: { type: 'c', value: new THREE.Color("rgb(128, 255, 128)") },
    bottomBlueChannelColor: { type: 'c', value: new THREE.Color("rgb(0, 0, 255)") },
    topBlueChannelColor: { type: 'c', value: new THREE.Color("rgb(128, 128, 255)") }
}
var material = new THREE.ShaderMaterial({
    uniforms: uniforms,
    vertexShader: vertShader,
    fragmentShader: fragShader,
    skinning: true
});

As I understand I should add these ShaderChunks:
all of them in vertex shader.
#include <skinning_pars_vertex> above main function.
And these three in main function:
#include <skinbase_vertex>
#include <skinnormal_vertex>
#include <skinning_vertex>

But I don’t know how I should initialize skinning_pars_vertex uniforms and use which parameters of them in my shader.

I find it easier to take the shaders of some material from ShaderLib and than modify the parts I need to be different, by replacing the corresponding ‘#include [Chunk]’

That way you have all the default features of the choosen base material and I need only worry about my extra features - which is hard enough as it is.

Then could you tell me how I should modify for example MeshLambertMaterial to the shader which I want. (I just change fragment shader in above shader)

Have look at this one: https://codepen.io/fedorvaneldijk/pen/eaoKbJ

1 Like

One more example, with using of .onBeforeCompile(): FBX + Material.onBeforeCompile()
You just take a default shader as is and change only the desired parts, keeping all the other functionalities of it.

2 Likes

The posted link no longer works unfortunately.

Here is an updated version of @Fedor_van_Eldijk’s codepen: https://jsfiddle.net/ovjka67h/

1 Like