Cast Shadows in Shader Material with alpha map

Hey guys. I have a problem with cast shadows in ShaderMaterial with alpha map. I don’t know how to make the cast shadow look like a shaderMaterial and not like a rectangle. Any advice? When I used a different Material, it works, but the shaderMaterial doesn’t. Any ideas?
image

mesh.customDepthMaterial=new THREE.ShaderMaterial({
uniforms:{
alphaMap:{value:texture},
alphaTest:{value:0.5},
},
vertexShader:vs["grass_depth"],
fragmentShader:fs["grass_depth"],
});

Hi, @Chaser_Code What is inside vs["grass_depth"] and fs["grass_depth"]?

There was alphaTest with shaderMaterial. Here alpha test with MeshDepthMaterial

mesh.customDepthMaterial=new THREE.MeshDepthMaterial({
  depthPacking: THREE.RGBADepthPacking,
  alphaTest: 0.5,  
});

This not working…

  depthPacking: THREE.RGBADepthPacking,
  alphaTest: 0.5,  
});

@Chaser_Code only working:
const material = new MeshPhongMaterial({
alphaMap: alphaMap,
alphaTest: 0.3,
side: DoubleSide,
});

but I need shader…

I am using instanced grass. Small code and needs for correction:

mesh.customDepthMaterial=new THREE.ShaderMaterial({
uniforms:{
map:{value:textureGrass},
},
vertexShader:vs["grass_depth"],
fragmentShader:fs["grass_depth"],
});

vs["grass_depth"]=`
attribute vec3 offset;
...
void main(){
vec3 vPosition=position+offset;
vec4 mvPosition=modelViewMatrix*vec4(vPosition,1.0);
gl_Position=projectionMatrix*mvPosition;
}
`;

fs["grass_depth"]=`
uniform sampler2D map;
void main(){
vec4 diffuse=texture2D(map,vUv);
if(diffuse.a<0.5){ discard; }
gl_FragColor=diffuse;
}
`;

@Chaser_Code hmm… I still have a problem. Now the shadow is hidden.
image

Iam using new THREE.InstancedBufferGeometry instead of instancedMesh. Maybe there difference.
Can u send archive

Try to negate gl_Position.z in grassDepthVertexShader, thus
vDepth = -gl_Position.z / gl_Position.w;

@prisoner849 @Chaser_Code You can try in my repo.

Dekier/html-error (github.com)

file → GRASS.VUE

I dont know about vue. Used standard three.js example webgl_instancing_dynamic.html

const grassDepthVertexShader = `
varying vec2 vUv;
void main(){
vUv=uv;
vec4 mvPosition=vec4(position,1.0);
mvPosition=instanceMatrix*mvPosition;
mvPosition=modelViewMatrix*mvPosition;
gl_Position=projectionMatrix*mvPosition;
}
`;


const grassDepthFragmentShader=`
uniform sampler2D map;
varying vec2 vUv;
void main(){
gl_FragColor=vec4(1.0);
vec4 diffuse=texture2D(map,vUv);
if(diffuse.a<0.5){ discard; }
gl_FragColor=diffuse;
}
`;

image

hmm in Nuxt I have strange spots but in the shade provided by another model

shaders works but why shadows do not appear on the ground
image

grass bounding sphere must be in range of sun.shadow. Try mesh.frustumCulled=false;
And play with shadow parameters:

sun.shadow.mapSize.width=2048;
sun.shadow.mapSize.height=2048; 
sun.shadow.camera.near=0.0;
sun.shadow.camera.far=20;
sun.shadow.camera.left=-20;
sun.shadow.camera.right=20;
sun.shadow.camera.top=20;
sun.shadow.camera.bottom=-20;

near only brought the shadow closer and the rest did not change anything
image

Three.js modified example: webgl_instancing_dynamic.html

