#version 330 core // Ouput data layout(location = 0) out vec3 color; uniform sampler2DArray TextureAtlas; uniform sampler2DArray NormalAtlas; uniform sampler2DArray HOSAtlas; uniform mat4 View; uniform vec3 FogColor; #ifdef BLEND in GeometryData #else in VertexData #endif { vec3 Position_worldspace; #ifdef BLEND flat uint Materials[3]; vec3 MaterialRatio; #else flat uint Material; #endif vec3 FaceNormal_modelspace; #ifdef PBR vec3 FaceNormal_worldspace; vec3 EyeDirection_cameraspace; vec3 LightDirection_cameraspace; #endif #ifdef FOG float Depth; #endif } vs; vec3 expand(vec3 v) { return (v - 0.5) * 2; } vec4 getTexture(sampler2DArray sample, vec2 UV) { #ifdef BLEND vec4 colx = texture(sample, vec3(UV, vs.Materials[0])); if(vs.Materials[1] == vs.Materials[0]) { return vs.Materials[2] == vs.Materials[0] ? colx : mix(colx, texture(sample, vec3(UV, vs.Materials[2])), vs.MaterialRatio.z); } else { vec4 coly = texture(sample, vec3(UV, vs.Materials[1])); return vs.Materials[2] == vs.Materials[0] ? mix(colx, coly, vs.MaterialRatio.y) : ( vs.Materials[2] == vs.Materials[1] ? mix(coly, colx, vs.MaterialRatio.x) : colx * vs.MaterialRatio.x + coly * vs.MaterialRatio.y + texture(sample, vec3(UV, vs.Materials[2])) * vs.MaterialRatio.z); } #else return texture(sample, vec3(UV, vs.Material)); #endif } vec3 getTriTexture(sampler2DArray sample, vec2 crdx, vec2 crdy, vec2 crdz, vec3 weights) { return getTexture(sample, crdx).rgb * weights.x + getTexture(sample, crdy).rgb * weights.y + getTexture(sample, crdz).rgb * weights.z; } void main() { float texScale = .5; #ifdef TRIPLANAR // Triplanar float plateauSize = 0.001; float transitionSpeed = 2; vec3 blendWeights = abs(vs.FaceNormal_modelspace); blendWeights = blendWeights - plateauSize; blendWeights = pow(max(blendWeights, 0), vec3(transitionSpeed)); vec2 UVx = vs.Position_worldspace.yz * texScale; vec2 UVy = vs.Position_worldspace.zx * texScale; vec2 UVz = vs.Position_worldspace.xy * texScale; vec3 tex = getTriTexture(TextureAtlas, UVx, UVy, UVz, blendWeights); #ifdef PBR // Whiteout normal blend vec3 texNx = expand(getTexture(NormalAtlas, UVx).rgb); vec3 texNy = expand(getTexture(NormalAtlas, UVy).rgb); vec3 texNz = expand(getTexture(NormalAtlas, UVz).rgb); // Swizzle world normals into tangent space and apply Whiteout blend texNx = vec3(texNx.xy + vs.FaceNormal_worldspace.zy, abs(texNx.z) * vs.FaceNormal_worldspace.x); texNy = vec3(texNy.xy + vs.FaceNormal_worldspace.xz, abs(texNy.z) * vs.FaceNormal_worldspace.y); texNz = vec3(texNz.xy + vs.FaceNormal_worldspace.xy, abs(texNz.z) * vs.FaceNormal_worldspace.z); // Swizzle tangent normals to match world orientation and triblend vec3 worldNormal = normalize(texNx.zyx * blendWeights.x + texNy.xzy * blendWeights.y +texNz.xyz * blendWeights.z); vec3 texHOS = getTriTexture(HOSAtlas, UVx, UVy, UVz, blendWeights); #endif #else // Cheap planar vec3 blendWeights = abs(vs.FaceNormal_modelspace); vec3 nrm = normalize(pow(blendWeights, vec3(80))); vec2 UV = (vec2(vs.Position_worldspace.xy * nrm.z) + vec2(vs.Position_worldspace.yz * nrm.x) + vec2(vs.Position_worldspace.zx * nrm.y)) * texScale; vec3 tex = getTexture(TextureAtlas, UV).rgb; #ifdef PBR vec3 texN = expand(getTexture(NormalAtlas, UV).rgb); // Swizzle world normals into tangent space and apply Whiteout blend // Swizzle tangent normals to match world orientation and triblend vec3 worldNormal = normalize(vec3(texN.xy + vs.FaceNormal_worldspace.zy, abs(texN.z) * vs.FaceNormal_worldspace.x).zyx * blendWeights.x + vec3(texN.xy + vs.FaceNormal_worldspace.xz, abs(texN.z) * vs.FaceNormal_worldspace.y).xzy * blendWeights.y + vec3(texN.xy + vs.FaceNormal_worldspace.xy, abs(texN.z) * vs.FaceNormal_worldspace.z).xyz * blendWeights.z); vec3 texHOS = getTexture(HOSAtlas, UV).rgb; #endif #endif // Colors #ifdef PBR // Material properties vec3 MaterialDiffuseColor = tex; vec3 MaterialAmbientColor = vec3(.1) * MaterialDiffuseColor * texHOS.y; vec3 MaterialSpecularColor = vec3(.8) * texHOS.z; vec3 Normal_cameraspace = normalize((View * vec4(worldNormal,0)).xyz); // Light emission properties // You probably want to put them as uniforms vec3 LightColor = vec3(1, 0.9, 0.9); float LightPower = 1.2f; // Distance to the light float distance = 1.0f;//length( LightPosition_worldspace - Position_worldspace ); // Direction of the light (from the fragment to the light) vec3 l = normalize(vs.LightDirection_cameraspace); // Cosine of the angle between the normal and the light direction, // clamped above 0 // - light is at the vertical of the triangle -> 1 // - light is perpendiular to the triangle -> 0 // - light is behind the triangle -> 0 float cosTheta = clamp(dot(Normal_cameraspace,l), 0,1 ); // Eye vector (towards the camera) vec3 E = normalize(vs.EyeDirection_cameraspace); // Direction in which the triangle reflects the light vec3 R = reflect(-l,Normal_cameraspace); // Cosine of the angle between the Eye vector and the Reflect vector, // clamped to 0 // - Looking into the reflection -> 1 // - Looking elsewhere -> < 1 float cosAlpha = clamp( dot( E,R ), 0,1 ); float visibility=1.0; // MAYBE: shadow color = // Ambient : simulates indirect lighting MaterialAmbientColor + // Diffuse : "color" of the object visibility * MaterialDiffuseColor * LightColor * LightPower * cosTheta / (distance * distance) + // Specular : reflective highlight, like a mirror visibility * MaterialSpecularColor * LightColor * LightPower * pow(cosAlpha,5) / (distance * distance); #else color = tex; #endif #if FOG float ratio = exp(vs.Depth * 0.69)-1; color = mix(color, pow(FogColor, vec3(2.2)), clamp(ratio, 0, 1)); #endif color = pow(color, vec3(1.0 / 2.2)); }