Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
A basic example of a ThreeJS (r108) ShaderMaterial with shadows, fog and dithering support.
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,
]),
vertexShader: `
#include <common>
#include <fog_pars_vertex>
#include <shadowmap_pars_vertex>
void main() {
#include <begin_vertex>
#include <project_vertex>
#include <worldpos_vertex>
#include <shadowmap_vertex>
#include <fog_vertex>
}
`,
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>
void main() {
// CHANGE THAT TO YOUR NEEDS
// ------------------------------
vec3 finalColor = vec3(0, 0.75, 0);
vec3 shadowColor = vec3(0, 0, 0);
float shadowPower = 0.5;
// ------------------------------
// it just mixes the shadow color with the frag color
gl_FragColor = vec4( mix(finalColor, shadowColor, (1.0 - getShadowMask() ) * shadowPower), 1.0);
#include <fog_fragment>
#include <dithering_fragment>
}
`
};
import BasicCustomShader from 'BasicCustomShader.js'
// and here is how to create the material
const material = new THREE.ShaderMaterial({
...BasicCustomShader,
fog: true,
lights: true,
dithering: true,
});
// PS : you should also set `receiveShadow = true` on your mesh !
@forestluch
Copy link

forestluch commented Jun 14, 2022

Hi, thanks for your example, that's good. I have another question...
When I try to write a multi-light support shader like that...

vec3 GetDiffuse(vec3 _normalWS)
{
vec3 normalWS = _normalWS;
vec3 diffuse = vec3(0,0,0);
#if NUM_DIR_LIGHTS > 0
diffuse = LightingLambert(directionalLights[0].color, vNormal, -directionalLights[0].direction);
#endif
#if NUM_POINT_LIGHTS > 0
for(int i=0; i<NUM_POINT_LIGHTS; i++)
{
PointLight light = pointLights[i];
vec3 dTmp = vec3(0,0,0);
float lightAffect = 1.0 - clamp(distance(vPos,light.position) / light.distance,0.0,1.0);
dTmp = LightingLambert(light.color, vNormal, normalize(vPos - light.position)) * lightAffect;
diffuse += dTmp;
}
#endif
diffuse *= getShadowMask();
return diffuse;
}

void main()
{
gl_FragColor = GetDiffuse(NORMAL_FROM_VERTEXSHADER);
}

It causes weird shadow...
How to let that support 2 or more lights with the correct shadow? thanks

@pifragile
Copy link

pifragile commented Dec 9, 2022

thanks a lot this is super helpful!
i tried to run it with r147 and i get:

Shader Error 0 - VALIDATE_STATUS false

Program Info Log: Vertex shader is not compiled.
�
VERTEX

ERROR: 0:193: 'transformedNormal' : undeclared identifier
ERROR: 0:193: 'inverseTransformDirection' : no matching overloaded function found
ERROR: 0:193: '=' : dimension mismatch
ERROR: 0:193: '=' : cannot convert from 'const mediump float' to 'highp 3-component vector of float'
�

  188: 	#endif
  189: 	worldPosition = modelMatrix * worldPosition;
  190: #endif
  191: #if defined( USE_SHADOWMAP ) || ( 1 > 0 )
  192: 	#if 0 > 0 || 1 > 0 || 0 > 0
> 193: 		vec3 shadowWorldNormal = inverseTransformDirection( transformedNormal, viewMatrix );
  194: 		vec4 shadowWorldPosition;
  195: 	#endif
  196: 	#if 0 > 0
  197: 	
  198: 	#endif
  199: 	#if 1 > 0

any advice?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment