1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
|
#version 120
uniform vec2 mapSizePO2; // (1.0 / pwr2map{x,z} * SQUARE_SIZE)
uniform vec2 mapSize; // (1.0 / map{x,z} * SQUARE_SIZE)
uniform mat4 shadowMatrix;
uniform vec4 shadowParams;
uniform vec3 camPos;
uniform vec3 camUp;
uniform vec3 camRight;
uniform float frame;
uniform vec3 windSpeed;
uniform vec3 sunDir;
uniform vec3 ambientLightColor;
uniform vec3 diffuseLightColor;
varying vec3 normal;
varying vec4 shadingTexCoords;
varying vec2 bladeTexCoords;
varying vec3 ambientDiffuseLightTerm;
#if defined(HAVE_SHADOWS) || defined(SHADOW_GEN)
varying vec4 shadowTexCoords;
#endif
const float PI = 3.14159265358979323846264;
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
// Crytek - foliage animation
// src: http://http.developer.nvidia.com/GPUGems3/gpugems3_ch16.html
//
// This bends the entire plant in the direction of the wind.
// vPos: The world position of the plant *relative* to the base of the plant.
vec3 ApplyMainBending(in vec3 vPos, in vec2 vWind, in float fBendScale)
{
float fLength = length(vPos);
float fBF = vPos.y * fBendScale + 1.0;
fBF *= fBF;
fBF = fBF * fBF - fBF;
vPos.xz += vWind.xy * fBF;
return normalize(vPos) * fLength;
}
vec2 SmoothCurve( vec2 x ) {
return x * x * (3.0 - 2.0 * x);
}
vec2 TriangleWave( vec2 x ) {
return abs( fract( x + 0.5 ) * 1.99 - 1.0 );
}
vec2 SmoothTriangleWave( vec2 x ) {
// similar to sine wave, but faster
return SmoothCurve( TriangleWave( x ) );
}
const vec2 V_FREQ = vec2(1.975, 0.793);
// This provides "chaotic" motion for leaves and branches (the entire plant, really)
void ApplyDetailBending(inout vec3 vPos, vec3 vNormal, float fDetailPhase, float fTime, float fSpeed, float fDetailAmp)
{
float vWavesIn = fTime + fDetailPhase;
vec2 vWaves = (fract( vec2(vWavesIn) * V_FREQ ) * 2.0 - 1.0 ) * fSpeed;
vWaves = SmoothTriangleWave( vWaves );
vPos.xyz += vNormal.xyz * vWaves.xxy * fDetailAmp;
}
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
void main() {
vec2 texOffset = vec2(0.);
gl_FrontColor = gl_Color;
#ifndef DISTANCE_FAR
// mesh grass
normal = gl_NormalMatrix * gl_Normal;
vec4 worldPos = gl_ModelViewMatrix * gl_Vertex;
// anim
vec3 objPos = mat3(gl_ModelViewMatrix) * gl_Vertex.xyz;
worldPos.xyz += ApplyMainBending(objPos, windSpeed.xz, gl_MultiTexCoord0.s * 0.004 + 0.007) - objPos;
ApplyDetailBending(worldPos.xyz, normal,
gl_MultiTexCoord0.s,
frame / 30.0,
0.3,
gl_MultiTexCoord0.t * 0.4);
// compute ambient & diffuse lighting per-vertex, specular is per-pixel
float fNdotL = dot(normal, sunDir);
float diffuseTerm = fNdotL * 0.4 + 0.6; // front surface //TODO make constants customizable?
diffuseTerm = max(diffuseTerm, ((-fNdotL) * 0.3 + 0.7) * 0.8); // back surface //TODO make constants customizable?
ambientDiffuseLightTerm = ambientLightColor + diffuseTerm * diffuseLightColor;
#else
// billboards
gl_FrontColor.a *= gl_Normal.z; // alpha blend far turfs
vec4 worldPos = /* gl_ModelViewMatrix * */ gl_Vertex; // MVM is empty in far draw pass
// get the camera angle on the billboard and select the corresponding sprite
float cosCamAngle = normalize(camPos.xyz - worldPos.xyz).y;
float ang = acos(-cosCamAngle);
texOffset.s = clamp(floor((ang + PI / 16.0 - PI / 2.0) / PI * 30.0), 0.0, 15.0) / 16.0;
// billboard size
vec2 billboardSize = gl_Normal.xy;
// cut of lower half in horizontal views (the fartexture is empty in lower 50% in horizontal view!)
billboardSize.y = max(billboardSize.y, billboardSize.y * cosCamAngle);
// span the billboard
worldPos.xyz += camRight * billboardSize.x;
worldPos.xyz += camUp * billboardSize.y;
// adjust texcoord for cut of billboard
texOffset.t = max((0.5 * cosCamAngle - 0.5), -gl_MultiTexCoord0.t);
// anim
float seed = fract(abs(dot(gl_Vertex.xyz, vec3(1.0))));
vec3 objPos = (worldPos.xyz - gl_Vertex.xyz);
worldPos.xyz += ApplyMainBending(objPos, windSpeed.xz, seed * 0.006 + 0.01) - objPos;
ApplyDetailBending(worldPos.xyz, vec3(1., 0., 1.),
seed,
frame / 30.0,
0.3,
0.5 * max(1.0 - gl_MultiTexCoord0.t, cosCamAngle));
// move up when looking down (to fix clipping issues)
worldPos.y += 5.0 * cosCamAngle;
// compute ambient & diffuse lighting per-vertex
ambientDiffuseLightTerm = ambientLightColor + diffuseLightColor;
#endif
#if defined(HAVE_SHADOWS) || defined(SHADOW_GEN)
vec4 vertexShadowPos = shadowMatrix * worldPos;
vertexShadowPos.st += shadowParams.xy;
shadowTexCoords = vertexShadowPos;
#endif
#ifdef SHADOW_GEN
{
bladeTexCoords = gl_MultiTexCoord0.st + texOffset;
gl_Position = gl_ProjectionMatrix * vertexShadowPos;
return;
}
#endif
shadingTexCoords = worldPos.xzxz * vec4(mapSizePO2, mapSize);
bladeTexCoords = gl_MultiTexCoord0.st + texOffset;
gl_Position = gl_ProjectionMatrix * worldPos;
gl_FogFragCoord = distance(camPos, worldPos.xyz);
gl_FogFragCoord = (gl_Fog.end - gl_FogFragCoord) * gl_Fog.scale;
gl_FogFragCoord = clamp(gl_FogFragCoord, 0.0, 1.0);
}
|