summaryrefslogtreecommitdiff
path: root/engine-ocean/Resources/Shaders/grassgeom.geom
diff options
context:
space:
mode:
Diffstat (limited to 'engine-ocean/Resources/Shaders/grassgeom.geom')
-rw-r--r--engine-ocean/Resources/Shaders/grassgeom.geom250
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);
+ }
+}
+
+