# Cast Shadows in Shader Material with alpha map

**URL:** <https://discourse.threejs.org/t/cast-shadows-in-shader-material-with-alpha-map/59152>\
**Category:** Questions\
**Tags:** shadows, textures, materials, shaders\
**Created:** [December 12, 2023, 2:36pm UTC](https://discourse.threejs.org/t/cast-shadows-in-shader-material-with-alpha-map/59152 "2023-12-12T14:36:52Z")\
**Posts on this page:** 18\
**Page:** 1

<div class="post-metadata">

**Author:** ![MarcinDekier](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/marcindekier/32/27683_2.png) [@MarcinDekier](https://discourse.threejs.org/u/MarcinDekier)\
**Post date:** [December 12, 2023, 2:36pm UTC](https://discourse.threejs.org/t/cast-shadows-in-shader-material-with-alpha-map/59152/1 "2023-12-12T14:36:52Z")

</div>

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](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/3/0/3056df0eaf3b39865ad9d7466a4bb60f3a9e202b.jpeg)

---

<div class="post-metadata">

**Author:** ![Chaser\_Code](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/chaser_code/32/20199_2.png) [@Chaser\_Code](https://discourse.threejs.org/u/Chaser_Code)\
**Post date:** [December 12, 2023, 3:29pm UTC](https://discourse.threejs.org/t/cast-shadows-in-shader-material-with-alpha-map/59152/2 "2023-12-12T15:29:46Z")

</div>

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

```

---

<div class="post-metadata">

**Author:** ![MarcinDekier](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/marcindekier/32/27683_2.png) [@MarcinDekier](https://discourse.threejs.org/u/MarcinDekier)\
**Post date:** [December 12, 2023, 7:53pm UTC](https://discourse.threejs.org/t/cast-shadows-in-shader-material-with-alpha-map/59152/3 "2023-12-12T19:53:47Z")

</div>

> [@Chaser\_Code](#):
>
> `vs["grass_depth"]`

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

---

<div class="post-metadata">

**Author:** ![Chaser\_Code](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/chaser_code/32/20199_2.png) [@Chaser\_Code](https://discourse.threejs.org/u/Chaser_Code)\
**Post date:** [December 13, 2023, 7:41am UTC](https://discourse.threejs.org/t/cast-shadows-in-shader-material-with-alpha-map/59152/4 "2023-12-13T07:41:43Z")

</div>

There was alphaTest with shaderMaterial. Here alpha test with MeshDepthMaterial

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

```

---

<div class="post-metadata">

**Author:** ![MarcinDekier](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/marcindekier/32/27683_2.png) [@MarcinDekier](https://discourse.threejs.org/u/MarcinDekier)\
**Post date:** [December 13, 2023, 8:52am UTC](https://discourse.threejs.org/t/cast-shadows-in-shader-material-with-alpha-map/59152/5 "2023-12-13T08:52:52Z")

</div>

This not working…

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

---

<div class="post-metadata">

**Author:** ![MarcinDekier](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/marcindekier/32/27683_2.png) [@MarcinDekier](https://discourse.threejs.org/u/MarcinDekier)\
**Post date:** [December 13, 2023, 8:54am UTC](https://discourse.threejs.org/t/cast-shadows-in-shader-material-with-alpha-map/59152/6 "2023-12-13T08:54:33Z")

</div>

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

but I need shader…

---

<div class="post-metadata">

**Author:** ![Chaser\_Code](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/chaser_code/32/20199_2.png) [@Chaser\_Code](https://discourse.threejs.org/u/Chaser_Code)\
**Post date:** [December 13, 2023, 9:21am UTC](https://discourse.threejs.org/t/cast-shadows-in-shader-material-with-alpha-map/59152/7 "2023-12-13T09:21:11Z")

</div>

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

```javascript
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;
}
`;

```

 ![image](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/c/6/c604dee10ff24f1e2b20d0f60a4313495151b932.jpeg)

---

<div class="post-metadata">

**Author:** ![MarcinDekier](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/marcindekier/32/27683_2.png) [@MarcinDekier](https://discourse.threejs.org/u/MarcinDekier)\
**Post date:** [December 13, 2023, 9:43am UTC](https://discourse.threejs.org/t/cast-shadows-in-shader-material-with-alpha-map/59152/8 "2023-12-13T09:43:17Z")

</div>

@Chaser_Code hmm… I still have a problem. Now the shadow is hidden.  
 ![image](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/a/0/a0cb9001a5885630ba37d439139738f9d5de2dc7.jpeg)

 ![image](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/0/b/0b1c083b90d5de4a49ea2bea88f69d990f2bd6c7.png)

---

<div class="post-metadata">

**Author:** ![Chaser\_Code](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/chaser_code/32/20199_2.png) [@Chaser\_Code](https://discourse.threejs.org/u/Chaser_Code)\
**Post date:** [December 13, 2023, 10:03am UTC](https://discourse.threejs.org/t/cast-shadows-in-shader-material-with-alpha-map/59152/9 "2023-12-13T10:03:01Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![prisoner849](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/prisoner849/32/535_2.png) [@prisoner849](https://discourse.threejs.org/u/prisoner849)\
**Post date:** [December 13, 2023, 10:24am UTC](https://discourse.threejs.org/t/cast-shadows-in-shader-material-with-alpha-map/59152/10 "2023-12-13T10:24:05Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![MarcinDekier](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/marcindekier/32/27683_2.png) [@MarcinDekier](https://discourse.threejs.org/u/MarcinDekier)\
**Post date:** [December 13, 2023, 10:42am UTC](https://discourse.threejs.org/t/cast-shadows-in-shader-material-with-alpha-map/59152/11 "2023-12-13T10:42:48Z")

</div>

@prisoner849 @Chaser_Code You can try in my repo.

[Dekier/html-error (github.com)](https://github.com/Dekier/html-error)

file → GRASS.VUE

---

<div class="post-metadata">

**Author:** ![Chaser\_Code](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/chaser_code/32/20199_2.png) [@Chaser\_Code](https://discourse.threejs.org/u/Chaser_Code)\
**Post date:** [December 13, 2023, 12:11pm UTC](https://discourse.threejs.org/t/cast-shadows-in-shader-material-with-alpha-map/59152/12 "2023-12-13T12:11:09Z")

</div>

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

```javascript
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](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/c/9/c92ca06927be1d8a6e42422d17e5b48ff4e78d98.jpeg)

---

<div class="post-metadata">

**Author:** ![MarcinDekier](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/marcindekier/32/27683_2.png) [@MarcinDekier](https://discourse.threejs.org/u/MarcinDekier)\
**Post date:** [December 13, 2023, 1:53pm UTC](https://discourse.threejs.org/t/cast-shadows-in-shader-material-with-alpha-map/59152/13 "2023-12-13T13:53:42Z")

</div>

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

 ![image](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/3/1/313e4cb1b351c70fe92ea13a4cff312ede967d1d.jpeg)

---

<div class="post-metadata">

**Author:** ![MarcinDekier](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/marcindekier/32/27683_2.png) [@MarcinDekier](https://discourse.threejs.org/u/MarcinDekier)\
**Post date:** [December 13, 2023, 1:58pm UTC](https://discourse.threejs.org/t/cast-shadows-in-shader-material-with-alpha-map/59152/14 "2023-12-13T13:58:32Z")

</div>

shaders works but why shadows do not appear on the ground  
 ![image](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/9/b/9bc4e2fb7caf7af0d2857bb180b37ce0bc35ae65.png)

---

<div class="post-metadata">

**Author:** ![Chaser\_Code](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/chaser_code/32/20199_2.png) [@Chaser\_Code](https://discourse.threejs.org/u/Chaser_Code)\
**Post date:** [December 13, 2023, 2:05pm UTC](https://discourse.threejs.org/t/cast-shadows-in-shader-material-with-alpha-map/59152/15 "2023-12-13T14:05:29Z")

</div>

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

```javascript
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;

```

---

<div class="post-metadata">

**Author:** ![MarcinDekier](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/marcindekier/32/27683_2.png) [@MarcinDekier](https://discourse.threejs.org/u/MarcinDekier)\
**Post date:** [December 13, 2023, 2:19pm UTC](https://discourse.threejs.org/t/cast-shadows-in-shader-material-with-alpha-map/59152/16 "2023-12-13T14:19:12Z")

</div>

near only brought the shadow closer and the rest did not change anything  
 ![image](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/e/0/e03e1a1fd37e925bb19bd9a7294df5bb058af144.jpeg)

---

<div class="post-metadata">

**Author:** ![Chaser\_Code](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/chaser_code/32/20199_2.png) [@Chaser\_Code](https://discourse.threejs.org/u/Chaser_Code)\
**Post date:** [December 13, 2023, 2:36pm UTC](https://discourse.threejs.org/t/cast-shadows-in-shader-material-with-alpha-map/59152/17 "2023-12-13T14:36:06Z")

</div>

Three.js modified example: webgl\_instancing\_dynamic.html

```javascript
<!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>

```

---

<div class="post-metadata">

**Author:** ![ajp](https://avatars.discourse-cdn.com/v4/letter/a/c4cdca/32.png) [@ajp](https://discourse.threejs.org/u/ajp)\
**Post date:** [November 19, 2024, 6:31pm UTC](https://discourse.threejs.org/t/cast-shadows-in-shader-material-with-alpha-map/59152/18 "2024-11-19T18:31:06Z")

</div>

A working fiddle.js for anyone who comes to this later: [ThreeJS Casting shadows through alpha masked mesh geometry three.js v0.170.0 - JSFiddle - Code Playground](https://jsfiddle.net/8re1wa67/1/)  
This solution of using custom shaders for the `customDepthMaterial` works in v0.170.0 where as [this solution](https://discourse.threejs.org/t/cast-shadow-through-alpha-masked-mesh-customdepthmaterial/12760/3) that used `customDistanceMaterial` worked for older versions of three.js does not seem to work anymore.
