@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
151 lines (95 loc) • 4.2 kB
JavaScript
export const ParticleBillboardShader = {
vertex() {
return `
uniform float cameraNear;
uniform float cameraFar;
uniform vec2 resolution;
attribute float size;
attribute float atlasPatch;
attribute float rotation;
varying vec4 vPatch;
varying float vSize;
varying float vFadeDistance;
varying vec4 vColor;
varying vec2 vRotationMultiplier;
void main() {
float paramScale = 1.0;
vColor = vec4(1.0);
vSize = size * paramScale;
vPatch = atlasPatch;
mat4 modelViewProjectionMatrix = projectionMatrix * modelViewMatrix;
vec4 position4 = vec4( position, 1.0 );
gl_Position = modelViewProjectionMatrix * position4;
float rotationGlobal = rotation;
vRotationMultiplier = vec2( cos(rotationGlobal),sin(rotationGlobal) );
float radius = vSize/2.0;
vFadeDistance = 1.0 / radius;
gl_PointSize = resolution.y * projectionMatrix[1][1] * radius / gl_Position.w;
}`
},
fragment() {
return `
uniform sampler2D tSpriteAtlas;
uniform sampler2D tDepth;
uniform float cameraNear;
uniform float cameraFar;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
uniform vec2 resolution;
varying float vFadeDistance;
varying vec4 vPatch;
varying float vSize;
varying vec4 vColor;
varying vec2 vRotationMultiplier;
float depthToLinear( float z ) {
float z_n = 2.0 * z - 1.0;
float z_e = 2.0 * cameraNear * cameraFar / (cameraFar + cameraNear - z_n * (cameraFar - cameraNear));
return z_e;
}
float calculateFade(in float particleDepth, in float sceneDepth){
float zFade;
float linearParticleDepth = depthToLinear(particleDepth);
float linearSceneDepth = depthToLinear(sceneDepth);
float depthDelta = (linearSceneDepth - linearParticleDepth);
float inputDepth = depthDelta* vFadeDistance;
if(inputDepth <= 0.0){
return 0.0;
}
if(inputDepth >= 1.0){
return 1.0;
}
if(inputDepth <= 0.5){
zFade = 0.5 * pow( clamp(2.0*inputDepth, 0.0, 1.0), 2.0);
}else{
zFade = 1.0 - 0.5 * pow( clamp(2.0*(1.0 - inputDepth), 0.0, 1.0), 2.0);
}
return zFade;
}
void main() {
float fragmentDepth = gl_FragCoord.z;
vec2 pixelPosition = gl_FragCoord.xy / resolution;
float sceneDepth = texture2D( tDepth, pixelPosition ).x;
if(fragmentDepth + 0.0001 > sceneDepth){
discard;
}
vec2 centeredUv = gl_PointCoord.xy - 0.5;
vec2 texelCoordinate = vec2( centeredUv.x* vRotationMultiplier.x - centeredUv.y* vRotationMultiplier.y, centeredUv.x * vRotationMultiplier.y + centeredUv.y * vRotationMultiplier.x) + 0.5;
texelCoordinate = clamp(texelCoordinate, vec2(0.0), vec2(1.0) );
vec2 uv = texelCoordinate*vPatch.zw + vPatch.xy;
vec4 spriteColor = texture2D( tSpriteAtlas, uv );
if(spriteColor.a == 0.0){
discard;
}
vec4 texel = spriteColor *vColor;
float zFade = calculateFade(fragmentDepth, sceneDepth);
texel.a *= zFade;
gl_FragColor = texel;
}`;
}
}