Simon 1 year ago
parent
commit
6ad62ecbff
40 changed files with 2041 additions and 2 deletions
  1. 0 0
      assets/index-968ffcfb.js.map
  2. 1 1
      assets/index-e23b2515.js
  3. 0 0
      assets/index-e23b2515.js.map
  4. 1 0
      characters/README.txt
  5. BIN
      characters/guard.glb
  6. BIN
      characters/paladin.glb
  7. BIN
      characters/ybot.glb
  8. 1 1
      index.html
  9. 1 0
      models/README.txt
  10. BIN
      models/mountain.glb
  11. 67 0
      shaders/bugs-lighting-model-fsh.glsl
  12. 116 0
      shaders/bugs-lighting-model-vsh.glsl
  13. 105 0
      shaders/common.glsl
  14. 143 0
      shaders/grass-lighting-model-fsh.glsl
  15. 232 0
      shaders/grass-lighting-model-vsh.glsl
  16. 17 0
      shaders/header.glsl
  17. 127 0
      shaders/lighting-model-fsh.glsl
  18. 57 0
      shaders/lighting-model-vsh.glsl
  19. 312 0
      shaders/noise.glsl
  20. 44 0
      shaders/oklab.glsl
  21. 109 0
      shaders/phong-lighting-model-fsh.glsl
  22. 44 0
      shaders/phong-lighting-model-vsh.glsl
  23. 14 0
      shaders/sky-lighting-model-fsh.glsl
  24. 15 0
      shaders/sky-lighting-model-vsh.glsl
  25. 54 0
      shaders/sky.glsl
  26. 149 0
      shaders/terrain-lighting-model-fsh.glsl
  27. 84 0
      shaders/terrain-lighting-model-vsh.glsl
  28. 162 0
      shaders/water-lighting-model-fsh.glsl
  29. 46 0
      shaders/water-lighting-model-vsh.glsl
  30. 26 0
      shaders/water-texture-fsh.glsl
  31. 12 0
      shaders/water-texture-vsh.glsl
  32. 21 0
      shaders/wind-lighting-model-fsh.glsl
  33. 81 0
      shaders/wind-lighting-model-vsh.glsl
  34. BIN
      textures/butterfly.png
  35. BIN
      textures/dust.png
  36. BIN
      textures/grass.png
  37. BIN
      textures/grid.png
  38. BIN
      textures/moth.png
  39. BIN
      textures/terrain.png
  40. BIN
      textures/whitesquare.png

File diff suppressed because it is too large
+ 0 - 0
assets/index-968ffcfb.js.map


File diff suppressed because it is too large
+ 1 - 1
assets/index-e23b2515.js


File diff suppressed because it is too large
+ 0 - 0
assets/index-e23b2515.js.map


+ 1 - 0
characters/README.txt

@@ -0,0 +1 @@
+Taken from https://www.mixamo.com/

BIN
characters/guard.glb


BIN
characters/paladin.glb


BIN
characters/ybot.glb


+ 1 - 1
index.html

@@ -5,7 +5,7 @@
   
   <link rel="shortcut icon" href="#">
   <script async src="https://unpkg.com/[email protected]/dist/es-module-shims.js"></script>
-  <script type="module" crossorigin src="/Quick_Grass/assets/index-968ffcfb.js"></script>
+  <script type="module" crossorigin src="/Quick_Grass/assets/index-e23b2515.js"></script>
   <link rel="stylesheet" href="/Quick_Grass/assets/index-e7e16abe.css">
 </head>
 <body>

+ 1 - 0
models/README.txt

@@ -0,0 +1 @@
+These mountains were made from rocks from https://quaternius.com/

BIN
models/mountain.glb


+ 67 - 0
shaders/bugs-lighting-model-fsh.glsl

@@ -0,0 +1,67 @@
+#define PHONG
+uniform vec3 diffuse;
+uniform vec3 emissive;
+uniform vec3 specular;
+uniform float shininess;
+uniform float opacity;
+#include <common>
+#include <packing>
+#include <dithering_pars_fragment>
+#include <color_pars_fragment>
+#include <uv_pars_fragment>
+#include <map_pars_fragment>
+#include <alphamap_pars_fragment>
+#include <alphatest_pars_fragment>
+#include <alphahash_pars_fragment>
+#include <aomap_pars_fragment>
+#include <lightmap_pars_fragment>
+#include <emissivemap_pars_fragment>
+#include <envmap_common_pars_fragment>
+#include <envmap_pars_fragment>
+#include <fog_pars_fragment>
+#include <bsdfs>
+#include <lights_pars_begin>
+#include <normal_pars_fragment>
+#include <lights_phong_pars_fragment>
+#include <shadowmap_pars_fragment>
+#include <bumpmap_pars_fragment>
+#include <normalmap_pars_fragment>
+#include <specularmap_pars_fragment>
+#include <logdepthbuf_pars_fragment>
+#include <clipping_planes_pars_fragment>
+
+varying vec3 vWorldNormal;
+
+uniform sampler2D bugsTexture;
+
+void main() {
+	#include <clipping_planes_fragment>
+	vec4 diffuseColor = vec4( diffuse, opacity );
+
+	ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );
+	vec3 totalEmissiveRadiance = emissive;
+	#include <logdepthbuf_fragment>
+	#include <map_fragment>
+	#include <color_fragment>
+	#include <alphamap_fragment>
+	#include <alphatest_fragment>
+	#include <alphahash_fragment>
+	#include <specularmap_fragment>
+	#include <normal_fragment_begin>
+	#include <normal_fragment_maps>
+	#include <emissivemap_fragment>
+	#include <lights_phong_fragment>
+	#include <lights_fragment_begin>
+	#include <lights_fragment_maps>
+	#include <lights_fragment_end>
+	#include <aomap_fragment>
+	vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;
+
+	#include <envmap_fragment>
+	#include <opaque_fragment>
+	#include <tonemapping_fragment>
+	#include <colorspace_fragment>
+	#include <fog_fragment>
+	#include <premultiplied_alpha_fragment>
+	#include <dithering_fragment>
+}

+ 116 - 0
shaders/bugs-lighting-model-vsh.glsl

@@ -0,0 +1,116 @@
+
+
+#define PHONG
+varying vec3 vViewPosition;
+#include <common>
+#include <uv_pars_vertex>
+#include <displacementmap_pars_vertex>
+#include <envmap_pars_vertex>
+#include <color_pars_vertex>
+#include <fog_pars_vertex>
+#include <normal_pars_vertex>
+#include <morphtarget_pars_vertex>
+#include <skinning_pars_vertex>
+#include <shadowmap_pars_vertex>
+#include <logdepthbuf_pars_vertex>
+#include <clipping_planes_pars_vertex>
+
+varying vec3 vWorldNormal;
+
+uniform vec2 bugsSize;
+uniform vec4 bugsParams;
+uniform float time;
+
+uniform sampler2D heightmap;
+uniform vec3 heightmapParams;
+
+attribute vec3 offset;
+
+
+void main() {
+  #include <uv_vertex>
+  #include <color_vertex>
+  #include <morphcolor_vertex>
+  // #include <beginnormal_vertex>
+
+  vec3 objectNormal = vec3(0.0, 1.0, 0.0);
+#ifdef USE_TANGENT
+  vec3 objectTangent = vec3( tangent.xyz );
+#endif
+
+  // #include <begin_vertex>
+
+vec3 transformed = vec3( position );
+#ifdef USE_ALPHAHASH
+	vPosition = vec3( position );
+#endif
+
+  vec4 bugHashVal = hash42(offset.xz);
+
+  float BUG_SCALE = mix(0.35, 0.55, bugHashVal.z);
+  transformed *= BUG_SCALE;
+
+  const float FLAP_SPEED = 20.0;
+  float flapTimeSample = time * FLAP_SPEED + bugHashVal.x * 100.0;
+  transformed.y += mix(0.0, sin(flapTimeSample), abs(position.x)) * BUG_SCALE;
+  transformed.x *= abs(cos(flapTimeSample));
+
+  float TIME_PERIOD = 20.0;
+  float repeatingTime = TIME_PERIOD * 0.5 - abs(mod(time, TIME_PERIOD) - TIME_PERIOD * 0.5);
+
+  float height = noise11(time * 3.0 + bugHashVal.x * 100.0);
+  // transformed.y += height * 0.5;
+
+  // Loop
+  float loopTime = time * 0.5 + bugHashVal.x * 123.23;
+  float loopSize = 2.0;
+  vec3 bugsOffset = vec3(sin(loopTime) * loopSize, height * 0.125, cos(loopTime) * loopSize) + offset;
+
+  // Forward
+  transformed = rotateY(-loopTime + PI / 2.0) * transformed;
+  transformed += bugsOffset;
+
+  // Center
+  vec3 bugCenter = offset;
+
+  vec3 bugsWorldPos = (modelMatrix * vec4(bugCenter, 1.0)).xyz;
+  vec2 heightmapUV = vec2(
+      remap(bugsWorldPos.x, -heightmapParams.z * 0.5, heightmapParams.z * 0.5, 0.0, 1.0),
+      remap(bugsWorldPos.z, -heightmapParams.z * 0.5, heightmapParams.z * 0.5, 1.0, 0.0));
+  float terrainHeight = texture2D(heightmap, heightmapUV).x * heightmapParams.x - heightmapParams.y;
+  transformed.y += terrainHeight;
+
+  if (terrainHeight < -11.0) {
+    transformed.y -= 1000.0;
+  }
+
+  objectNormal = normal;
+
+  #include <morphnormal_vertex>
+  #include <skinbase_vertex>
+  #include <skinnormal_vertex>
+  #include <defaultnormal_vertex>
+  #include <normal_vertex>
+
+  #include <morphtarget_vertex>
+  #include <skinning_vertex>
+  #include <displacementmap_vertex>
+
+  // #include <project_vertex>
+  vec4 mvPosition = vec4( transformed, 1.0 );
+#ifdef USE_INSTANCING
+	mvPosition = instanceMatrix * mvPosition;
+#endif
+  mvPosition = modelViewMatrix * mvPosition;
+  gl_Position = projectionMatrix * mvPosition;
+
+  #include <logdepthbuf_vertex>
+  #include <clipping_planes_vertex>
+  vViewPosition = - mvPosition.xyz;
+  #include <worldpos_vertex>
+  #include <envmap_vertex>
+  #include <shadowmap_vertex>
+  #include <fog_vertex>
+
+  vWorldNormal = (modelMatrix * vec4(normal.xyz, 0.0)).xyz;
+}

+ 105 - 0
shaders/common.glsl

