Add shadows to custom shader material / instance mesh

Hi so I have some grass that uses shader materials and they are instance meshes … in my scene I have a light that cast shadows, so far so good but It doesn’t work for the grass so I wondering how i can apply shadows to it? to recieve shadows and cast them any idea’s?
code:


const vertexShader = `
varying vec2 vUv;
uniform float time;

${simpleNoise}

void main() {

  vUv = uv;
  float t = time * 2.;
  
  // VERTEX POSITION
  
  vec4 mvPosition = vec4( position, 1.0 );
  #ifdef USE_INSTANCING
    mvPosition = instanceMatrix * mvPosition;
  #endif
  
  // DISPLACEMENT
  
  float noise = smoothNoise(mvPosition.xz * 0.5 + vec2(0., t));
  noise = pow(noise * 0.5 + 0.5, 2.) * 2.;
  
  // here the displacement is made stronger on the blades tips.
  float dispPower = 1. - cos( uv.y * 3.1416 * 0.5 );
  
  float displacement = noise * ( 0.3 * dispPower );
  mvPosition.z -= displacement;
  
  //
  
  vec4 modelViewPosition = modelViewMatrix * mvPosition;
  gl_Position = projectionMatrix * modelViewPosition;

}
`;

const fragmentShader = `
varying vec2 vUv;

void main() {
  vec3 baseColor = vec3( 0.41, 1.0, 0.5 );
  float clarity = ( vUv.y * 0.875 ) + 0.125;
  gl_FragColor = vec4( baseColor * clarity, 1 );
}
`;

const uniforms = {
time: {
  value: 0
}
}

this.leavesMaterial = new THREE.ShaderMaterial({
vertexShader,
fragmentShader,
uniforms,
side: THREE.DoubleSide,
castShadow: true,
recieveShadow: true,
});



const instanceNumber = 50000;
const dummy = new THREE.Object3D();

const geometry = new THREE.PlaneGeometry( 0.1, 1, 1, 4 );
geometry.translate( 0, 0.5, 0 ); // move grass blade geometry lowest point at 0.

const instancedMesh = new THREE.InstancedMesh( geometry, this.leavesMaterial, instanceNumber );

this.scene_.add( instancedMesh );

// Position and scale the grass blade instances randomly.

for ( let i=0 ; i<instanceNumber ; i++ ) {

dummy.position.set(
  ( Math.random() - 0.3 ) * 300,
  0,
  ( Math.random() - 0.3 ) * 300
);

dummy.scale.setScalar( 1.0 + Math.random() * 2.6 );
dummy.scale.y = 1.0 + Math.random() * 5.5;
dummy.rotation.y = Math.random() * Math.PI;

dummy.updateMatrix();
instancedMesh.setMatrixAt( i, dummy.matrix );

}

thanks for any help

1 Like

tried this but didn’t work:

import { mergeUniforms } from 'three/src/renderers/shaders/UniformsUtils.js'
import { UniformsLib } from 'three/src/renderers/shaders/UniformsLib.js'
    uniforms: mergeUniforms([
      UniformsLib.lights,
        UniformsLib.fog,
    ]);
     
 
const vertexShader = `
#include <common>
#include <fog_pars_vertex>
#include <shadowmap_pars_vertex>

varying vec2 vUv;
uniform float time;

${simpleNoise}

void main() {
  #include <begin_vertex>
      #include <project_vertex>
      #include <worldpos_vertex>
      #include <shadowmap_vertex>
      #include <fog_vertex>
  vUv = uv;
  float t = time * 2.;
  
  // VERTEX POSITION
  
  vec4 mvPosition = vec4( position, 1.0 );
  #ifdef USE_INSTANCING
    mvPosition = instanceMatrix * mvPosition;
  #endif
  
  // DISPLACEMENT
  
  float noise = smoothNoise(mvPosition.xz * 0.5 + vec2(0., t));
  noise = pow(noise * 0.5 + 0.5, 2.) * 2.;
  
  // here the displacement is made stronger on the blades tips.
  float dispPower = 1. - cos( uv.y * 3.1416 * 0.5 );
  
  float displacement = noise * ( 0.3 * dispPower );
  mvPosition.z -= displacement;
  
  //
  
  vec4 modelViewPosition = modelViewMatrix * mvPosition;
  gl_Position = projectionMatrix * modelViewPosition;

}
`;

