diff options
Diffstat (limited to 'engine-ocean/Resources/Shaders/grassgeom.geom')
-rw-r--r-- | engine-ocean/Resources/Shaders/grassgeom.geom | 250 |
1 files changed, 250 insertions, 0 deletions
diff --git a/engine-ocean/Resources/Shaders/grassgeom.geom b/engine-ocean/Resources/Shaders/grassgeom.geom new file mode 100644 index 0000000..124d6b3 --- /dev/null +++ b/engine-ocean/Resources/Shaders/grassgeom.geom @@ -0,0 +1,250 @@ +#version 330 core + +layout (points) in; +layout (triangle_strip, max_vertices = 36) out; +uniform mat4 view, projection; +uniform vec3 worldSpace_camPos; +uniform float u_time; +uniform sampler2D wind_texture; +uniform sampler2D meadow_texture; +uniform vec3 playerPos; + +uniform vec4 plane; + + + +// texture atlasing +//uniform float numRows; +//uniform vec2 atlas_offset; + +in VS_OUT { + float visibility; +} gs_in[]; + +out GS_OUT { + vec2 texCoord; + float visibility; +} gs_out; + +// grass shader referenced from: https://vulpinii.github.io/tutorials/grass-modelisation/en/ +///////// +float PI = 3.141592653589793; +mat4 windModel = mat4(1.f); +mat4 trampleModel = mat4(1.f); +int numRows = 1; + +vec2 atlas_offset = vec2(0.f); + +vec2 getOffset(int index, int numRows){ + int column = int(mod(index, numRows)); + float xoffset = float(column)/float(numRows); + + int row = index/numRows; + float yOffset = float(row)/float(numRows); + return vec2(xoffset, yOffset); +} + +mat4 rotX(float a){ + mat4 rx = mat4(1.f); + rx[1] = vec4(0.f, cos(a), -sin(a), 0.f); + rx[2] = vec4(0.f, sin(a), cos(a), 0.f); + + return rx; +} + +mat4 rotY(float a){ + mat4 ry = mat4(1.f); + ry[0] = vec4(cos(a), 0.f, sin(a), 0.f); + ry[2] = vec4(-sin(a), 0.f, cos(a), 0.f); + + return ry; +} + +mat4 rotZ(float a){ + mat4 rz = mat4(1.f); + rz[0] = vec4(cos(a), sin(a), 0.f, 0.f); + rz[1] = vec4(-sin(a), cos(a), 0.f, 0.f); + + return rz; +} + +float randomize(vec2 st){ + return fract(sin(dot(st.xy,vec2(12.9898,78.233)))*43758.5453123); +} + + +void makeQuad(vec4 grass_pos, mat4 crossmodel){ + vec4 vertexPos[4]; + vertexPos[0] = vec4(-.9f, 0.f, 0.f, 0.f); // bottom left + vertexPos[1] = vec4(0.9f, 0.f, 0.f, 0.f); // bottom right + vertexPos[2] = vec4(-0.9f, 1.f, 0.f, 0.f); // upper left + vertexPos[3] = vec4(0.9f, 1.f, 0.f, 0.f); // upper right + + vec2 texCoords[4]; + texCoords[0] = vec2(0.f, 0.f); + texCoords[1] = vec2(1.f, 0.f); + texCoords[2] = vec2(0.f, 1.f); + texCoords[3] = vec2(1.f, 1.f); + + mat4 randomY = rotY(randomize(grass_pos.zx)*PI); + + // will apply wind only to top two corners of quad + mat4 defaultWind = mat4(1.f); + mat4 defaultTrample = mat4(1.f); + + gl_ClipDistance[0]=dot(vec4(grass_pos), plane); + + + vec2 clampedOffset = atlas_offset; + for (int i=0; i<4; i++){ + if (i>=2) { + defaultWind = windModel; + defaultTrample = trampleModel; + + } + + gl_Position = projection*view*(grass_pos + (defaultTrample*defaultWind*randomY*crossmodel*vertexPos[i])); + gs_out.texCoord = (texCoords[i]/numRows) + clampedOffset; + EmitVertex(); + } + + EndPrimitive(); + +} + +struct TrampleInfo { + vec3 trampleOffset; + float windMultiplier; + +}; + + +// trample referenced from NedMakesGames: https://www.youtube.com/watch?v=AmO7k-Lr0XM +TrampleInfo calculateTrample(vec3 entityWorldPos, float maxDistance, float falloff, float pushAwayStrength, float pushDownStrength){ + vec3 offset = vec3(0.f); + float windMultiplier = 1.f; + vec3 distanceVec = gl_in[0].gl_Position.xyz-playerPos; + float distance = length(distanceVec); + + // convert to trample strength + float strength = 1 - pow(clamp(distance / maxDistance, 0.f, 1.f), falloff); + + // apply pushAway offest in xz plane + vec3 xzDistance = vec3(distanceVec.x, 0.f, distanceVec.z); + vec3 pushAwayOffset = normalize(xzDistance) * pushAwayStrength * strength; + + // pushDown offset always points downwards + vec3 squishOffset = vec3(0.f, -1.f, 0.f) * pushDownStrength * strength; + + offset += pushAwayOffset + squishOffset; + + // supress wind when this grass is being trampled + + windMultiplier = min(windMultiplier, 1-strength); + + TrampleInfo info; + info.trampleOffset = offset; + info.windMultiplier = windMultiplier; + + return info; +} + +void makeGrass(int numQuads){ + mat4 model0, model45, modelm45; + model0 = mat4(1.f); + model45 = rotY(radians(45)); + modelm45 = rotY(-radians(45)); + + + // wind calculation + vec2 windDir = vec2(1.f); + float windStrength = .05f; + + // uv coordinates of wind + vec2 uv = gl_in[0].gl_Position.xz/10.f + windDir * u_time; + uv.x = mod(uv.x, 1.0); + uv.y = mod(uv.y, 1.0); + vec4 windSpot = texture(wind_texture, uv); + + // get index in meadow texture atlas depending on where uv is + + vec2 meadow_uv = gl_in[0].gl_Position.xz * .03f; + meadow_uv.x = mod(meadow_uv.x, 1.0); + meadow_uv.y = mod(meadow_uv.y, 1.0); + vec4 meadowSpot = texture(meadow_texture, meadow_uv); + float meadowSpotAccumulate = meadowSpot.r + meadowSpot.g + meadowSpot.b; + + // convert meadowSpot to range 0-maxindex + + numRows = 4; + int index = int(((meadowSpotAccumulate) / (3.f) ) * (16.f)); + if (index < 0) index = 0; + if (index > 15) index = 15; + atlas_offset = getOffset(index, numRows); + + + // matrix that rotates top of grass away from player + TrampleInfo info = calculateTrample(playerPos, 2.f, 5.f, .52f, .51f); + trampleModel = (rotX(info.trampleOffset.x*PI*1.f) * rotZ(info.trampleOffset.z*PI*1.f)); + + // matrix that tilts quad in x and z dir, accordiing to wind dir and force + windModel = (rotX(windSpot.x*PI*.75f*info.windMultiplier - PI*.25f) * rotZ(windSpot.z*PI*.75f*info.windMultiplier - PI*.25f)); + + + // draw number of quads based on level of detail + switch(numQuads){ + case 1: { + makeQuad(gl_in[0].gl_Position, model0); + break; + } + case 2: { + makeQuad(gl_in[0].gl_Position, model45); + makeQuad(gl_in[0].gl_Position, modelm45); + break; + } + default: { + makeQuad(gl_in[0].gl_Position, model0); + makeQuad(gl_in[0].gl_Position, model45); + makeQuad(gl_in[0].gl_Position, modelm45); + break; + } + } + +} + + +const float LOD1 = 5.f; +const float LOD2 = 10.f; +const float LOD3 = 30.f; + + +void main() +{ + gs_out.visibility = gs_in[0].visibility; + + vec3 dist_to_camera = gl_in[0].gl_Position.xyz - worldSpace_camPos; + float dist_length = length(dist_to_camera); + + // add transition for smooth levels + float t = 6.f; + if (dist_length > LOD2) t*=1.5f; + dist_length += (randomize(gl_in[0].gl_Position.xz)*t - t/2.f); + + // change depending on distance + int detailLevel = 3; + if (dist_length > LOD1) detailLevel = 2; + if (dist_length > LOD2) detailLevel = 1; + if (dist_length > LOD3) detailLevel = 0; + + // make grass with transition levels + if (detailLevel != 1 + || (detailLevel == 1 && (int(gl_in[0].gl_Position.x * 10) % 1) == 0 + || (int(gl_in[0].gl_Position.z * 10) % 1) == 0) + || (detailLevel == 2 && (int(gl_in[0].gl_Position.x * 5) % 1) == 0 + || (int(gl_in[0].gl_Position.z * 5) % 1) == 0) + ) { + makeGrass(detailLevel); + } +} + + |