<!DOCTYPE html>
<html lang="en">
	<head>
		<title>three.js webgl - instancing - dynamic</title>
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
		<link type="text/css" rel="stylesheet" href="main.css">
	</head>
	<body>

		<!-- Import maps polyfill -->
		<!-- Remove this when import maps will be widely supported -->
		<script async src="https://unpkg.com/es-module-shims@1.3.6/dist/es-module-shims.js"></script>

		<script type="importmap">
			{
				"imports": {
					"three": "../build/three.module.js"
				}
			}
		</script>

		<script type="module">

			import * as THREE from 'three';

			import Stats from './jsm/libs/stats.module.js';
			import { GUI } from './jsm/libs/lil-gui.module.min.js';

			let camera, scene, renderer, stats;

			let mesh;
			const amount = 10;
			const count = Math.pow( amount, 3 );
			const dummy = new THREE.Object3D();

			init();
			animate();

			function init() {

				camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 0.1, 100 );
				camera.position.set(10,10,10 );
				camera.lookAt( 0, 0, 0 );

				scene = new THREE.Scene();

				const loader = new THREE.BufferGeometryLoader();
				loader.load( 'models/json/suzanne_buffergeometry.json', function ( geometry ) {
                          geometry = new THREE.PlaneGeometry(1, 1, 1, 1);
					geometry.computeVertexNormals();
					geometry.scale( 0.5, 0.5, 0.5 );




const textureLoader = new THREE.TextureLoader();
let grassMap = textureLoader.load( './0_grass.png' );
grassMap.encoding = THREE.sRGBEncoding;

        			//const material = new THREE.MeshNormalMaterial();
					// check overdraw



var sun=new THREE.DirectionalLight(0xFFEEBB,1.4);
sun.position.set(-6,10,-5);
sun.castShadow=true;
sun.shadow.mapSize.width=2048;
sun.shadow.mapSize.height=2048;
sun.shadow.camera.near=0.0;
sun.shadow.camera.far=20;
sun.shadow.camera.left=-20;
sun.shadow.camera.right=20;
sun.shadow.camera.top=20;
sun.shadow.camera.bottom=-20;
sun.shadow.bias=-0.00004;
sun.shadow.radius=0.2; // 1 - DEFAULT
sun.shadow.blurSamples=2; // 8 - DEFAULT
sun.shadow.needsUpdate=true;
sun.shadow.autoUpdate=true;
scene.add(sun);


var dhelper=new THREE.DirectionalLightHelper(sun,1);
scene.add(dhelper);


var shadow_camera=new THREE.CameraHelper(sun.shadow.camera);
scene.add(shadow_camera);



let floor=new THREE.Mesh(new THREE.BoxGeometry(10,0.1,10),new THREE.MeshStandardMaterial({color:0x007000}));
floor.castShadow=true;
floor.receiveShadow=true;
floor.position.set(0,0,0);
scene.add(floor);


let bbb=new THREE.Mesh(new THREE.BoxGeometry(1,1,1),new THREE.MeshStandardMaterial({color:0x007000}));
bbb.castShadow=true;
bbb.receiveShadow=true;
bbb.position.set(0,0,0);
scene.add(bbb);


const grassDepthVertexShader = `
varying vec2 vUv;
void main(){
vUv=uv;
vec4 mvPosition=vec4(position,1.0);
mvPosition=instanceMatrix*mvPosition;
mvPosition=modelViewMatrix*mvPosition;
gl_Position=projectionMatrix*mvPosition;
}
`;


const grassDepthFragmentShader=`
uniform sampler2D map;
varying vec2 vUv;
void main(){
gl_FragColor=vec4(1.0);
vec4 diffuse=texture2D(map,vUv);
if(diffuse.a<0.5){ discard; }
gl_FragColor=diffuse;
}
`;


let material = new THREE.MeshBasicMaterial( { map:grassMap,color: 0xffffff, opacity: 1.0, transparent: true,  side: THREE.DoubleSide } );


material=new THREE.ShaderMaterial({
  uniforms: {
    map: { value: grassMap },
  },
  vertexShader: grassDepthVertexShader,
  fragmentShader: grassDepthFragmentShader,
  side: THREE.DoubleSide,
})



mesh = new THREE.InstancedMesh( geometry, material, count );
mesh.instanceMatrix.setUsage( THREE.DynamicDrawUsage ); // will be updated every frame
scene.add( mesh );


mesh.castShadow=true;
mesh.receiveShadow=false;
mesh.frustumCulled=false;


mesh.customDepthMaterial=new THREE.ShaderMaterial({
  uniforms: {
    map: { value: grassMap },
  },
  vertexShader: grassDepthVertexShader,
  fragmentShader: grassDepthFragmentShader,
  side: THREE.DoubleSide,
})


					//

					const gui = new GUI();
					gui.add( mesh, 'count', 0, count );

				} );

				//

				renderer = new THREE.WebGLRenderer( { antialias: true } );
				renderer.setPixelRatio( window.devicePixelRatio );
				renderer.setSize( window.innerWidth, window.innerHeight );
                renderer.shadowMap.enabled=true;
                document.body.appendChild( renderer.domElement );

				//

				stats = new Stats();
				document.body.appendChild( stats.dom );

				//

				window.addEventListener( 'resize', onWindowResize );

			}

			function onWindowResize() {

				camera.aspect = window.innerWidth / window.innerHeight;
				camera.updateProjectionMatrix();

				renderer.setSize( window.innerWidth, window.innerHeight );

			}

			//

			function animate() {

				requestAnimationFrame( animate );

				render();

				stats.update();

			}

			function render() {

				if ( mesh ) {

					const time = Date.now() * 0.001;

					mesh.rotation.x = Math.sin( time / 4 );
					mesh.rotation.y = Math.sin( time / 2 );

					let i = 0;
					const offset = ( amount - 1 ) / 2;

					for ( let x = 0; x < amount; x ++ ) {

						for ( let y = 0; y < amount; y ++ ) {

							for ( let z = 0; z < amount; z ++ ) {

								dummy.position.set( offset - x, offset - y, offset - z );
								dummy.rotation.y = ( Math.sin( x / 4 + time ) + Math.sin( y / 4 + time ) + Math.sin( z / 4 + time ) );
								dummy.rotation.z = dummy.rotation.y * 2;
                                dummy.scale.set( 4,4,4 );
								dummy.updateMatrix();

								mesh.setMatrixAt( i ++, dummy.matrix );

							}

						}

					}

					mesh.instanceMatrix.needsUpdate = true;

				}

				renderer.render( scene, camera );

			}

		</script>

	</body>
</html>