@@ -0,0 +1,105 @@
+// #define PI 3.14159265359
+
+
+float saturate(float x) {
+  return clamp(x, 0.0, 1.0);
+}
+
+vec2 saturate2(vec2 x) {
+  return clamp(x, vec2(0.0), vec2(1.0));
+}
+
+vec3 saturate3(vec3 x) {
+  return clamp(x, vec3(0.0), vec3(1.0));
+}
+
+
+float linearstep(float minValue, float maxValue, float v) {
+  return clamp((v - minValue) / (maxValue - minValue), 0.0, 1.0);
+}
+
+float inverseLerp(float minValue, float maxValue, float v) {
+  return (v - minValue) / (maxValue - minValue);
+}
+
+float inverseLerpSat(float minValue, float maxValue, float v) {
+  return saturate((v - minValue) / (maxValue - minValue));
+}
+
+float remap(float v, float inMin, float inMax, float outMin, float outMax) {
+  float t = inverseLerp(inMin, inMax, v);
+  return mix(outMin, outMax, t);
+}
+
+vec3 LINEAR_TO_GAMMA(vec3 value) {
+  vec3 colour = pow(value, vec3(1.0 / 2.2));
+
+	return colour;
+}
+
+vec3 GAMMA_TO_LINEAR(vec3 value) {
+  vec3 colour = pow(value, vec3(2.2));
+
+	return colour;
+}
+
+
+float easeOut(float x, float t) {
+	return 1.0 - pow(1.0 - x, t);
+}
+
+float easeIn(float x, float t) {
+	return pow(x, t);
+}
+
+
+mat2 rotate2D(float angle) {
+  float s = sin(angle);
+  float c = cos(angle);
+  return mat2(c, -s, s, c);
+}
+
+mat3 rotateX(float theta) {
+    float c = cos(theta);
+    float s = sin(theta);
+    return mat3(
+        vec3(1, 0, 0),
+        vec3(0, c, -s),
+        vec3(0, s, c)
+    );
+}
+
+// Rotation matrix around the Y axis.
+mat3 rotateY(float theta) {
+    float c = cos(theta);
+    float s = sin(theta);
+    return mat3(
+        vec3(c, 0, s),
+        vec3(0, 1, 0),
+        vec3(-s, 0, c)
+    );
+}
+
+// Rotation matrix around the Z axis.
+mat3 rotateZ(float theta) {
+    float c = cos(theta);
+    float s = sin(theta);
+    return mat3(
+        vec3(c, -s, 0),
+        vec3(s, c, 0),
+        vec3(0, 0, 1)
+    );
+}
+
+mat3 rotateAxis(vec3 axis, float angle) {
+  axis = normalize(axis);
+  float s = sin(angle);
+  float c = cos(angle);
+  float oc = 1.0 - c;
+
+  return mat3(
+    oc * axis.x * axis.x + c,           oc * axis.x * axis.y - axis.z * s,  oc * axis.z * axis.x + axis.y * s,
+    oc * axis.x * axis.y + axis.z * s,  oc * axis.y * axis.y + c,           oc * axis.y * axis.z - axis.x * s,
+    oc * axis.z * axis.x - axis.y * s,  oc * axis.y * axis.z + axis.x * s,  oc * axis.z * axis.z + c
+  );
+}

+ 143 - 0
shaders/grass-lighting-model-fsh.glsl

@@ -0,0 +1,143 @@
+#define PHONG
+uniform vec3 diffuse;
+uniform vec3 emissive;
+uniform vec3 specular;
+uniform float shininess;
+uniform float opacity;
+#include <common>
+#include <packing>
+#include <dithering_pars_fragment>
+#include <color_pars_fragment>
+#include <uv_pars_fragment>
+#include <map_pars_fragment>
+#include <alphamap_pars_fragment>
+#include <alphatest_pars_fragment>
+#include <alphahash_pars_fragment>
+#include <aomap_pars_fragment>
+#include <lightmap_pars_fragment>
+#include <emissivemap_pars_fragment>
+#include <envmap_common_pars_fragment>
+#include <envmap_pars_fragment>
+#include <fog_pars_fragment>
+#include <bsdfs>
+#include <lights_pars_begin>
+#include <normal_pars_fragment>
+// #include <lights_phong_pars_fragment>
+
+uniform sampler2D grassTexture;
+uniform vec3 grassLODColour;
+uniform float time;
+uniform mat3 normalMatrix;
+
+varying vec3 vGrassColour;
+varying vec4 vGrassParams;
+varying vec3 vNormal2;
+varying vec3 vWorldPosition;
+
+varying vec3 vViewPosition;
+struct BlinnPhongMaterial {
+	vec3 diffuseColor;
+	vec3 specularColor;
+	float specularShininess;
+	float specularStrength;
+};
+
+
+void RE_Direct_BlinnPhong( const in IncidentLight directLight, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {
+	float wrap = 0.5;
+	float dotNL = saturate( (dot( geometry.normal, directLight.direction ) + wrap) / (1.0 + wrap) );
+	vec3 irradiance = dotNL * directLight.color;
+	reflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );
+	reflectedLight.directSpecular += irradiance * BRDF_BlinnPhong( directLight.direction, geometry.viewDir, geometry.normal, material.specularColor, material.specularShininess ) * material.specularStrength;
+
+  // Backscatter fakery
+	wrap = 0.5;
+  float backLight = saturate((dot(geometry.viewDir, -directLight.direction) + wrap) / (1.0 + wrap));
+  float falloff = 0.5;//mix(0.5, pow(1.0 - saturate(dot(geometry.viewDir, geometry.normal)), 2.0), 1.0) * 0.5;
+  vec3 scatter = directLight.color * pow(backLight, 1.0) * falloff *  BRDF_Lambert(material.diffuseColor);
+
+  reflectedLight.indirectDiffuse += scatter * (1.0 - vGrassParams.z);
+}
+void RE_IndirectDiffuse_BlinnPhong( const in vec3 irradiance, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {
+	reflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );
+}
+#define RE_Direct				      RE_Direct_BlinnPhong
+#define RE_IndirectDiffuse		RE_IndirectDiffuse_BlinnPhong
+
+#include <shadowmap_pars_fragment>
+#include <bumpmap_pars_fragment>
+#include <normalmap_pars_fragment>
+#include <specularmap_pars_fragment>
+#include <logdepthbuf_pars_fragment>
+#include <clipping_planes_pars_fragment>
+
+
+void main() {
+	vec3 viewDir = normalize(cameraPosition - vWorldPosition);
+
+	#include <clipping_planes_fragment>
+	vec4 diffuseColor = vec4( diffuse, opacity );
+
+  // Grass
+  float heightPercent = vGrassParams.x;
+  float height = vGrassParams.y;
+	float lodFadeIn = vGrassParams.z;
+	float lodFadeOut = 1.0 - lodFadeIn;
+
+  float grassMiddle = mix(
+			smoothstep(abs(vGrassParams.w - 0.5), 0.0, 0.1), 1.0, lodFadeIn);
+
+  float isSandy = saturate(linearstep(-11.0, -14.0, height));
+
+	float density = 1.0 - isSandy;
+
+	// Density is in the range [0, 1]
+	// 0 being no grass
+	// 1 being full grass
+	float aoForDensity = mix(1.0, 0.25, density);
+  float ao = mix(aoForDensity, 1.0, easeIn(heightPercent, 2.0));
+
+  diffuseColor.rgb *= vGrassColour;
+	diffuseColor.rgb *= mix(0.85, 1.0, grassMiddle);
+  diffuseColor.rgb *= ao;
+
+
+	ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );
+	vec3 totalEmissiveRadiance = emissive;
+	#include <logdepthbuf_fragment>
+	#include <map_fragment>
+	#include <color_fragment>
+	#include <alphamap_fragment>
+	#include <alphatest_fragment>
+	#include <alphahash_fragment>
+	#include <specularmap_fragment>
+	#include <normal_fragment_begin>
+	#include <normal_fragment_maps>
+
+	vec3 normal2 = normalize(vNormal2);
+	normal = normalize(mix(vNormal, normal2, vGrassParams.w));
+
+	#include <emissivemap_fragment>
+	// #include <lights_phong_fragment>
+
+  BlinnPhongMaterial material;
+  material.diffuseColor = diffuseColor.rgb;
+  material.specularColor = specular;
+
+	#include <lights_fragment_begin>
+	#include <lights_fragment_maps>
+	#include <lights_fragment_end>
+	#include <aomap_fragment>
+	vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;
+
+	#include <envmap_fragment>
+	#include <opaque_fragment>
+	#include <tonemapping_fragment>
+	#include <colorspace_fragment>
+	// #include <fog_fragment>
+
+	gl_FragColor.xyz = CalculateFog(gl_FragColor.xyz, viewDir, vFogDepth);
+
+	#include <premultiplied_alpha_fragment>
+	#include <dithering_fragment>
+}

+ 232 - 0
shaders/grass-lighting-model-vsh.glsl

