packages/miew/src/gfx/shaders/Uber.frag
#if defined (NORMALS_TO_G_BUFFER)
#define fragColor gl_FragData[0]
#else
#define fragColor gl_FragColor
#endif
#ifdef ATTR_ALPHA_COLOR
varying float alphaCol;
#endif
#ifdef COLOR_FROM_POS
uniform mat4 world2colorMatrix;
#endif
#if defined(USE_LIGHTS) && defined(SHADOWMAP)
#if NUM_DIR_LIGHTS > 0
uniform sampler2D directionalShadowMap[ NUM_DIR_LIGHTS ];
uniform mat4 directionalShadowMatrix[ NUM_DIR_LIGHTS ]; //only for sprites
varying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHTS ];
varying vec3 vDirectionalShadowNormal[ NUM_DIR_LIGHTS ];
vec4 vDirLightWorldCoord[ NUM_DIR_LIGHTS ];
vec3 vDirLightWorldNormal[ NUM_DIR_LIGHTS ];
#ifdef SHADOWMAP_PCF_RAND
// We use 4 instead uniform variable or define because this value is used in for(... i < value; ...) with
// unroll_loop and unroll_loop has pattern:
// /#pragma unroll_loop[\s]+?for \( int i \= (\d+)\; i < (\d+)\; i \+\+ \) \{([\s\S]+?)(?=\})\}/g
uniform vec2 samplesKernel[4]; // 4 is length of _samplesKernel which is defined in UberMaterial.js
uniform sampler2D noiseTex;
uniform vec2 noiseTexelSize;
uniform vec2 srcTexelSize;
uniform mat4 projectionMatrix;
#endif
#endif
#endif
#ifdef ATTR_COLOR
varying vec3 vColor;
#endif
#ifdef ATTR_COLOR2
varying vec3 vColor2;
#ifndef CYLINDER_SPRITE
varying vec2 vUv;
#endif
#endif
uniform vec3 diffuse;
uniform vec3 emissive;
uniform vec3 specular;
uniform float shininess;
uniform vec3 fixedColor;
uniform float opacity;
uniform float zClipValue;
uniform float clipPlaneValue;
#ifdef NORMALS_TO_G_BUFFER
varying vec3 viewNormal;
#endif
#define PI 3.14159265359
#define RECIPROCAL_PI 0.31830988618
#define saturate(a) clamp( a, 0.0, 1.0 )
#ifdef USE_FOG
uniform vec3 fogColor;
uniform float fogAlpha;
uniform float fogNear;
uniform float fogFar;
#endif
varying vec3 vWorldPosition; // world position of the pixel (invalid when INSTANCED_SPRITE is defined)
varying vec3 vViewPosition;
#if !defined (SPHERE_SPRITE) && !defined (CYLINDER_SPRITE)
varying vec3 vNormal;
#endif
/////////////////////////////////////////// ZSprites ////////////////////////////////////////////////
#if defined (SPHERE_SPRITE) || defined (CYLINDER_SPRITE)
uniform float nearPlaneValue;
#endif
#ifdef SPHERE_SPRITE
varying vec4 spritePosEye;
#endif
#if defined(SPHERE_SPRITE) || defined(CYLINDER_SPRITE)
uniform float zOffset;
#if !defined(USE_LIGHTS) || !defined(SHADOWMAP) || !defined(SHADOWMAP_PCF_RAND) || !(NUM_DIR_LIGHTS > 0)
uniform mat4 projectionMatrix;
#endif
float calcDepthForSprites(vec4 pixelPosEye, float zOffset, mat4 projMatrix) {
vec4 pixelPosScreen = projMatrix * pixelPosEye;
return 0.5 * (pixelPosScreen.z / pixelPosScreen.w + 1.0) + zOffset;
}
#endif
#ifdef SPHERE_SPRITE
varying vec4 instOffset;
uniform mat4 modelMatrix;
uniform mat4 modelViewMatrix;
uniform mat4 invModelViewMatrix;
uniform mat3 normalMatrix;
bool intersect_ray_sphere(in vec3 origin, in vec3 ray, out vec3 point, out float frontFaced) {
// intersect XZ-projected ray with circle
float a = dot(ray, ray);
float b = dot(ray, origin);
float c = dot(origin, origin) - 1.0;
float det = b * b - a * c;
if (det < 0.0) return false;
float t1 = (-b - sqrt(det)) / a;
float t2 = (-b + sqrt(det)) / a;
// calculate both intersection points
vec3 p1 = origin + ray * t1;
vec3 p2 = origin + ray * t2;
// choose nearest point inside frustum
#ifdef ORTHOGRAPHIC_CAMERA
// orthografic camera is used for dirLight sources. So in it for all spheres the point with smaller 't' is visible
// t1 is always smaller than t2 (from calculations)
point = p1;
frontFaced = 1.0;
return true;
#else
// for perspective camera first intersection can be in front of near plane. If not intersection is p1 else - p2
// t* = 0.0 corresponds to point of intersection near plane by the ray from camera to curPixel
if (t1 >= 0.0) {
point = p1;
frontFaced = 1.0;
return true;
}
if (t2 >= 0.0) {
point = p2;
frontFaced = -1.0;
return true;
}
#endif
return false;
}
bool get_sphere_point(in vec3 pixelPosEye, out vec3 point, out float frontFaced) {
vec3 origin, ray;
#ifdef ORTHOGRAPHIC_CAMERA
// transform vector from sprite center to curPixel into sphere local coords
origin = pixelPosEye.xyz - spritePosEye.xyz;
origin = (invModelViewMatrix * vec4(origin, 0.0)).xyz / instOffset.w;
// transform camera orientation vector into sphere local coords
ray = (invModelViewMatrix * vec4(0.0, 0.0, -1.0, 0.0)).xyz;
#else
// find point of intersection near plane by the ray from camera to curPixel
vec4 v = vec4(-(nearPlaneValue / pixelPosEye.z) * pixelPosEye, 1.0);
// transform intersection point into sphere local coords
v = invModelViewMatrix * v;
origin = (v.xyz - instOffset.xyz) / instOffset.w;
// transform vector from camera pos to curPixel into sphere local coords
ray = (invModelViewMatrix * vec4(pixelPosEye, 0.0)).xyz;
#endif
ray = normalize(ray);
return intersect_ray_sphere(origin, ray, point, frontFaced);
}
#endif
#ifdef CYLINDER_SPRITE
varying vec4 matVec1;
varying vec4 matVec2;
varying vec4 matVec3;
varying vec4 invmatVec1;
varying vec4 invmatVec2;
varying vec4 invmatVec3;
uniform mat4 modelMatrix;
uniform mat4 modelViewMatrix;
uniform mat4 invModelViewMatrix;
uniform mat3 normalMatrix;
varying vec4 spritePosEye;
bool intersect_ray_cylinder(in vec3 origin, in vec3 ray, out vec3 point, out float frontFaced) {
// intersect XZ-projected ray with circle
float a = dot(ray.xz, ray.xz);
float b = dot(ray.xz, origin.xz);
float c = dot(origin.xz, origin.xz) - 1.0;
float det = b * b - a * c;
if (det < 0.0) return false;
float t1 = (-b - sqrt(det)) / a;
float t2 = (-b + sqrt(det)) / a;
// calculate both intersection points
vec3 p1 = origin + ray * t1;
vec3 p2 = origin + ray * t2;
float halfHeight = 0.5;
// choose nearest point
#ifdef ORTHOGRAPHIC_CAMERA
// orthografic camera is used for dirLight sources. So in it for all cylinders the point with smaller 't' is visible
// if it is not outside of cylinnder (t1 is always smaller than t2).
if (p1.y >= -halfHeight && p1.y <= halfHeight) {
point = p1;
frontFaced = 1.0;
return true;
}
if (p2.y >= -halfHeight && p2.y <= halfHeight) {
point = p2;
frontFaced = -1.0;
return true;
}
#else
// for perspective camera first intersection can be in front of near plane. If not intersection is p1 else - p2
// t* = 0.0 corresponds to point of intersection near plane by the ray from camera to curPixel
if (t1 >= 0.0 && p1.y >= -halfHeight && p1.y <= halfHeight) {
point = p1;
frontFaced = 1.0;
return true;
}
if (t2 >= 0.0 && p2.y >= -halfHeight && p2.y <= halfHeight) {
point = p2;
frontFaced = -1.0;
return true;
}
#endif
return false;
}
bool get_cylinder_point(in vec3 pixelPosEye, out vec3 point, out float frontFaced) {
vec3 origin, ray;
vec4 v;
#ifdef ORTHOGRAPHIC_CAMERA
// transform vector from sprite center to curPixel into cylinder local coords
v = invModelViewMatrix * vec4(pixelPosEye.xyz - spritePosEye.xyz, 0.0);
origin = vec3(dot(v, invmatVec1), dot(v, invmatVec2), dot(v, invmatVec3));
// transform camera orientation vector into cylinder local coords
v = invModelViewMatrix * vec4(0.0, 0.0, -1.0, 0.0);
ray = vec3(dot(v, invmatVec1), dot(v, invmatVec2), dot(v, invmatVec3));
#else
// find point of intersection near plane by the ray from camera to curPixel
v = vec4(-(nearPlaneValue / pixelPosEye.z) * pixelPosEye, 1.0);
// transform intersection point into cylinder local coords
v = invModelViewMatrix * v;
origin = vec3(dot(v, invmatVec1), dot(v, invmatVec2), dot(v, invmatVec3));
// transform vector from camera pos to curPixel into cylinder local coords
v = invModelViewMatrix * vec4(pixelPosEye, 0.0);
ray = vec3(dot(v, invmatVec1), dot(v, invmatVec2), dot(v, invmatVec3));
#endif
ray = normalize(ray);
return intersect_ray_cylinder(origin, ray, point, frontFaced);
}
#endif
///////////////////////////////////// Pack and unpack ///////////////////////////////////////////////
const float PackUpscale = 256. / 255.; // fraction -> 0..1 (including 1)
const float UnpackDownscale = 255. / 256.; // 0..1 -> fraction (excluding 1)
const vec3 PackFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );
const vec4 UnpackFactors = UnpackDownscale / vec4( PackFactors, 1. );
const float ShiftRight8 = 1. / 256.;
vec4 packDepthToRGBA( const in float v ) {
vec4 r = vec4( fract( v * PackFactors ), v );
r.yzw -= r.xyz * ShiftRight8; // tidy overflow
return r * PackUpscale;
}
float unpackRGBAToDepth( const in vec4 v ) {
return dot( v, UnpackFactors );
}
////////////////////////////////////////// All Lighting /////////////////////////////////////////////////
#ifdef TOON_SHADING
#define LOW_TOON_BORDER 0.0
#define MEDIUM_TOON_BORDER 0.7
#define HIGH_TOON_BORDER 1.0
#define MEDIUM_TOON_RANGE 0.5
#define HIGH_TOON_RANGE 0.95
#endif
#if defined(USE_LIGHTS) && NUM_DIR_LIGHTS > 0
struct ReflectedLight {
vec3 directDiffuse;
vec3 directSpecular;
vec3 indirectDiffuse;
};
struct BlinnPhongMaterial {
vec3 diffuseColor;
vec3 specularColor;
float specularShininess;
};
struct GeometricContext {
vec3 normal;
vec3 viewDir;
};
struct DirectionalLight {
vec3 direction;
vec3 color;
};
uniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ];
struct DirectionalLightShadow {
vec2 shadowMapSize;
float shadowBias;
float shadowRadius;
};
uniform DirectionalLightShadow directionalLightShadows[ NUM_DIR_LIGHTS ];
uniform vec3 ambientLightColor;
/////////////////////////////////////////// Shadowmap ////////////////////////////////////////////////
#if defined(SHADOWMAP)
float texture2DCompare( sampler2D depths, vec2 uv, float compare ) {
return step( compare, unpackRGBAToDepth( texture2D( depths, uv ) ) );
}
float getShadow( sampler2D shadowMap, DirectionalLightShadow dirLight, vec4 shadowCoord, vec3 vViewPosition, vec3 vNormal ) {
float shadow = 0.0;
// When shadows for sprites will appear use here for them normals as it done for G-buffer
shadowCoord.xyz += dirLight.shadowBias * vNormal;
shadowCoord.xyz /= shadowCoord.w;
bvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );
bool inFrustum = all( inFrustumVec );
bvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );
bool frustumTest = all( frustumTestVec );
if ( frustumTest ) {
#ifdef SHADOWMAP_BASIC
shadow = texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z );
#endif
#ifdef SHADOWMAP_PCF_SHARP
vec2 texelSize = vec2( 1.0 ) / dirLight.shadowMapSize;
float dx0 = - texelSize.x * dirLight.shadowRadius;
float dy0 = - texelSize.y * dirLight.shadowRadius;
float dx1 = + texelSize.x * dirLight.shadowRadius;
float dy1 = + texelSize.y * dirLight.shadowRadius;
shadow = (
texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +
texture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +
texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +
texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +
texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z ) +
texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +
texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +
texture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +
texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )
) * ( 1.0 / 9.0 );
#endif
#ifdef SHADOWMAP_PCF_RAND
vec2 texelSize = vec2( 1.0 ) / dirLight.shadowMapSize;
vec4 vUv = ((projectionMatrix * vec4(vViewPosition, 1.0)) + 1.0) / 2.0;
vec2 vUvNoise = vUv.xy / srcTexelSize * noiseTexelSize;
vec2 noiseVec = normalize(texture2D(noiseTex, vUvNoise).rg);
mat2 mNoise = mat2(noiseVec.x, noiseVec.y, -noiseVec.y, noiseVec.x);
vec2 offset;
#pragma unroll_loop_start
for ( int i = 0; i < 4; i ++ ) { // 4 is length of _samplesKernel which is defined in UberMaterial.js
offset = mNoise * ( normalize( samplesKernel[ i ]) * texelSize * dirLight.shadowRadius );
shadow += texture2DCompare( shadowMap, shadowCoord.xy + offset, shadowCoord.z );
}
#pragma unroll_loop_end
shadow /= float( 4 ); // 4 is length of _samplesKernel which is defined in UberMaterial.js
#endif
}
return shadow;//(shadow != 1.0) ? 0.5 : 1.0;//vec4(shadow, shadow, shadow, 1.0);
}
#endif
/////////////////////////////////////////// Lighting /////////////////////////////////////////////////
vec3 BRDF_Diffuse_Lambert( const in vec3 diffuseColor ) {
return RECIPROCAL_PI * diffuseColor;
} // validated
vec3 F_Schlick( const in vec3 specularColor, const in float dotLH ) {
// Original approximation by Christophe Schlick '94
//;float fresnel = pow( 1.0 - dotLH, 5.0 );
// Optimized variant (presented by Epic at SIGGRAPH '13)
float fresnel = exp2( ( -5.55473 * dotLH - 6.98316 ) * dotLH );
return ( 1.0 - specularColor ) * fresnel + specularColor;
} // validated
float G_BlinnPhong_Implicit( /* const in float dotNL, const in float dotNV */ ) {
// geometry term is (n dot l)(n dot v) / 4(n dot l)(n dot v)
return 0.25;
}
float D_BlinnPhong( const in float shininess, const in float dotNH ) {
return RECIPROCAL_PI * ( shininess * 0.5 + 1.0 ) * pow( dotNH, shininess );
}
vec3 BRDF_Specular_BlinnPhong( const in DirectionalLight incidentLight, const in GeometricContext geometry, const in vec3 specularColor, const in float shininess ) {
vec3 halfDir = normalize( incidentLight.direction + geometry.viewDir );
float dotNH = saturate(dot( geometry.normal, halfDir ));
float dotLH = saturate(dot( incidentLight.direction, halfDir ));
vec3 F = F_Schlick( specularColor, dotLH );
float G = G_BlinnPhong_Implicit( /* dotNL, dotNV */ );
float D = D_BlinnPhong( shininess, dotNH );
return F * ( G * D );
} // validated
void RE_Direct_BlinnPhong( const in DirectionalLight directLight, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight, float penumbra ) {
float dotNL = saturate( dot( geometry.normal, directLight.direction ));
#ifdef TOON_SHADING
if(dotNL < MEDIUM_TOON_RANGE){
dotNL = LOW_TOON_BORDER;
}
else if(dotNL < HIGH_TOON_RANGE){
dotNL = MEDIUM_TOON_BORDER;
}
else{
dotNL = HIGH_TOON_BORDER;
}
#endif
vec3 irradiance = dotNL * directLight.color * PI;
reflectedLight.directDiffuse += penumbra * irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );
reflectedLight.directSpecular += penumbra * irradiance * BRDF_Specular_BlinnPhong( directLight, geometry, material.specularColor, material.specularShininess );
}
void RE_IndirectDiffuse_BlinnPhong( const in vec3 irradiance, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {
reflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );
}
vec3 calcLighting(const in GeometricContext geometry, const in BlinnPhongMaterial material, vec3 vViewPosition) {
ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ));
vec3 irradiance = ambientLightColor * PI;
float shadowMask = 1.0;
// see THREE.WebGLProgram.unrollLoops
#pragma unroll_loop_start
for ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {
#ifdef SHADOWMAP
shadowMask = getShadow( directionalShadowMap[ i ], directionalLightShadows[ i ], vDirLightWorldCoord[ i ], vViewPosition, vDirLightWorldNormal[ i ] );
#endif
if ( shadowMask > 0.0 ) RE_Direct_BlinnPhong( directionalLights[ i ], geometry, material, reflectedLight, shadowMask );
}
#pragma unroll_loop_end
RE_IndirectDiffuse_BlinnPhong(irradiance, material, reflectedLight);
return saturate(reflectedLight.indirectDiffuse + reflectedLight.directDiffuse + reflectedLight.directSpecular);
}
#endif
/////////////////////////////////////////// Dashed Line ///////////////////////////////////////////////
#ifdef DASHED_LINE
uniform float dashedLineSize;
uniform float dashedLinePeriod;
varying float vLineDistance;
#endif
/////////////////////////////////////////// Main ///////////////////////////////////////////////
void main() {
#ifdef CLIP_PLANE
if (vViewPosition.z < clipPlaneValue) discard;
#endif
#ifdef ZCLIP
if (vViewPosition.z < zClipValue) discard;
#endif
#if defined(USE_LIGHTS) && defined(SHADOWMAP)
#if NUM_DIR_LIGHTS > 0
// see THREE.WebGLProgram.unrollLoops
#pragma unroll_loop_start
for ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {
vDirLightWorldCoord[ i ] = vDirectionalShadowCoord[ i ];
vDirLightWorldNormal[ i ] = vDirectionalShadowNormal[ i ];
}
#pragma unroll_loop_end
#endif
#endif
vec4 pixelPosWorld = vec4(vWorldPosition, 1.0);
vec4 pixelPosEye;
#ifdef SPHERE_SPRITE
vec3 viewNormalSprites;
float frontFaced = 1.0;
vec3 normal;
/* quick-and-dirty method
normal.xy = ' + INSTANCED_SPRITE_OVERSCALE + ' * (2.0 * vUv - 1.0);
float r2 = dot(normal.xy, normal.xy);
if (r2 > 1.0) discard;
float normalZ = sqrt(1.0 - r2);
normal.z = normalZ;
normal = normal * ( -1.0 + 2.0 * float( gl_FrontFacing ) );
pixelPosEye = vec4(spritePosEye.xyz, 1.0);
pixelPosEye.z += spritePosEye.w * normalZ;
*/
// ray-trace sphere surface
{
vec3 p;
if (!get_sphere_point(-vViewPosition, p, frontFaced)) discard;
vec4 v = vec4(instOffset.xyz + p * instOffset.w, 1.0);
pixelPosWorld = modelMatrix * v;
pixelPosEye = modelViewMatrix * v;
normal = normalize(normalMatrix * p);
#ifdef NORMALS_TO_G_BUFFER
viewNormalSprites = normalize(mat3(modelViewMatrix)*p);
#endif
#if defined(USE_LIGHTS) && defined(SHADOWMAP)
#if NUM_DIR_LIGHTS > 0
// see THREE.WebGLProgram.unrollLoops
#pragma unroll_loop_start
for ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {
vDirLightWorldCoord[ i ] = directionalShadowMatrix[ i ] * pixelPosWorld;
vDirLightWorldNormal[ i ] = (directionalShadowMatrix[ i ] * (modelMatrix * vec4(p, 0.0))).xyz;
}
#pragma unroll_loop_end
#endif
#endif
}
#endif
#ifdef CYLINDER_SPRITE
vec3 normal;
vec3 viewNormalSprites;
float frontFaced = 1.0;
float cylinderY = 0.0;
// ray-trace cylinder surface
{
vec3 p;
if (!get_cylinder_point(-vViewPosition, p, frontFaced)) discard;
cylinderY = 0.5 * (p.y + 1.0);
vec4 v = vec4(p, 1.0);
v = vec4(dot(v, matVec1), dot(v, matVec2), dot(v, matVec3), 1.0);
pixelPosWorld = modelMatrix * v;
pixelPosEye = modelViewMatrix * v;
vec3 localNormal = normalize(vec3(p.x, 0.0, p.z));
normal = vec3(
dot(localNormal, matVec1.xyz),
dot(localNormal, matVec2.xyz),
dot(localNormal, matVec3.xyz));
#ifdef NORMALS_TO_G_BUFFER
viewNormalSprites = normalize(mat3(modelViewMatrix)*normal);
#endif
#if defined(USE_LIGHTS) && defined(SHADOWMAP)
#if NUM_DIR_LIGHTS > 0
// see THREE.WebGLProgram.unrollLoops
#pragma unroll_loop_start
for ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {
vDirLightWorldCoord[ i ] = directionalShadowMatrix[ i ] * pixelPosWorld;
vDirLightWorldNormal[ i ] = (directionalShadowMatrix[ i ] * (modelMatrix * vec4(normal, 0.0))).xyz;
}
#pragma unroll_loop_end
#endif
#endif
normal = normalize(normalMatrix * normal);
}
#endif
#ifdef ATTR_COLOR
vec3 vertexColor = vColor;
#else
vec3 vertexColor = vec3(1.0, 1.0, 1.0);
#endif
#ifdef ATTR_COLOR2
#ifdef CYLINDER_SPRITE
float colorCoef = cylinderY; // cylinder parameter is calculated from ray-tracing
#else
float colorCoef = vUv.y; // cylinder parameter is interpolated as tex coord
#endif
// choose either color or color2
vertexColor = mix(vColor2, vColor, step(0.5, colorCoef));
#endif
// negative red component is a special condition
if (vertexColor.x < 0.0) discard;
#ifdef DASHED_LINE
if ( mod( vLineDistance, dashedLinePeriod ) > dashedLineSize ) discard;
#endif
// transparency prepass writes only z, so we don't need to calc the color
#ifdef PREPASS_TRANSP
fragColor = vec4(1.0, 1.0, 1.0, 1.0);
#if defined(SPHERE_SPRITE) || defined(CYLINDER_SPRITE)
gl_FragDepthEXT = calcDepthForSprites(pixelPosEye, zOffset, projectionMatrix);
#endif
return;
#endif
float totalOpacity = opacity;
#ifdef ATTR_ALPHA_COLOR
totalOpacity *= alphaCol;
#endif
// discard fully transparent pixels
if (totalOpacity == 0.0) discard;
#ifdef FAKE_OPACITY
// discard pixels in checker pattern
vec2 dm_coord = floor(gl_FragCoord.xy);
dm_coord = fract(dm_coord * 0.5);
if (totalOpacity < 1.0 && (dm_coord.x < 0.5 ^^ dm_coord.y < 0.5)) discard;
vec4 diffuseColor = vec4(diffuse, 1.0);
#else
vec4 diffuseColor = vec4(diffuse, totalOpacity);
#endif
float flipNormal;
#if !defined (SPHERE_SPRITE) && !defined (CYLINDER_SPRITE)
flipNormal = 1.0;
#ifdef DOUBLE_SIDED
flipNormal = float( gl_FrontFacing );
#endif
vec3 normal = normalize( vNormal ) * flipNormal;
#endif
diffuseColor.rgb *= vertexColor;
#if defined(SPHERE_SPRITE) || defined(CYLINDER_SPRITE)
gl_FragDepthEXT = calcDepthForSprites(pixelPosEye, zOffset, projectionMatrix);
#endif
#ifdef NORMALS_TO_G_BUFFER
#if defined (SPHERE_SPRITE) || defined (CYLINDER_SPRITE)
vec3 viewNormaInColor = viewNormalSprites;
#else
vec3 viewNormaInColor = viewNormal;
float frontFaced = float( gl_FrontFacing );
#endif
// [-1, 1] -> [0, 1]
viewNormaInColor = 0.5 * viewNormaInColor + 0.5;
gl_FragData[1] = vec4(viewNormaInColor, frontFaced);
#endif
#if defined(USE_LIGHTS) && NUM_DIR_LIGHTS > 0
vec3 viewDir;
#if defined(SPHERE_SPRITE) || defined(CYLINDER_SPRITE)
viewDir = -pixelPosEye.xyz;
#else
viewDir = vViewPosition;
#endif
GeometricContext geometry = GeometricContext(normal, normalize( viewDir ));
BlinnPhongMaterial material = BlinnPhongMaterial(diffuseColor.rgb, specular, shininess);
vec3 outgoingLight = calcLighting(geometry, material, viewDir);
#else
vec3 outgoingLight = diffuseColor.rgb;
#endif
#ifdef COLOR_FROM_DEPTH
float depth = 0.0;
#if defined(SPHERE_SPRITE) || defined(CYLINDER_SPRITE)
gl_FragDepthEXT = calcDepthForSprites(pixelPosEye, zOffset, projectionMatrix);
depth = gl_FragDepthEXT;
#else
depth = gl_FragCoord.z;
#endif
fragColor = packDepthToRGBA(depth);
return;
#endif
#ifdef COLOR_FROM_POS
fragColor = world2colorMatrix * pixelPosWorld;
#else
#ifdef OVERRIDE_COLOR
fragColor = vec4(fixedColor, diffuseColor.a);
#else
fragColor = vec4(outgoingLight, diffuseColor.a);//vec4(vNormal, 1.0);
#endif
#ifdef USE_FOG
float viewDistance;
#if defined(SPHERE_SPRITE) || defined(CYLINDER_SPRITE)
viewDistance = abs(pixelPosEye.z);
#else
viewDistance = vViewPosition.z;
#endif
float fogFactor = smoothstep( fogNear, fogFar, viewDistance) * fogAlpha;
#ifdef FOG_TRANSPARENT
fragColor.a = fragColor.a * (1.0 - fogFactor);
#else
fragColor.rgb = mix( fragColor.rgb, fogColor, fogFactor );
#endif
#endif
#endif
}