const fragmentShader = `
#include <common>
#include <packing>
#include <fog_pars_fragment>
#include <bsdfs>
#include <lights_pars_begin>
#include <shadowmap_pars_fragment>
#include <shadowmask_pars_fragment>
#include <dithering_pars_fragment>

varying vec2 vUv;

void main() {
  vec3 baseColor = vec3( 0.41, 1.0, 0.5 );
  float clarity = ( vUv.y * 0.875 ) + 0.125;
  

 
  vec3 shadowColor = vec3(0, 0, 0);
  float shadowPower = 0.5;

  gl_FragColor = vec4( mix(baseColor * clarity, shadowColor, (1.0 - getShadowMask() ) * shadowPower), 1.0);
   
  #include <fog_fragment>
      #include <dithering_fragment>
}
`;


const uniforms = {
  time: {
    value: 0
  }
  }

 
 
this.leavesMaterial = new THREE.ShaderMaterial({
vertexShader,
fragmentShader,
uniforms,
fog: true,
lights: true,
dithering: true,
side: THREE.DoubleSide,
});

tried it this way simplexNoise not defined

import { mergeUniforms } from './three/src/renderers/shaders/UniformsUtils.js'
import { UniformsLib } from './three/src/renderers/shaders/UniformsLib.js'

export default {


  uniforms: mergeUniforms([
    UniformsLib.lights,
    UniformsLib.fog,
  ]),




simpleNoise: `
float N (vec2 st) { // https://thebookofshaders.com/10/
    return fract( sin( dot( st.xy, vec2(12.9898,78.233 ) ) ) *  43758.5453123);
}

float smoothNoise( vec2 ip ){ // https://www.youtube.com/watch?v=zXsWftRdsvU
  vec2 lv = fract( ip );
  vec2 id = floor( ip );
  
  lv = lv * lv * ( 3. - 2. * lv );
  
  float bl = N( id );
  float br = N( id + vec2( 1, 0 ));
  float b = mix( bl, br, lv.x );
  
  float tl = N( id + vec2( 0, 1 ));
  float tr = N( id + vec2( 1, 1 ));
  float t = mix( tl, tr, lv.x );
  
  return mix( b, t, lv.y );
}
`,

  vertexShader: `
    #include <common>
    #include <fog_pars_vertex>
    #include <shadowmap_pars_vertex>
	varying vec2 vUv;
uniform float time;

${simpleNoise}
    void main() {
      #include <begin_vertex>
      #include <project_vertex>
      #include <worldpos_vertex>
      #include <shadowmap_vertex>
      #include <fog_vertex>
	  
	   vUv = uv;
  float t = time * 2.;
  
  // VERTEX POSITION
  
  vec4 mvPosition = vec4( position, 1.0 );
  #ifdef USE_INSTANCING
    mvPosition = instanceMatrix * mvPosition;
  #endif
  
  // DISPLACEMENT
  
  float noise = smoothNoise(mvPosition.xz * 0.5 + vec2(0., t));
  noise = pow(noise * 0.5 + 0.5, 2.) * 2.;
  
  // here the displacement is made stronger on the blades tips.
  float dispPower = 1. - cos( uv.y * 3.1416 * 0.5 );
  
  float displacement = noise * ( 0.3 * dispPower );
  mvPosition.z -= displacement;
  
  //
  
  vec4 modelViewPosition = modelViewMatrix * mvPosition;
  gl_Position = projectionMatrix * modelViewPosition;
    }
  `,

  fragmentShader: `
    #include <common>
    #include <packing>
    #include <fog_pars_fragment>
    #include <bsdfs>
    #include <lights_pars_begin>
    #include <shadowmap_pars_fragment>
    #include <shadowmask_pars_fragment>
    #include <dithering_pars_fragment>
	varying vec2 vUv;
    void main() {
      // CHANGE THAT TO YOUR NEEDS
      // ------------------------------
	  
	   vec3 baseColor = vec3( 0.41, 1.0, 0.5 );
  float clarity = ( vUv.y * 0.875 ) + 0.125;
     
      vec3 shadowColor = vec3(0, 0, 0);
      float shadowPower = 0.5;
      // ------------------------------
      
	  
      // it just mixes the shadow color with the frag color
      gl_FragColor = vec4( mix( (baseColor * clarity, 1), shadowColor, (1.0 - getShadowMask() ) * shadowPower), 1.0);
	  
	
      #include <fog_fragment>
      #include <dithering_fragment>
    }
  `
};

main:

const uniforms = {

time: {

value: 0

}

}

this.leavesMaterial = new THREE.ShaderMaterial({

...BasicCustomShader,

uniforms,

side: THREE.DoubleSide,

fog: true,

lights: true,

dithering: true,

});