@@ -0,0 +1,232 @@
+
+
+#define PHONG
+varying vec3 vViewPosition;
+#include <common>
+#include <uv_pars_vertex>
+#include <displacementmap_pars_vertex>
+#include <envmap_pars_vertex>
+#include <color_pars_vertex>
+#include <fog_pars_vertex>
+#include <normal_pars_vertex>
+#include <morphtarget_pars_vertex>
+#include <skinning_pars_vertex>
+#include <shadowmap_pars_vertex>
+#include <logdepthbuf_pars_vertex>
+#include <clipping_planes_pars_vertex>
+
+varying vec3 vWorldNormal;
+varying vec3 vGrassColour;
+varying vec4 vGrassParams;
+varying vec3 vNormal2;
+varying vec3 vWorldPosition;
+
+uniform vec2 grassSize;
+uniform vec4 grassParams;
+uniform vec4 grassDraw;
+uniform float time;
+uniform sampler2D heightmap;
+uniform vec4 heightParams;
+uniform vec3 playerPos;
+uniform mat4 viewMatrixInverse;
+
+attribute float vertIndex;
+
+
+void main() {
+  #include <uv_vertex>
+  #include <color_vertex>
+  #include <morphcolor_vertex>
+  #include <beginnormal_vertex>
+  #include <begin_vertex>
+
+  vec3 grassOffset = vec3(position.x, 0.0, position.y);
+
+  // Blade world position
+  vec3 grassBladeWorldPos = (modelMatrix * vec4(grassOffset, 1.0)).xyz;
+  vec2 heightmapUV = vec2(
+      remap(grassBladeWorldPos.x, -heightParams.x * 0.5, heightParams.x * 0.5, 0.0, 1.0),
+      remap(grassBladeWorldPos.z, -heightParams.x * 0.5, heightParams.x * 0.5, 1.0, 0.0));
+  vec4 heightmapSample = texture2D(heightmap, heightmapUV);
+  grassBladeWorldPos.y += heightmapSample.x * grassParams.z - grassParams.w;
+
+  float heightmapSampleHeight = 1.0;//mix(0.5, 1.0, heightmapSample.y);
+
+  vec4 hashVal1 = hash42(vec2(grassBladeWorldPos.x, grassBladeWorldPos.z));
+
+  float highLODOut = smoothstep(grassDraw.x * 0.5, grassDraw.x, distance(cameraPosition, grassBladeWorldPos));
+// hack lod
+  float lodFadeIn = smoothstep(grassDraw.x, grassDraw.y, distance(cameraPosition, grassBladeWorldPos));
+
+  // Check terrain type, maybe don't allow grass blade
+  float isSandy = linearstep(-11.0, -14.0, grassBladeWorldPos.y);
+  float grassAllowedHash = hashVal1.w - isSandy;
+  float isGrassAllowed = step(0.0, grassAllowedHash);
+
+  float randomAngle = hashVal1.x * 2.0 * 3.14159;
+  float randomShade = remap(hashVal1.y, -1.0, 1.0, 0.5, 1.0);
+  float randomHeight = remap(hashVal1.z, 0.0, 1.0, 0.75, 1.5) * mix(1.0, 0.0, lodFadeIn) * isGrassAllowed * heightmapSampleHeight;
+  float randomWidth = (1.0 - isSandy) * heightmapSampleHeight;
+  float randomLean = remap(hashVal1.w, 0.0, 1.0, 0.1, 0.4);
+
+  // HACK
+  // randomHeight = 1.0;
+  // randomShade = 1.0;
+  // randomWidth = 1.0;
+
+  vec2 hashGrassColour = hash22(vec2(grassBladeWorldPos.x, grassBladeWorldPos.z));
+  float leanAnimation = noise12(vec2(time * 0.35) + grassBladeWorldPos.xz * 137.423) * 0.1;
+
+  float GRASS_SEGMENTS = grassParams.x;
+  float GRASS_VERTICES = grassParams.y;
+
+  // Figure out vertex id, > GRASS_VERTICES is back side
+  float vertID = mod(float(vertIndex), GRASS_VERTICES);
+
+  // 1 = front, -1 = back
+  float zSide = -(floor(vertIndex / GRASS_VERTICES) * 2.0 - 1.0);
+
+  // 0 = left, 1 = right
+  float xSide = mod(vertID, 2.0);
+
+  float heightPercent = (vertID - xSide) / (GRASS_SEGMENTS * 2.0);
+
+  float grassTotalHeight = grassSize.y * randomHeight;
+  float grassTotalWidthHigh = easeOut(1.0 - heightPercent, 2.0);
+  float grassTotalWidthLow = 1.0 - heightPercent;
+  float grassTotalWidth = grassSize.x * mix(grassTotalWidthHigh, grassTotalWidthLow, highLODOut) * randomWidth;
+
+// hack lod
+  // grassTotalWidth = grassSize.x * randomWidth;
+
+  // Shift verts
+  float x = (xSide - 0.5) * grassTotalWidth;
+  float y = heightPercent * grassTotalHeight;
+
+  float windDir = noise12(grassBladeWorldPos.xz * 0.05 + 0.05 * time);
+  float windNoiseSample = noise12(grassBladeWorldPos.xz * 0.25 + time * 1.0);
+  float windLeanAngle = remap(windNoiseSample, -1.0, 1.0, 0.25, 1.0);
+  windLeanAngle = easeIn(windLeanAngle, 2.0) * 1.25;
+  vec3 windAxis = vec3(cos(windDir), 0.0, sin(windDir));
+
+  windLeanAngle *= heightPercent;
+
+  float distToPlayer = distance(grassBladeWorldPos.xz, playerPos.xz);
+  float playerFalloff = smoothstep(2.5, 1.0, distToPlayer);
+  float playerLeanAngle = mix(0.0, 0.2, playerFalloff * linearstep(0.5, 0.0, windLeanAngle));
+  vec3 grassToPlayer = normalize(vec3(playerPos.x, 0.0, playerPos.z) - vec3(grassBladeWorldPos.x, 0.0, grassBladeWorldPos.z));
+  vec3 playerLeanAxis = vec3(grassToPlayer.z, 0, -grassToPlayer.x);
+
+// hack lod
+  // randomLean = 0.0;
+  // windLeanAngle = 0.0;
+  // leanAnimation = 0.0;
+
+  randomLean += leanAnimation;
+
+  float easedHeight = mix(easeIn(heightPercent, 2.0), 1.0, highLODOut);
+  float curveAmount = -randomLean * easedHeight;
+
+  float ncurve1 = -randomLean * easedHeight;
+  vec3 n1 = vec3(0.0, (heightPercent + 0.01), 0.0);
+  n1 = rotateX(ncurve1) * n1;
+
+  float ncurve2 = -randomLean * easedHeight * 0.9;
+  vec3 n2 = vec3(0.0, (heightPercent + 0.01) * 0.9, 0.0);
+  n2 = rotateX(ncurve2) * n2;
+
+  vec3 ncurve = normalize(n1 - n2);
+
+  mat3 grassMat = rotateAxis(playerLeanAxis, playerLeanAngle) * rotateAxis(windAxis, windLeanAngle) * rotateY(randomAngle);
+
+  vec3 grassFaceNormal = vec3(0.0, 0.0, 1.0);
+  grassFaceNormal = grassMat * grassFaceNormal;
+  grassFaceNormal *= zSide;
+
+  vec3 grassVertexNormal = vec3(0.0, -ncurve.z, ncurve.y);
+  vec3 grassVertexNormal1 = rotateY(PI * 0.3 * zSide) * grassVertexNormal;
+  vec3 grassVertexNormal2 = rotateY(PI * -0.3 * zSide) * grassVertexNormal;
+
+  grassVertexNormal1 = grassMat * grassVertexNormal1;
+  grassVertexNormal1 *= zSide;
+
+  grassVertexNormal2 = grassMat * grassVertexNormal2;
+  grassVertexNormal2 *= zSide;
+
+  vec3 grassVertexPosition = vec3(x, y, 0.0);
+  grassVertexPosition = rotateX(curveAmount) * grassVertexPosition;
+  grassVertexPosition = grassMat * grassVertexPosition;
+
+  grassVertexPosition += grassOffset;
+
+  vec3 b1 = GAMMA_TO_LINEAR(vec3(0.02, 0.075, 0.01));
+  vec3 b2 = GAMMA_TO_LINEAR(vec3(0.025, 0.1, 0.01));
+  vec3 t1 = GAMMA_TO_LINEAR(vec3(0.25, 0.5, 0.15));
+  vec3 t2 = GAMMA_TO_LINEAR(vec3(0.3, 0.6, 0.2));
+
+  vec3 baseColour = mix(b1, b2, hashGrassColour.x);
+  vec3 tipColour = mix(t1, t2, hashGrassColour.y);
+  vec3 highLODColour = mix(baseColour, tipColour, easeIn(heightPercent, 4.0)) * randomShade;
+  vec3 lowLODColour = mix(b1, t1, heightPercent);
+  vGrassColour = mix(highLODColour, lowLODColour, highLODOut);
+  vGrassParams = vec4(heightPercent, grassBladeWorldPos.y, highLODOut, xSide);
+  
+  const float SKY_RATIO = 0.25;
+  // TODO: Grab terrain normal
+  vec3 UP = vec3(0.0, 1.0, 0.0);
+  // float skyFadeIn = smoothstep(grassDraw.x * 0.5, grassDraw.x, distance(cameraPosition, grassBladeWorldPos)) * SKY_RATIO;
+  float skyFadeIn = (1.0 - highLODOut) * SKY_RATIO;
+  vec3 normal1 = normalize(mix(UP, grassVertexNormal1, skyFadeIn));
+  vec3 normal2 = normalize(mix(UP, grassVertexNormal2, skyFadeIn));
+
+  transformed = grassVertexPosition;
+  transformed.y += grassBladeWorldPos.y;
+
+  vec3 cameraWorldLeft = (viewMatrixInverse * vec4(-1.0, 0.0, 0.0, 0.0)).xyz;
+
+  vec3 viewDir = normalize(cameraPosition - grassBladeWorldPos);
+  vec3 viewDirXZ = normalize(vec3(viewDir.x, 0.0, viewDir.z));
+
+  vec3 grassFaceNormalXZ = normalize(vec3(grassFaceNormal.x, 0.0, grassFaceNormal.z));
+
+  float viewDotNormal = saturate(dot(grassFaceNormal, viewDirXZ));
+  float viewSpaceThickenFactor = easeOut(1.0 - viewDotNormal, 4.0) * smoothstep(0.0, 0.2, viewDotNormal);
+
+  objectNormal = grassVertexNormal1;
+
+  #include <morphnormal_vertex>
+  #include <skinbase_vertex>
+  #include <skinnormal_vertex>
+
+  #include <defaultnormal_vertex>
+  #include <normal_vertex>
+
+  vNormal = normalize(normalMatrix * normal1);
+  vNormal2 = normalize(normalMatrix * normal2);
+
+  #include <morphtarget_vertex>
+  #include <skinning_vertex>
+  #include <displacementmap_vertex>
+
+  // #include <project_vertex>
+  vec4 mvPosition = vec4( transformed, 1.0 );
+#ifdef USE_INSTANCING
+	mvPosition = instanceMatrix * mvPosition;
+#endif
+  mvPosition = modelViewMatrix * mvPosition;
+
+  // HACK
+  mvPosition.x += viewSpaceThickenFactor * (xSide - 0.5) * grassTotalWidth * 0.5 * zSide;
+
+  gl_Position = projectionMatrix * mvPosition;
+
+  #include <logdepthbuf_vertex>
+  #include <clipping_planes_vertex>
+  vViewPosition = - mvPosition.xyz;
+  #include <worldpos_vertex>
+  #include <envmap_vertex>
+  #include <shadowmap_vertex>
+  #include <fog_vertex>
+
+  vWorldPosition = worldPosition.xyz;
+}

+ 17 - 0
shaders/header.glsl

@@ -0,0 +1,17 @@
+
+
+vec3 COLOUR_LIGHT_BLUE = vec3(0.42, 0.65, 0.85);
+vec3 COLOUR_LIGHT_GREEN = vec3(0.25, 1.0, 0.25);
+vec3 COLOUR_PALE_GREEN = vec3(0.42, 0.85, 0.65);
+vec3 COLOUR_LIGHT_PURPLE = vec3(0.85, 0.25, 0.85);
+vec3 COLOUR_BRIGHT_PINK = vec3(1.0, 0.5, 0.5);
+
+vec3 COLOUR_BRIGHT_RED = vec3(1.0, 0.1, 0.02);
+vec3 COLOUR_BRIGHT_BLUE = vec3(0.01, 0.2, 1.0);
+vec3 COLOUR_BRIGHT_GREEN = vec3(0.01, 1.0, 0.2);
+vec3 COLOUR_PALE_BLUE = vec3(0.42, 0.65, 0.85);
+vec3 COLOUR_LIGHT_YELLOW = vec3(1.0, 1.0, 0.25);
+
+
+
+#define USE_OKLAB

+ 127 - 0
shaders/lighting-model-fsh.glsl

@@ -0,0 +1,127 @@
+#define STANDARD
+#ifdef PHYSICAL
+	#define IOR
+	#define USE_SPECULAR
+#endif
+uniform vec3 diffuse;
+uniform vec3 emissive;
+uniform float roughness;
+uniform float metalness;
+uniform float opacity;
+#ifdef IOR
+	uniform float ior;
+#endif
+#ifdef USE_SPECULAR
+	uniform float specularIntensity;
+	uniform vec3 specularColor;
+	#ifdef USE_SPECULAR_COLORMAP
+		uniform sampler2D specularColorMap;
+	#endif
+	#ifdef USE_SPECULAR_INTENSITYMAP
+		uniform sampler2D specularIntensityMap;
+	#endif
+#endif
+#ifdef USE_CLEARCOAT
+	uniform float clearcoat;
+	uniform float clearcoatRoughness;
+#endif
+#ifdef USE_IRIDESCENCE
+	uniform float iridescence;
+	uniform float iridescenceIOR;
+	uniform float iridescenceThicknessMinimum;
+	uniform float iridescenceThicknessMaximum;
+#endif
+#ifdef USE_SHEEN
+	uniform vec3 sheenColor;
+	uniform float sheenRoughness;
+	#ifdef USE_SHEEN_COLORMAP
+		uniform sampler2D sheenColorMap;
+	#endif
+	#ifdef USE_SHEEN_ROUGHNESSMAP
+		uniform sampler2D sheenRoughnessMap;
+	#endif
+#endif
+#ifdef USE_ANISOTROPY
+	uniform vec2 anisotropyVector;
+	#ifdef USE_ANISOTROPYMAP
+		uniform sampler2D anisotropyMap;
+	#endif
+#endif
+varying vec3 vViewPosition;
+#include <common>
+#include <packing>
+#include <dithering_pars_fragment>
+#include <color_pars_fragment>
+#include <uv_pars_fragment>
+#include <map_pars_fragment>
+#include <alphamap_pars_fragment>
+#include <alphatest_pars_fragment>
+#include <alphahash_pars_fragment>
+#include <aomap_pars_fragment>
+#include <lightmap_pars_fragment>
+#include <emissivemap_pars_fragment>
+#include <iridescence_fragment>
+#include <cube_uv_reflection_fragment>
+#include <envmap_common_pars_fragment>
+#include <envmap_physical_pars_fragment>
+#include <fog_pars_fragment>
+#include <lights_pars_begin>
+#include <normal_pars_fragment>
+#include <lights_physical_pars_fragment>
+#include <transmission_pars_fragment>
+#include <shadowmap_pars_fragment>
+#include <bumpmap_pars_fragment>
+#include <normalmap_pars_fragment>
+#include <clearcoat_pars_fragment>
+#include <iridescence_pars_fragment>
+#include <roughnessmap_pars_fragment>
+#include <metalnessmap_pars_fragment>
+#include <logdepthbuf_pars_fragment>
+#include <clipping_planes_pars_fragment>
+
+varying vec3 vWorldNormal;
+
+void main() {
+	#include <clipping_planes_fragment>
+	vec4 diffuseColor = vec4( diffuse, opacity );
+	ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );
+	vec3 totalEmissiveRadiance = emissive;
+	#include <logdepthbuf_fragment>
+	#include <map_fragment>
+	#include <color_fragment>
+	#include <alphamap_fragment>
+	#include <alphatest_fragment>
+	#include <alphahash_fragment>
+	#include <roughnessmap_fragment>
+	#include <metalnessmap_fragment>
+	#include <normal_fragment_begin>
+	#include <normal_fragment_maps>
+	#include <clearcoat_normal_fragment_begin>
+	#include <clearcoat_normal_fragment_maps>
+	#include <emissivemap_fragment>
+	#include <lights_physical_fragment>
+	#include <lights_fragment_begin>
+	#include <lights_fragment_maps>
+	#include <lights_fragment_end>
+	#include <aomap_fragment>
+	vec3 totalDiffuse = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse;
+	vec3 totalSpecular = reflectedLight.directSpecular + reflectedLight.indirectSpecular;
+	#include <transmission_fragment>
+	vec3 outgoingLight = totalDiffuse + totalSpecular + totalEmissiveRadiance;
+	#ifdef USE_SHEEN
+		float sheenEnergyComp = 1.0 - 0.157 * max3( material.sheenColor );
+		outgoingLight = outgoingLight * sheenEnergyComp + sheenSpecular;
+	#endif
+	#ifdef USE_CLEARCOAT
+		float dotNVcc = saturate( dot( geometry.clearcoatNormal, geometry.viewDir ) );
+		vec3 Fcc = F_Schlick( material.clearcoatF0, material.clearcoatF90, dotNVcc );
+		outgoingLight = outgoingLight * ( 1.0 - material.clearcoat * Fcc ) + clearcoatSpecular * material.clearcoat;
+	#endif
+
+	#include <opaque_fragment>
+	#include <tonemapping_fragment>
+	#include <colorspace_fragment>
+	#include <fog_fragment>
+	#include <premultiplied_alpha_fragment>
+	#include <dithering_fragment>
+}

+ 57 - 0
shaders/lighting-model-vsh.glsl

@@ -0,0 +1,57 @@
+#define STANDARD
+varying vec3 vViewPosition;
+#ifdef USE_TRANSMISSION
+	varying vec3 vWorldPosition;
+#endif
+#include <common>
+#include <uv_pars_vertex>
+#include <displacementmap_pars_vertex>
+#include <color_pars_vertex>
+#include <fog_pars_vertex>
+#include <normal_pars_vertex>
+#include <morphtarget_pars_vertex>
+#include <skinning_pars_vertex>
+#include <shadowmap_pars_vertex>
+#include <logdepthbuf_pars_vertex>
+#include <clipping_planes_pars_vertex>
+
+varying vec3 vWorldNormal;
+
+void main() {
+	#include <uv_vertex>
+	#include <color_vertex>
+	#include <morphcolor_vertex>
+	#include <beginnormal_vertex>
+	#include <morphnormal_vertex>
+	#include <skinbase_vertex>
+	#include <skinnormal_vertex>
+	#include <defaultnormal_vertex>
+	#include <normal_vertex>
+	#include <begin_vertex>
+	#include <morphtarget_vertex>
+	#include <skinning_vertex>
+	#include <displacementmap_vertex>
+	#include <project_vertex>
+	#include <logdepthbuf_vertex>
+	#include <clipping_planes_vertex>
+
+	vViewPosition = - mvPosition.xyz;
+
+	// #include <worldpos_vertex>
+#if defined( USE_ENVMAP ) || defined( DISTANCE ) || defined ( USE_SHADOWMAP ) || defined ( USE_TRANSMISSION ) || NUM_SPOT_LIGHT_COORDS > 0
+	vec4 worldPosition = vec4( transformed, 1.0 );
+	#ifdef USE_INSTANCING
+		worldPosition = instanceMatrix * worldPosition;
+	#endif
+	worldPosition = modelMatrix * worldPosition;
+#endif
+
+	#include <shadowmap_vertex>
+	#include <fog_vertex>
+#ifdef USE_TRANSMISSION
+	vWorldPosition = worldPosition.xyz;
+#endif
+
+	vWorldNormal = (modelMatrix * vec4(normal.xyz, 0.0)).xyz;
+	// vWorldNormal = normal.xyz;
+}

+ 312 - 0
shaders/noise.glsl

@@ -0,0 +1,312 @@
+// Virtually all of these were taken from: https://www.shadertoy.com/view/ttc3zr
+
+uvec4 murmurHash42(uvec2 src) {
+    const uint M = 0x5bd1e995u;
+    uvec4 h = uvec4(1190494759u, 2147483647u, 3559788179u, 179424673u);
+    src *= M; src ^= src>>24u; src *= M;
+    h *= M; h ^= src.x; h *= M; h ^= src.y;
+    h ^= h>>13u; h *= M; h ^= h>>15u;
+    return h;
+}
+
+uint murmurHash11(uint src) {
+  const uint M = 0x5bd1e995u;
+  uint h = 1190494759u;
+  src *= M; src ^= src>>24u; src *= M;
+  h *= M; h ^= src;
+  h ^= h>>13u; h *= M; h ^= h>>15u;
+  return h;
+}
+
+uint murmurHash12(uvec2 src) {
+  const uint M = 0x5bd1e995u;
+  uint h = 1190494759u;
+  src *= M; src ^= src>>24u; src *= M;
+  h *= M; h ^= src.x; h *= M; h ^= src.y;
+  h ^= h>>13u; h *= M; h ^= h>>15u;
+  return h;
+}
+
+uint murmurHash13(uvec3 src) {
+    const uint M = 0x5bd1e995u;
+    uint h = 1190494759u;
+    src *= M; src ^= src>>24u; src *= M;
+    h *= M; h ^= src.x; h *= M; h ^= src.y; h *= M; h ^= src.z;
+    h ^= h>>13u; h *= M; h ^= h>>15u;
+    return h;
+}
+
+uvec2 murmurHash22(uvec2 src) {
+  const uint M = 0x5bd1e995u;
+  uvec2 h = uvec2(1190494759u, 2147483647u);
+  src *= M; src ^= src>>24u; src *= M;
+  h *= M; h ^= src.x; h *= M; h ^= src.y;
+  h ^= h>>13u; h *= M; h ^= h>>15u;
+  return h;
+}
+
+uvec2 murmurHash21(uint src) {
+  const uint M = 0x5bd1e995u;
+  uvec2 h = uvec2(1190494759u, 2147483647u);
+  src *= M; src ^= src>>24u; src *= M;
+  h *= M; h ^= src;
+  h ^= h>>13u; h *= M; h ^= h>>15u;
+  return h;
+}
+
+uvec2 murmurHash23(uvec3 src) {
+    const uint M = 0x5bd1e995u;
+    uvec2 h = uvec2(1190494759u, 2147483647u);
+    src *= M; src ^= src>>24u; src *= M;
+    h *= M; h ^= src.x; h *= M; h ^= src.y; h *= M; h ^= src.z;
+    h ^= h>>13u; h *= M; h ^= h>>15u;
+    return h;
+}
+
+uvec3 murmurHash31(uint src) {
+    const uint M = 0x5bd1e995u;
+    uvec3 h = uvec3(1190494759u, 2147483647u, 3559788179u);
+    src *= M; src ^= src>>24u; src *= M;
+    h *= M; h ^= src;
+    h ^= h>>13u; h *= M; h ^= h>>15u;
+    return h;
+}
+
+uvec3 murmurHash33(uvec3 src) {
+  const uint M = 0x5bd1e995u;
+  uvec3 h = uvec3(1190494759u, 2147483647u, 3559788179u);
+  src *= M; src ^= src>>24u; src *= M;
+  h *= M; h ^= src.x; h *= M; h ^= src.y; h *= M; h ^= src.z;
+  h ^= h>>13u; h *= M; h ^= h>>15u;
+  return h;
+}
+
+// 3 outputs, 3 inputs
+vec3 hash33(vec3 src) {
+  uvec3 h = murmurHash33(floatBitsToUint(src));
+  return uintBitsToFloat(h & 0x007fffffu | 0x3f800000u) - 1.0;
+}
+
+// 1 output, 1 input
+float hash11(float src) {
+  uint h = murmurHash11(floatBitsToUint(src));
+  return uintBitsToFloat(h & 0x007fffffu | 0x3f800000u) - 1.0;
+}
+
+// 1 output, 2 inputs
+float hash12(vec2 src) {
+  uint h = murmurHash12(floatBitsToUint(src));
+  return uintBitsToFloat(h & 0x007fffffu | 0x3f800000u) - 1.0;
+}
+
+// 1 output, 3 inputs
+float hash13(vec3 src) {
+    uint h = murmurHash13(floatBitsToUint(src));
+    return uintBitsToFloat(h & 0x007fffffu | 0x3f800000u) - 1.0;
+}
+
+// 2 outputs, 1 input
+vec2 hash21(float src) {
+  uvec2 h = murmurHash21(floatBitsToUint(src));
+  return uintBitsToFloat(h & 0x007fffffu | 0x3f800000u) - 1.0;
+}
+
+// 3 outputs, 1 input
+vec3 hash31(float src) {
+    uvec3 h = murmurHash31(floatBitsToUint(src));
+    return uintBitsToFloat(h & 0x007fffffu | 0x3f800000u) - 1.0;
+}
+
+// 2 outputs, 2 inputs
+vec2 hash22(vec2 src) {
+  uvec2 h = murmurHash22(floatBitsToUint(src));
+  return uintBitsToFloat(h & 0x007fffffu | 0x3f800000u) - 1.0;
+}
+
+// 4 outputs, 2 inputs
+vec4 hash42(vec2 src) {
+  uvec4 h = murmurHash42(floatBitsToUint(src));
+  return uintBitsToFloat(h & 0x007fffffu | 0x3f800000u) - 1.0;
+}
+
+
+// 2 outputs, 3 inputs
+vec2 hash23(vec3 src) {
+    uvec2 h = murmurHash23(floatBitsToUint(src));
+    return uintBitsToFloat(h & 0x007fffffu | 0x3f800000u) - 1.0;
+}
+
+float noise11(float p) {
+  float i = floor(p);
+
+  float f = fract(p);
+  float u = smoothstep(0.0, 1.0, f);
+
+	float val = mix( hash11(i + 0.0),
+                   hash11(i + 1.0), u);
+  return val * 2.0 - 1.0;
+}
+
+float noise12(vec2 p) {
+  vec2 i = floor(p);
+
+  vec2 f = fract(p);
+  vec2 u = smoothstep(vec2(0.0), vec2(1.0), f);
+
+	float val = mix( mix( hash12( i + vec2(0.0, 0.0) ), 
+                        hash12( i + vec2(1.0, 0.0) ), u.x),
+                   mix( hash12( i + vec2(0.0, 1.0) ), 
+                        hash12( i + vec2(1.0, 1.0) ), u.x), u.y);
+  return val * 2.0 - 1.0;
+}
+
+float noise13(vec3 x) {
+  vec3 i = floor(x);
+  vec3 f = fract(x);
+  f = f*f*(3.0-2.0*f);
+
+  return mix(mix(mix( hash13(i+vec3(0.0, 0.0, 0.0)), 
+                      hash13(i+vec3(1.0, 0.0, 0.0)),f.x),
+                 mix( hash13(i+vec3(0.0, 1.0, 0.0)), 
+                      hash13(i+vec3(1.0, 1.0, 0.0)),f.x),f.y),
+             mix(mix( hash13(i+vec3(0.0, 0.0, 1.0)), 
+                      hash13(i+vec3(1.0, 0.0, 1.0)),f.x),
+                 mix( hash13(i+vec3(0.0, 1.0, 1.0)), 
+                      hash13(i+vec3(1.0, 1.0, 1.0)),f.x),f.y),f.z);
+}
+
+vec2 noise23(vec3 x) {
+  vec3 i = floor(x);
+  vec3 f = fract(x);
+  f = f*f*(3.0-2.0*f);
+
+  return mix(mix(mix( hash23(i+vec3(0.0, 0.0, 0.0)), 
+                      hash23(i+vec3(1.0, 0.0, 0.0)),f.x),
+                 mix( hash23(i+vec3(0.0, 1.0, 0.0)), 
+                      hash23(i+vec3(1.0, 1.0, 0.0)),f.x),f.y),
+             mix(mix( hash23(i+vec3(0.0, 0.0, 1.0)), 
+                      hash23(i+vec3(1.0, 0.0, 1.0)),f.x),
+                 mix( hash23(i+vec3(0.0, 1.0, 1.0)), 
+                      hash23(i+vec3(1.0, 1.0, 1.0)),f.x),f.y),f.z);
+}
+
+vec2 noise22(vec2 p) {
+	vec2 i = floor(p);
+
+	vec2 f = fract(p);
+	vec2 u = smoothstep(vec2(0.0), vec2(1.0), f);
+
+	vec2 val = mix( mix( hash22( i + vec2(0.0, 0.0) ), 
+											 hash22( i + vec2(1.0, 0.0) ), u.x),
+									mix( hash22( i + vec2(0.0, 1.0) ), 
+											 hash22( i + vec2(1.0, 1.0) ), u.x), u.y);
+	return val * 2.0 - 1.0;
+}
+
+// The MIT License
+// Copyright © 2017 Inigo Quilez
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+// https://www.youtube.com/c/InigoQuilez
+// https://iquilezles.org/
+vec4 noised_1_3(vec3 x) {
+  vec3 i = floor(x);
+  vec3 f = fract(x);
+    
+  // quintic interpolant
+  vec3 u = f*f*f*(f*(f*6.0-15.0)+10.0);
+  vec3 du = 30.0*f*f*(f*(f-2.0)+1.0);
+    
+  // gradients
+  vec3 ga = hash33( i+vec3(0.0,0.0,0.0) ) * 2.0 - 1.0;
+  vec3 gb = hash33( i+vec3(1.0,0.0,0.0) ) * 2.0 - 1.0;
+  vec3 gc = hash33( i+vec3(0.0,1.0,0.0) ) * 2.0 - 1.0;
+  vec3 gd = hash33( i+vec3(1.0,1.0,0.0) ) * 2.0 - 1.0;
+  vec3 ge = hash33( i+vec3(0.0,0.0,1.0) ) * 2.0 - 1.0;
+	vec3 gf = hash33( i+vec3(1.0,0.0,1.0) ) * 2.0 - 1.0;
+  vec3 gg = hash33( i+vec3(0.0,1.0,1.0) ) * 2.0 - 1.0;
+  vec3 gh = hash33( i+vec3(1.0,1.0,1.0) ) * 2.0 - 1.0;
+    
+  // projections
+  float va = dot( ga, f-vec3(0.0,0.0,0.0) );
+  float vb = dot( gb, f-vec3(1.0,0.0,0.0) );
+  float vc = dot( gc, f-vec3(0.0,1.0,0.0) );
+  float vd = dot( gd, f-vec3(1.0,1.0,0.0) );
+  float ve = dot( ge, f-vec3(0.0,0.0,1.0) );
+  float vf = dot( gf, f-vec3(1.0,0.0,1.0) );
+  float vg = dot( gg, f-vec3(0.0,1.0,1.0) );
+  float vh = dot( gh, f-vec3(1.0,1.0,1.0) );
+	
+  // interpolations
+  return vec4( va + u.x*(vb-va) + u.y*(vc-va) + u.z*(ve-va) + u.x*u.y*(va-vb-vc+vd) + u.y*u.z*(va-vc-ve+vg) + u.z*u.x*(va-vb-ve+vf) + (-va+vb+vc-vd+ve-vf-vg+vh)*u.x*u.y*u.z,    // value
+                ga + u.x*(gb-ga) + u.y*(gc-ga) + u.z*(ge-ga) + u.x*u.y*(ga-gb-gc+gd) + u.y*u.z*(ga-gc-ge+gg) + u.z*u.x*(ga-gb-ge+gf) + (-ga+gb+gc-gd+ge-gf-gg+gh)*u.x*u.y*u.z +   // derivatives
+                du * (vec3(vb,vc,ve) - va + u.yzx*vec3(va-vb-vc+vd,va-vc-ve+vg,va-vb-ve+vf) + u.zxy*vec3(va-vb-ve+vf,va-vb-vc+vd,va-vc-ve+vg) + u.yzx*u.zxy*(-va+vb+vc-vd+ve-vf-vg+vh) ));
+}
+
+float FBM_1_2(vec2 p, int octaves, float persistence, float lacunarity) {
+  float amplitude = 1.0;
+  float frequency = 1.0;
+  float total = 0.0;
+  float normalization = 0.0;
+
+  for (int i = 0; i < octaves; ++i) {
+    float noiseValue = noise12(p * frequency);
+    total += noiseValue * amplitude;
+    normalization += amplitude;
+    amplitude *= persistence;
+    frequency *= lacunarity;
+  }
+
+  total /= normalization;
+  total = total * 0.5 + 0.5;
+
+  return total;
+}
+
+float FBM_1_3(vec3 p, int octaves, float persistence, float lacunarity) {
+  float amplitude = 1.0;
+  float frequency = 1.0;
+  float total = 0.0;
+  float normalization = 0.0;
+
+  for (int i = 0; i < octaves; ++i) {
+    float noiseValue = noise13(p * frequency);
+    total += noiseValue * amplitude;
+    normalization += amplitude;
+    amplitude *= persistence;
+    frequency *= lacunarity;
+  }
+
+  total /= normalization;
+  total = total * 0.5 + 0.5;
+
+  return total;
+}
+
+const mat3 m3  = mat3( 0.00,  0.80,  0.60,
+                      -0.80,  0.36, -0.48,
+                      -0.60, -0.48,  0.64 );
+const mat3 m3i = mat3( 0.00, -0.80, -0.60,
+                       0.80,  0.36, -0.48,
+                       0.60, -0.48,  0.64 );
+
+vec4 FBM_D_1_4(in vec3 x, int octaves) {
+  float f = 1.98;  // could be 2.0
+  float s = 0.49;  // could be 0.5
+  float a = 0.0;
+  float b = 0.5;
+  vec3  d = vec3(0.0);
+  mat3  m = mat3(
+      1.0,0.0,0.0,
+      0.0,1.0,0.0,
+      0.0,0.0,1.0);
+  for( int i=0; i < octaves; i++ )
+  {
+      vec4 n = noised_1_3(x);
+      a += b*n.x;          // accumulate values
+      d += b*m*n.yzw;      // accumulate derivatives
+      b *= s;
+      x = f*m3*x;
+      m = f*m3i*m;
+  }
+  return vec4( a, d );
+}

+ 44 - 0
shaders/oklab.glsl

@@ -0,0 +1,44 @@
+/////////////////////////////////////////////////////////////////////////
+//
+// OKLab stuff, mostly based off https://www.shadertoy.com/view/ttcyRS
+//
+/////////////////////////////////////////////////////////////////////////
+
+const mat3 kLMStoCONE = mat3(
+    4.0767245293, -1.2681437731, -0.0041119885,
+    -3.3072168827, 2.6093323231, -0.7034763098,
+    0.2307590544, -0.3411344290,  1.7068625689);
+
+const mat3 kCONEtoLMS = mat3(
+    0.4121656120, 0.2118591070, 0.0883097947,
+    0.5362752080, 0.6807189584, 0.2818474174,
+    0.0514575653, 0.1074065790, 0.6302613616);
+
+vec3 rgbToOklab(vec3 c) {
+  vec3 lms = kCONEtoLMS * c;
+
+  return sign(lms)*pow(abs(lms), vec3(0.3333333333333));
+}
+
+vec3 oklabToRGB(vec3 c) {
+  vec3 lms = c;
+  
+  return kLMStoCONE * (lms * lms * lms);
+}
+
+
+#ifndef USE_OKLAB
+#define col3 vec3
+#else
+vec3 col3(float r, float g, float b) {
+  return rgbToOklab(vec3(r, g, b));
+}
+
+vec3 col3(vec3 v) {
+  return rgbToOklab(v);
+}
+
+vec3 col3(float v) {
+  return rgbToOklab(vec3(v));
+}
+#endif

+ 109 - 0
shaders/phong-lighting-model-fsh.glsl

@@ -0,0 +1,109 @@
+#define PHONG
+uniform vec3 diffuse;
+uniform vec3 emissive;
+uniform vec3 specular;
+uniform float shininess;
+uniform float opacity;
+#include <common>
+#include <packing>
+#include <dithering_pars_fragment>
+#include <color_pars_fragment>
+#include <uv_pars_fragment>
+#include <map_pars_fragment>
+#include <alphamap_pars_fragment>
+#include <alphatest_pars_fragment>
+#include <alphahash_pars_fragment>
+#include <aomap_pars_fragment>
+#include <lightmap_pars_fragment>
+#include <emissivemap_pars_fragment>
+#include <envmap_common_pars_fragment>
+#include <envmap_pars_fragment>
+#include <fog_pars_fragment>
+#include <bsdfs>
+#include <lights_pars_begin>
+#include <normal_pars_fragment>
+
+varying vec3 vViewPosition;
+struct BlinnPhongMaterial {
+	vec3 diffuseColor;
+	vec3 specularColor;
+	float specularShininess;
+	float specularStrength;
+};
+void RE_Direct_BlinnPhong( const in IncidentLight directLight, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {
+	float dotNL = saturate( dot( geometry.normal, directLight.direction ) );
+	vec3 irradiance = dotNL * directLight.color;
+	reflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );
+	reflectedLight.directSpecular += irradiance * BRDF_BlinnPhong( directLight.direction, geometry.viewDir, geometry.normal, material.specularColor, material.specularShininess ) * material.specularStrength;
+
+  // Backscatter
+  float backLight = saturate(dot(geometry.viewDir, -directLight.direction));
+  float falloff = pow(1.0 - saturate(dot(geometry.viewDir, geometry.normal)), 2.0);
+  vec3 scatter = directLight.color * pow(backLight, 4.0) * falloff *  BRDF_Lambert(material.diffuseColor);
+
+  // reflectedLight.indirectDiffuse += scatter * 2.0;
+}
+void RE_IndirectDiffuse_BlinnPhong( const in vec3 irradiance, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {
+	reflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );
+}
+#define RE_Direct				      RE_Direct_BlinnPhong
+#define RE_IndirectDiffuse		RE_IndirectDiffuse_BlinnPhong
+
+
+#include <shadowmap_pars_fragment>
+#include <bumpmap_pars_fragment>
+#include <normalmap_pars_fragment>
+#include <specularmap_pars_fragment>
+#include <logdepthbuf_pars_fragment>
+#include <clipping_planes_pars_fragment>
+
+
+varying vec3 vWorldNormal;
+varying vec3 vWorldPosition;
+
+void main() {
+	#include <clipping_planes_fragment>
+
+	vec3 viewDir = normalize(cameraPosition - vWorldPosition);
+
+	vec4 diffuseColor = vec4( diffuse, opacity );
+	ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );
+	vec3 totalEmissiveRadiance = emissive;
+	#include <logdepthbuf_fragment>
+	#include <map_fragment>
+	#include <color_fragment>
+	#include <alphamap_fragment>
+	#include <alphatest_fragment>
+	#include <alphahash_fragment>
+	#include <specularmap_fragment>
+	#include <normal_fragment_begin>
+	#include <normal_fragment_maps>
+	#include <emissivemap_fragment>
+
+	// #include <lights_phong_fragment>
+  BlinnPhongMaterial material;
+  material.diffuseColor = diffuseColor.rgb;
+  material.specularColor = specular;
+  material.specularShininess = shininess;
+  material.specularStrength = specularStrength;
+
+	#include <lights_fragment_begin>
+	#include <lights_fragment_maps>
+	#include <lights_fragment_end>
+	#include <aomap_fragment>
+	vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;
+
+  // outgoingLight = normalize(vWorldNormal);
+	// outgoingLight = reflectedLight.directSpecular;
+
+	#include <envmap_fragment>
+	#include <opaque_fragment>
+	#include <tonemapping_fragment>
+	#include <colorspace_fragment>
+	// #include <fog_fragment>
+
+	gl_FragColor.xyz = CalculateFog(gl_FragColor.xyz, viewDir, vFogDepth);
+
+	#include <premultiplied_alpha_fragment>
+	#include <dithering_fragment>
+}

+ 44 - 0
shaders/phong-lighting-model-vsh.glsl

@@ -0,0 +1,44 @@
+#define PHONG
+varying vec3 vViewPosition;
+#include <common>
+#include <uv_pars_vertex>
+#include <displacementmap_pars_vertex>
+#include <envmap_pars_vertex>
+#include <color_pars_vertex>
+#include <fog_pars_vertex>
+#include <normal_pars_vertex>
+#include <morphtarget_pars_vertex>
+#include <skinning_pars_vertex>
+#include <shadowmap_pars_vertex>
+#include <logdepthbuf_pars_vertex>
+#include <clipping_planes_pars_vertex>
+
+varying vec3 vWorldNormal;
+varying vec3 vWorldPosition;
+
+void main() {
+	#include <uv_vertex>
+	#include <color_vertex>
+	#include <morphcolor_vertex>
+	#include <beginnormal_vertex>
+	#include <morphnormal_vertex>
+	#include <skinbase_vertex>
+	#include <skinnormal_vertex>
+	#include <defaultnormal_vertex>
+	#include <normal_vertex>
+	#include <begin_vertex>
+	#include <morphtarget_vertex>
+	#include <skinning_vertex>
+	#include <displacementmap_vertex>
+	#include <project_vertex>
+	#include <logdepthbuf_vertex>
+	#include <clipping_planes_vertex>
+	vViewPosition = - mvPosition.xyz;
+	#include <worldpos_vertex>
+	#include <envmap_vertex>
+	#include <shadowmap_vertex>
+	#include <fog_vertex>
+
+  vWorldNormal = (modelMatrix * vec4(normal.xyz, 0.0)).xyz;
+	vWorldPosition = (modelMatrix * vec4(transformed, 1.0)).xyz;
+}

+ 14 - 0
shaders/sky-lighting-model-fsh.glsl

@@ -0,0 +1,14 @@
+uniform float time;
+
+
+varying vec3 vWorldPosition;
+varying vec3 vWorldNormal;
+
+
+
+void main() {
+  vec3 viewDir = normalize(vWorldPosition - cameraPosition);
+  vec3 colour = CalculateSkyLighting(viewDir, vWorldNormal);
+
+  gl_FragColor = vec4(colour, 1.0);
+}

+ 15 - 0
shaders/sky-lighting-model-vsh.glsl

@@ -0,0 +1,15 @@
+varying vec3 vWorldPosition;
+varying vec3 vWorldNormal;
+varying vec2 vUv;
+
+
+void main() {
+  vec4 localSpacePosition = vec4(position, 1.0);
+  vec4 worldPosition = modelMatrix * localSpacePosition;
+
+  vWorldPosition = worldPosition.xyz;
+  vWorldNormal = normalize((modelMatrix * vec4(normal, 0.0)).xyz);
+  vUv = uv;
+
+  gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
+}

+ 54 - 0
shaders/sky.glsl

@@ -0,0 +1,54 @@
+
+vec3 SKY_lighterBlue = vec3(0.39, 0.57, 0.86) * 0.35;
+vec3 SKY_midBlue = vec3(0.1, 0.11, 0.1) * 0.5;
+vec3 SKY_darkerBlue = vec3(0.0);
+vec3 SKY_SUN_COLOUR = vec3(0.5);
+vec3 SKY_SUN_GLOW_COLOUR = vec3(0.15, 0.2, 0.25);
+vec3 SKY_FOG_GLOW_COLOUR = vec3(vec3(0.75, 0.75, 1.0) * 0.15);
+float SKY_POWER = 16.0;
+float SUN_POWER = 128.0;
+float SKY_DARK_POWER = 2.0;
+float SKY_fogScatterDensity = 0.0002;
+float SKY_fogExtinctionDensity = 0.006;
+vec3 SUN_DIR = vec3(-1.0, 0.45, 1.0);
+
+// This is just a bunch of nonsense since I didn't want to implement a full
+// sky model. It's just a simple gradient with a sun and some fog.
+vec3 CalculateSkyLighting(vec3 viewDir, vec3 normalDir) {
+  vec3 lighterBlue = col3(GAMMA_TO_LINEAR(SKY_lighterBlue));
+  vec3 midBlue = col3(GAMMA_TO_LINEAR(SKY_midBlue));
+  vec3 darkerBlue = col3(GAMMA_TO_LINEAR(SKY_darkerBlue));
+
+  vec3 SUN_COLOUR = col3(GAMMA_TO_LINEAR(SKY_SUN_COLOUR));
+  vec3 SUN_GLOW_COLOUR = col3(GAMMA_TO_LINEAR(SKY_SUN_GLOW_COLOUR));
+
+  float viewDirY = linearstep(-0.01, 1.0, viewDir.y);
+
+  float skyGradientMixFactor = saturate(viewDirY);
+  vec3 skyGradient = mix(darkerBlue, lighterBlue, exp(-sqrt(saturate(viewDirY)) * 2.0));
+
+  vec3 sunDir = normalize(SUN_DIR);
+  float mu = 1.0 - saturate(dot(viewDir, sunDir));
+
+  vec3 colour = skyGradient + SUN_GLOW_COLOUR * saturate(exp(-sqrt(mu) * 10.0)) * 0.75;
+  colour += SUN_COLOUR * smoothstep(0.9997, 0.9998, 1.0 - mu);
+
+  colour = oklabToRGB(colour);
+
+  return colour;
+}
+
+vec3 CalculateSkyFog(vec3 normalDir) {
+  return CalculateSkyLighting(normalDir, normalDir);
+}
+
+vec3 CalculateFog(vec3 baseColour, vec3 viewDir, float sceneDepth) {
+	vec3 fogSkyColour = CalculateSkyFog(-viewDir);
+	float fogDepth = sceneDepth * sceneDepth;
+
+	float fogScatterFactor = exp(-SKY_fogScatterDensity * SKY_fogScatterDensity * fogDepth);
+	float fogExtinctionFactor = exp(-SKY_fogExtinctionDensity * SKY_fogExtinctionDensity * fogDepth);
+
+	vec3 finalColour = baseColour * fogExtinctionFactor + fogSkyColour * (1.0 - fogScatterFactor);
+  return finalColour;
+}

+ 149 - 0
shaders/terrain-lighting-model-fsh.glsl

@@ -0,0 +1,149 @@
+#define STANDARD
+#ifdef PHYSICAL
+	#define IOR
+	#define USE_SPECULAR
+#endif
+uniform vec3 diffuse;
+uniform vec3 emissive;
+uniform float roughness;
+uniform float metalness;
+uniform float opacity;
+#ifdef IOR
+	uniform float ior;
+#endif
+#ifdef USE_SPECULAR
+	uniform float specularIntensity;
+	uniform vec3 specularColor;
+	#ifdef USE_SPECULAR_COLORMAP
+		uniform sampler2D specularColorMap;
+	#endif
+	#ifdef USE_SPECULAR_INTENSITYMAP
+		uniform sampler2D specularIntensityMap;
+	#endif
+#endif
+#ifdef USE_CLEARCOAT
+	uniform float clearcoat;
+	uniform float clearcoatRoughness;
+#endif
+#ifdef USE_IRIDESCENCE
+	uniform float iridescence;
+	uniform float iridescenceIOR;
+	uniform float iridescenceThicknessMinimum;
+	uniform float iridescenceThicknessMaximum;
+#endif
+#ifdef USE_SHEEN
+	uniform vec3 sheenColor;
+	uniform float sheenRoughness;
+	#ifdef USE_SHEEN_COLORMAP
+		uniform sampler2D sheenColorMap;
+	#endif
+	#ifdef USE_SHEEN_ROUGHNESSMAP
+		uniform sampler2D sheenRoughnessMap;
+	#endif
+#endif
+#ifdef USE_ANISOTROPY
+	uniform vec2 anisotropyVector;
+	#ifdef USE_ANISOTROPYMAP
+		uniform sampler2D anisotropyMap;
+	#endif
+#endif
+varying vec3 vViewPosition;
+#include <common>
+#include <packing>
+#include <dithering_pars_fragment>
+#include <color_pars_fragment>
+#include <uv_pars_fragment>
+#include <map_pars_fragment>
+#include <alphamap_pars_fragment>
+#include <alphatest_pars_fragment>
+#include <alphahash_pars_fragment>
+#include <aomap_pars_fragment>
+#include <lightmap_pars_fragment>
+#include <emissivemap_pars_fragment>
+#include <iridescence_fragment>
+#include <cube_uv_reflection_fragment>
+#include <envmap_common_pars_fragment>
+#include <envmap_physical_pars_fragment>
+#include <fog_pars_fragment>
+#include <lights_pars_begin>
+#include <normal_pars_fragment>
+#include <lights_physical_pars_fragment>
+#include <transmission_pars_fragment>
+#include <shadowmap_pars_fragment>
+#include <bumpmap_pars_fragment>
+#include <normalmap_pars_fragment>
+#include <clearcoat_pars_fragment>
+#include <iridescence_pars_fragment>
+#include <roughnessmap_pars_fragment>
+#include <metalnessmap_pars_fragment>
+#include <logdepthbuf_pars_fragment>
+#include <clipping_planes_pars_fragment>
+
+varying vec3 vWorldNormal;
+varying vec3 vWorldPosition;
+varying vec3 vTerrainColour;
+
+uniform sampler2D grid;
+
+
+void main() {
+	#include <clipping_planes_fragment>
+	
+  vec3 viewDir = normalize(cameraPosition - vWorldPosition);
+
+	vec4 diffuseColor = vec4( diffuse, opacity );
+	diffuseColor.rgb *= vTerrainColour;
+	float grid1 = texture(grid, vWorldPosition.xz * 0.1).r;
+	float grid2 = texture(grid, vWorldPosition.xz * 1.0).r;
+
+	float gridHash1 = hash12(floor(vWorldPosition.xz * 1.0));
+
+	vec3 gridColour = mix(vec3(0.5 + remap(gridHash1, 0.0, 1.0, -0.2, 0.2)), vec3(0.0625), grid2);
+	gridColour = mix(gridColour, vec3(0.0), grid1);
+
+	// diffuseColor.rgb = gridColour;
+
+	ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );
+	vec3 totalEmissiveRadiance = emissive;
+	#include <logdepthbuf_fragment>
+	#include <map_fragment>
+	#include <color_fragment>
+	#include <alphamap_fragment>
+	#include <alphatest_fragment>
+	#include <alphahash_fragment>
+	#include <roughnessmap_fragment>
+	#include <metalnessmap_fragment>
+	#include <normal_fragment_begin>
+	#include <normal_fragment_maps>
+	#include <clearcoat_normal_fragment_begin>
+	#include <clearcoat_normal_fragment_maps>
+	#include <emissivemap_fragment>
+	#include <lights_physical_fragment>
+	#include <lights_fragment_begin>
+	#include <lights_fragment_maps>
+	#include <lights_fragment_end>
+	#include <aomap_fragment>
+	vec3 totalDiffuse = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse;
+	vec3 totalSpecular = reflectedLight.directSpecular + reflectedLight.indirectSpecular;
+	#include <transmission_fragment>
+	vec3 outgoingLight = totalDiffuse + totalSpecular + totalEmissiveRadiance;
+	#ifdef USE_SHEEN
+		float sheenEnergyComp = 1.0 - 0.157 * max3( material.sheenColor );
+		outgoingLight = outgoingLight * sheenEnergyComp + sheenSpecular;
+	#endif
+	#ifdef USE_CLEARCOAT
+		float dotNVcc = saturate( dot( geometry.clearcoatNormal, geometry.viewDir ) );
+		vec3 Fcc = F_Schlick( material.clearcoatF0, material.clearcoatF90, dotNVcc );
+		outgoingLight = outgoingLight * ( 1.0 - material.clearcoat * Fcc ) + clearcoatSpecular * material.clearcoat;
+	#endif
+
+	#include <opaque_fragment>
+	#include <tonemapping_fragment>
+	#include <colorspace_fragment>
+	// #include <fog_fragment>
+
+	gl_FragColor.xyz = CalculateFog(gl_FragColor.xyz, viewDir, vFogDepth);
+
+	#include <premultiplied_alpha_fragment>
+	#include <dithering_fragment>
+}

+ 84 - 0
shaders/terrain-lighting-model-vsh.glsl

@@ -0,0 +1,84 @@
+#define STANDARD
+varying vec3 vViewPosition;
+#ifdef USE_TRANSMISSION
+	varying vec3 vWorldPosition;
+#endif
+#include <common>
+#include <uv_pars_vertex>
+#include <displacementmap_pars_vertex>
+#include <color_pars_vertex>
+#include <fog_pars_vertex>
+#include <normal_pars_vertex>
+#include <morphtarget_pars_vertex>
+#include <skinning_pars_vertex>
+#include <shadowmap_pars_vertex>
+#include <logdepthbuf_pars_vertex>
+#include <clipping_planes_pars_vertex>
+
+uniform sampler2D heightmap;
+uniform vec4 heightParams;
+
+varying vec3 vWorldNormal;
+varying vec3 vWorldPosition;
+varying vec3 vTerrainColour;
+
+
+void main() {
+	#include <uv_vertex>
+	#include <color_vertex>
+	#include <morphcolor_vertex>
+	#include <beginnormal_vertex>
+	#include <morphnormal_vertex>
+	#include <skinbase_vertex>
+	#include <skinnormal_vertex>
+	#include <defaultnormal_vertex>
+	#include <normal_vertex>
+	#include <begin_vertex>
+
+  vec4 heightSample = texture2D(heightmap, uv);
+  float height = heightSample.x * heightParams.z - heightParams.w;
+
+  vec3 terrainWorldPos = (modelMatrix * vec4(transformed, 1.0)).xyz;
+  float distToVertex = distance(cameraPosition, terrainWorldPos);
+
+  float isSandy = linearstep(-11.0, -14.0, height);
+
+  vec2 hashGrassColour = hash22(vec2(position.x, position.z));
+  // vec3 baseColour = mix(vec3(0.02, 0.2, 0.01), vec3(0.025, 0.1, 0.01), hashGrassColour.x);
+  // vec3 tipColour = mix(vec3(0.5, 0.7, 0.1), vec3(0.4, 0.5, 0.025), hashGrassColour.y);
+  // vec3 tipColour = vec3(0.2, 0.35, 0.05);
+  // vec3 baseColour = vec3(0.02, 0.2, 0.01);
+  // vec3 tipColour = vec3(0.5, 0.5, 0.1);
+
+  vec3 baseColour = GAMMA_TO_LINEAR(vec3(0.05, 0.2, 0.01));
+  vec3 tipColour = GAMMA_TO_LINEAR(vec3(0.3, 0.3, 0.1));
+
+  float aoDist = smoothstep(25.0, 50.0, distToVertex);
+  float colourDist = smoothstep(50.0, 100.0, distToVertex);
+  float ao = mix(0.125, 1.0, aoDist);
+  ao = mix(ao, 1.0, isSandy);
+
+  vec3 SAND_COLOUR = GAMMA_TO_LINEAR(vec3(0.6, 0.4, 0.2));
+
+  vTerrainColour = mix(baseColour, tipColour, colourDist);
+  vTerrainColour = mix(vTerrainColour, SAND_COLOUR, smoothstep(-11.0, -14.0, height));
+  vTerrainColour *= ao;
+
+
+	#include <morphtarget_vertex>
+	#include <skinning_vertex>
+	#include <displacementmap_vertex>
+	#include <project_vertex>
+	#include <logdepthbuf_vertex>
+	#include <clipping_planes_vertex>
+	vViewPosition = - mvPosition.xyz;
+	#include <worldpos_vertex>
+	#include <shadowmap_vertex>
+	#include <fog_vertex>
+#ifdef USE_TRANSMISSION
+	vWorldPosition = worldPosition.xyz;
+#endif
+
+  vWorldNormal = (modelMatrix * vec4(normal.xyz, 0.0)).xyz;
+	vWorldPosition = worldPosition.xyz;
+}

+ 162 - 0
shaders/water-lighting-model-fsh.glsl

@@ -0,0 +1,162 @@
+#define PHONG
+uniform vec3 diffuse;
+uniform vec3 emissive;
+uniform vec3 specular;
+uniform float shininess;
+uniform float opacity;
+#include <common>
+#include <packing>
+#include <dithering_pars_fragment>
+#include <color_pars_fragment>
+#include <uv_pars_fragment>
+#include <map_pars_fragment>
+#include <alphamap_pars_fragment>
+#include <alphatest_pars_fragment>
+#include <alphahash_pars_fragment>
+#include <aomap_pars_fragment>
+#include <lightmap_pars_fragment>
+#include <emissivemap_pars_fragment>
+#include <envmap_common_pars_fragment>
+#include <envmap_pars_fragment>
+#include <fog_pars_fragment>
+#include <bsdfs>
+#include <lights_pars_begin>
+#include <normal_pars_fragment>
+#include <lights_phong_pars_fragment>
+#include <shadowmap_pars_fragment>
+#include <bumpmap_pars_fragment>
+#include <normalmap_pars_fragment>
+#include <specularmap_pars_fragment>
+#include <logdepthbuf_pars_fragment>
+#include <clipping_planes_pars_fragment>
+
+uniform mat4 projectionMatrix;
+uniform mat4 inverseProjectionMatrix;
+
+uniform sampler2D colourTexture;
+uniform vec2 resolution;
+uniform float time;
+
+varying vec3 vWorldNormal;
+varying vec3 vWorldPos;
+
+vec2 ViewToScreen(vec3 pos) {
+	vec4 clipPos = projectionMatrix * vec4(pos, 1.0);
+	vec3 ndcPos = clipPos.xyz / clipPos.w;
+	return ndcPos.xy * 0.5 + 0.5;
+}
+
+vec3 ScreenToView(vec2 uv) {
+	vec2 ndcPos = uv * 2.0 - 1.0;
+	vec4 clipPos = vec4(ndcPos, 0.0, 1.0);
+	vec4 viewPos = inverse(projectionMatrix) * clipPos;
+	return vec3(viewPos.xy / viewPos.w, 1.0);
+}
+
+// TODO: This was lazily done to just get it working.
+// Do not use this for anything other than this demo.
+vec4 TraceRay(vec3 rayWorldOrigin, vec3 rayWorldDir) {
+	const int MAX_COUNT = 32;
+
+	vec3 rayViewPos = (viewMatrix * vec4(rayWorldOrigin, 1.0)).xyz;
+	vec3 rayViewDir = (viewMatrix * vec4(rayWorldDir, 0.0)).xyz;
+
+	vec3 rayPos = rayViewPos;
+	vec3 rayDir = rayViewDir;
+
+	float dist = 0.01;
+	for (int i = 0; i < MAX_COUNT; i++) {
+		rayPos += rayDir * dist;
+		dist *= 1.5;
+
+		vec2 coords = ViewToScreen(rayPos);
+		float depthAtCoord = texture(colourTexture, coords).w;
+		float rayDepth = -rayPos.z;
+
+		if (depthAtCoord < rayDepth) {
+			if (depthAtCoord < -rayViewPos.z) {
+				continue;
+			}
+			if (coords.y < 0.0 || coords.y > 1.0) {
+				break;
+			}
+			return vec4(texture(colourTexture, coords).xyz, 1.0);
+		}
+	}
+	return vec4(0.0);
+}
+
+vec3 WaterNormal2(vec3 pos, float falloff) {
+	vec3 noiseNormal = FBM_D_1_4(vec3(pos.xz * 0.4, time * 0.8), 1).yzw;
+
+	return normalize(vec3(0.0, 1.0, 0.0) + noiseNormal * 0.5 * falloff);
+}
+
+void main() {
+	#include <clipping_planes_fragment>
+	vec4 diffuseColor = vec4( diffuse, opacity );
+
+	ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );
+	vec3 totalEmissiveRadiance = emissive;
+	#include <logdepthbuf_fragment>
+	#include <map_fragment>
+	#include <color_fragment>
+	#include <alphamap_fragment>
+	#include <alphatest_fragment>
+	#include <alphahash_fragment>
+	#include <specularmap_fragment>
+	#include <normal_fragment_begin>
+	#include <normal_fragment_maps>
+	#include <emissivemap_fragment>
+
+	#include <lights_phong_fragment>
+
+	#include <lights_fragment_begin>
+	#include <lights_fragment_maps>
+	#include <lights_fragment_end>
+	#include <aomap_fragment>
+	vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;
+
+  vec2 coords = gl_FragCoord.xy / resolution;
+  float sceneZ = texture(colourTexture, coords).w;
+  float waterZ = vViewPosition.z;
+	float waterDepth = sceneZ - waterZ;
+  float waterFalloff = smoothstep(0.0, 2.0, waterDepth);
+
+	float dist = distance(cameraPosition, vWorldPos);
+	vec3 viewDir = normalize(cameraPosition - vWorldPos);
+	// vec3 waterNormal = WaterNormal(vWorldPos, sceneZ);
+
+	float waterNormalFalloff = pow(saturate(dot(vec3(0.0, 1.0, 0.0), viewDir)), 2.0);// * easeIn(linearstep(100.0, 0.0, dist), 3.0);
+	vec3 waterNormal = WaterNormal2(vWorldPos, waterNormalFalloff);
+
+
+	float fresnel = pow(saturate(dot(waterNormal, viewDir)), 1.0);
+
+	vec3 reflectedDir = reflect(-viewDir, waterNormal);
+	vec3 refractDir = refract(-viewDir, waterNormal, 1.0 / 1.33);
+
+	vec4 tracedReflection = TraceRay(vWorldPos, reflectedDir);
+	vec3 tracedSky = CalculateSkyLighting(reflectedDir, viewDir);
+	float edgeFalloff = smoothstep(0.5, 0.3, abs(coords.x - 0.5));
+	edgeFalloff = remap(edgeFalloff, 0.0, 1.0, 0.25, 1.0);
+	vec3 reflectedColour = mix(tracedSky, tracedReflection.xyz, tracedReflection.w * edgeFalloff);
+  vec4 colourSample = texture(colourTexture, coords + noise23(vec3(vWorldPos.xz, time)) * 0.05 * waterNormalFalloff);
+	// vec4 tracedRefraction = TraceRay(vWorldPos, refractDir);
+
+	vec3 waterColour = mix(colourSample.xyz, vec3(0.2, 0.2, 0.5), waterFalloff);
+	vec4 froth = vec4(vec3(1.0), remap(noise13(vec3(vWorldPos.xz * 10.0, time * 2.0)), -1.0, 1.0, 0.0, 1.0)) * smoothstep(0.25, 0.0, waterDepth);
+	waterColour = mix(waterColour, froth.xyz, froth.w);
+
+  outgoingLight = mix(reflectedColour, waterColour, fresnel);
+	outgoingLight = mix(colourSample.xyz, outgoingLight, smoothstep(0.0, 0.1, waterDepth));
+
+
+	#include <envmap_fragment>
+	#include <opaque_fragment>
+	#include <tonemapping_fragment>
+	#include <colorspace_fragment>
+	#include <fog_fragment>
+	#include <premultiplied_alpha_fragment>
+	#include <dithering_fragment>
+}

+ 46 - 0
shaders/water-lighting-model-vsh.glsl

@@ -0,0 +1,46 @@
+#define PHONG
+varying vec3 vViewPosition;
+#include <common>
+#include <uv_pars_vertex>
+#include <displacementmap_pars_vertex>
+#include <envmap_pars_vertex>
+#include <color_pars_vertex>
+#include <fog_pars_vertex>
+#include <normal_pars_vertex>
+#include <morphtarget_pars_vertex>
+#include <skinning_pars_vertex>
+#include <shadowmap_pars_vertex>
+#include <logdepthbuf_pars_vertex>
+#include <clipping_planes_pars_vertex>
+
+varying vec3 vWorldNormal;
+varying vec3 vWorldPos;
+
+void main() {
+	#include <uv_vertex>
+	#include <color_vertex>
+	#include <morphcolor_vertex>
+	#include <beginnormal_vertex>
+
+	#include <morphnormal_vertex>
+	#include <skinbase_vertex>
+	#include <skinnormal_vertex>
+	#include <defaultnormal_vertex>
+	#include <normal_vertex>
+	#include <begin_vertex>
+
+	#include <morphtarget_vertex>
+	#include <skinning_vertex>
+	#include <displacementmap_vertex>
+	#include <project_vertex>
+	#include <logdepthbuf_vertex>
+	#include <clipping_planes_vertex>
+	vViewPosition = - mvPosition.xyz;
+	#include <worldpos_vertex>
+	#include <envmap_vertex>
+	#include <shadowmap_vertex>
+	#include <fog_vertex>
+
+	vWorldNormal = (modelMatrix * vec4(normal, 0.0)).xyz;
+	vWorldPos = (modelMatrix * vec4(transformed, 1.0)).xyz;
+}

+ 26 - 0
shaders/water-texture-fsh.glsl

@@ -0,0 +1,26 @@
+#include <common>
+#include <packing>
+
+uniform sampler2D colourTexture;
+uniform sampler2D depthTexture;
+uniform vec3 nearFar;
+
+varying vec2 vUvs;
+
+float GetDepth(float depthSample) {
+  float nf = nearFar.x;
+  float f_sub_n = nearFar.y;
+  float f = nearFar.z;
+
+  float z_final = depthSample;
+  return nf / (f_sub_n * z_final - f);
+}
+
+void main() {
+  vec4 colourSample = texture(colourTexture, vUvs);
+  float depthSample = texture(depthTexture, vUvs).r;
+
+  depthSample = -GetDepth(depthSample);
+
+  gl_FragColor = vec4(colourSample.xyz, depthSample);
+}

+ 12 - 0
shaders/water-texture-vsh.glsl

@@ -0,0 +1,12 @@
+
+varying vec2 vUvs;
+
+
+void main() {
+  vec4 localSpacePosition = vec4(position, 1.0);
+  vec4 worldPosition = modelMatrix * localSpacePosition;
+
+  vUvs = uv;
+
+  gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
+}

+ 21 - 0
shaders/wind-lighting-model-fsh.glsl

@@ -0,0 +1,21 @@
+#define PHONG
+uniform vec3 diffuse;
+uniform vec3 emissive;
+uniform vec3 specular;
+uniform float shininess;
+uniform float opacity;
+
+
+varying vec2 vUVs;
+varying float vWindParams;
+
+uniform sampler2D diffuseTexture;
+
+void main() {
+	vec4 colour = texture(diffuseTexture, vUVs).xyzx;
+
+	colour.xyz *= vec3(0.5);
+	colour.w *= vWindParams;
+
+	gl_FragColor = colour;
+}

+ 81 - 0
shaders/wind-lighting-model-vsh.glsl

@@ -0,0 +1,81 @@
+
+
+#define PHONG
+
+
+varying vec2 vUVs;
+varying float vWindParams;
+
+uniform vec2 dustSize;
+uniform float time;
+
+uniform sampler2D heightmap;
+uniform vec3 heightmapParams;
+
+attribute vec3 offset;
+
+
+const float PI = 3.1415926535897932384626433832795;
+
+void main() {
+
+vec3 transformed = vec3( position );
+#ifdef USE_ALPHAHASH
+	vPosition = vec3( position );
+#endif
+
+  {
+    vec3 baseWorldPosition = (modelMatrix * vec4(0.0, 0.0, 0.0, 1.0)).xyz + offset;
+    float hashSample = hash12(baseWorldPosition.xz);
+
+    float hashedTime = time + hashSample * 100.0;
+
+    float windDir = noise12(baseWorldPosition.xz * 0.05 + 0.5 * time);
+    // float windNoiseSample = noise12(grassBladeWorldPos.xz * 0.25 + time * 1.1);
+    // float windLeanAngle = saturate(remap(windNoiseSample, -1.0, 1.0, 0.25, 1.0));
+    // windLeanAngle = easeIn(windLeanAngle, 2.0) * 1.5;
+    vec3 windAxis = vec3(sin(windDir), 0.0, -cos(windDir));
+
+    const float TIME_REPEAT_PERIOD = 4.0;
+    float repeatingTime = mod(hashedTime, TIME_REPEAT_PERIOD);
+    float fadeInOut = (
+        smoothstep(0.0, TIME_REPEAT_PERIOD * 0.25, repeatingTime) *
+        smoothstep(TIME_REPEAT_PERIOD, TIME_REPEAT_PERIOD * 0.75, repeatingTime));
+
+    vec3 windOffset = offset + windAxis * repeatingTime * 5.0;
+
+    vec3 scaledPosition = position;
+    scaledPosition.xy *= dustSize;
+
+    vec3 scaledOffsetPosition = scaledPosition + windOffset;
+
+    vec3 worldPosition = (modelMatrix * vec4(scaledOffsetPosition, 1.0)).xyz;
+
+    vec3 z = normalize(cameraPosition - worldPosition);
+    vec3 x = normalize(cross(vec3(0.0, 1.0, 0.0), z));
+    vec3 y = normalize(cross(z, x));
+    mat3 alignMatrix = mat3(x, y, z);
+    transformed = alignMatrix * scaledPosition + windOffset;
+
+    vec2 heightmapUV = vec2(
+        remap(worldPosition.x, -heightmapParams.z * 0.5, heightmapParams.z * 0.5, 0.0, 1.0),
+        remap(worldPosition.z, -heightmapParams.z * 0.5, heightmapParams.z * 0.5, 1.0, 0.0));
+    float terrainHeight = texture2D(heightmap, heightmapUV).x * heightmapParams.x - heightmapParams.y;
+    transformed.y += terrainHeight;
+
+    vWindParams = fadeInOut;
+
+    float randomAngle = remap(hashSample, 0.0, 1.0, 0.0, 2.0 * PI);
+    vUVs = rotate2D(randomAngle) * uv;
+
+    // vec3 worldCenter = (modelMatrix * vec4(0.0, 0.0, 0.0, 1.0)).xyz + windOffset;
+    // vec3 viewCenter = normalize(worldCenter - cameraPosition);
+    // vec3 viewXZ = -normalize(vec3(viewCenter.x, 0.0, viewCenter.z));
+
+    // float i = floor(16.0 * (atan(viewXZ.z, viewXZ.x) + PI) / (2.0 * PI));
+    // float j = floor(16.0 * offset.w / (2.0 * PI));
+    // vBillboardLayer = vec2(i * 16.0 + j, smoothstep(350.0, 300.0, dist));
+  }
+
+  gl_Position = projectionMatrix * modelViewMatrix * vec4(transformed, 1.0);
+}

BIN
textures/butterfly.png


BIN
textures/dust.png


BIN
textures/grass.png


BIN
textures/grid.png


BIN
textures/moth.png


BIN
textures/terrain.png


BIN
textures/whitesquare.png


Some files were not shown because too many files changed in this diff