Skip to content

Commit

Permalink
wind + basic LOD
Browse files Browse the repository at this point in the history
  • Loading branch information
BarthPaleologue committed Nov 6, 2023
1 parent c9671c5 commit 2453022
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 21 deletions.
21 changes: 16 additions & 5 deletions src/shaders/grassVertex.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,14 @@ float easeOut(float t, float a) {
return 1.0 - pow(1.0 - t, a);
}

float easeIn(float t, float alpha) {
return pow(t, alpha);
}

#pragma glslify: perlin3 = require(./perlin3.glsl)

#pragma glslify: remap = require(./remap.glsl)

#include<instancesDeclaration>

void main() {
Expand All @@ -40,16 +46,21 @@ void main() {

// wind
vec3 objectWorld = (finalWorld * vec4(0.0, 0.0, 0.0, 1.0)).xyz;
float windStrength = (perlin3(objectWorld * 0.35 + time) - 0.5) * 2.0;
float windStrength = perlin3(objectWorld * 0.35 + time);
float windDir = perlin3(objectWorld * 0.05 + 0.05 * time) * 2.0 * 3.14;

float windLeanAngle = remap(windStrength, 0.0, 1.0, 0.25, 1.0);
windLeanAngle = easeIn(windLeanAngle, 2.0) * 1.25;

// curved grass blade
float leanAmount = 0.3;
float curveAmount = leanAmount * position.y + windStrength * 0.1;
vec3 leaningPosition = rotateAround(position, vec3(1.0, 0.0, 0.0), curveAmount);
float curveAmount = leanAmount * position.y + windLeanAngle;
vec3 leanAxis = rotateAround(vec3(1.0, 0.0, 0.0), vec3(0.0, 1.0, 0.0), windDir);
vec3 leaningPosition = rotateAround(position, leanAxis, curveAmount);

//vec3 leaningNormal = rotateAround(normal, vec3(1.0, 0.0, 0.0), curveAmount);
vec3 leaningNormal1 = rotateAround(curvyNormal1, vec3(1.0, 0.0, 0.0), curveAmount);
vec3 leaningNormal2 = rotateAround(curvyNormal2, vec3(1.0, 0.0, 0.0), curveAmount);
vec3 leaningNormal1 = rotateAround(curvyNormal1, leanAxis, curveAmount);
vec3 leaningNormal2 = rotateAround(curvyNormal2, leanAxis, curveAmount);

vec3 worldPosition = (finalWorld * vec4(leaningPosition, 1.0)).xyz;

Expand Down
6 changes: 6 additions & 0 deletions src/shaders/remap.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// remap a value comprised between low1 and high1 to a value between low2 and high2
float remap(float value, float low1, float high1, float low2, float high2) {
return low2 + (value - low1) * (high2 - low2) / (high1 - low1);
}

#pragma glslify: export(remap)
34 changes: 18 additions & 16 deletions src/ts/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {makeGrassBlade} from "./grassBlade";
import { StandardMaterial } from "@babylonjs/core/Materials/standardMaterial";
import {ArcRotateCamera, DirectionalLight} from "@babylonjs/core";
import {makeGrassMaterial} from "./grassMaterial";
import {makeInstancePatch} from "./instancePatch";

//import postprocessCode from "../shaders/smallPostProcess.glsl";

Expand All @@ -39,28 +40,29 @@ groundMaterial.diffuseColor.copyFromFloats(0.5, 0.5, 0.5);

ground.material = groundMaterial;

const grassBlade = makeGrassBlade(scene, 5);
grassBlade.isVisible = false;
const highQualityGrassBlade = makeGrassBlade(scene, 4);
highQualityGrassBlade.isVisible = false;

const lowQualityGrassBlade = makeGrassBlade(scene, 2);
lowQualityGrassBlade.isVisible = false;

const material = makeGrassMaterial(scene);
material.setVector3("lightDirection", light.direction);
grassBlade.material = material;
highQualityGrassBlade.material = material;
lowQualityGrassBlade.material = material;

const grassBlades = [];
const patchSize = 10;
const patchResolution = 50;
const cellSize = patchSize / patchResolution;
const patchPosition = new Vector3(0, 0, 0);

for(let x = 0; x < patchResolution; x++) {
for(let z = 0; z < patchResolution; z++) {
const blade = grassBlade.createInstance(`blade${x}${z}`);
const randomCellPositionX = Math.random() * cellSize;
const randomCellPositionZ = Math.random() * cellSize;
blade.position.x = patchPosition.x + (x / patchResolution) * patchSize - patchSize / 2 + randomCellPositionX;
blade.position.z = patchPosition.z + (z / patchResolution) * patchSize - patchSize / 2 + randomCellPositionZ;
blade.rotation.y = Math.random() * 2 * Math.PI;
grassBlades.push(blade);
const fieldPosition = new Vector3(0, 0, 0);
const fieldRadius = 4;

for(let x = -fieldRadius; x < fieldRadius; x++) {
for(let z = -fieldRadius; z < fieldRadius; z++) {
const radiusSquared = x * x + z * z;
if(radiusSquared > fieldRadius * fieldRadius) continue;
const patchPosition = new Vector3(x * patchSize, 0, z * patchSize).addInPlace(fieldPosition);
const grassBlade = radiusSquared < 2 * 2 ? highQualityGrassBlade : lowQualityGrassBlade;
makeInstancePatch(grassBlade, patchPosition, patchSize, patchResolution);
}
}

Expand Down
16 changes: 16 additions & 0 deletions src/ts/instancePatch.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import {Vector3} from "@babylonjs/core/Maths/math.vector";
import {Mesh} from "@babylonjs/core/Meshes/mesh";

export function makeInstancePatch(instance: Mesh, patchPosition: Vector3, patchSize: number, patchResolution: number) {
const cellSize = patchSize / patchResolution;
for(let x = 0; x < patchResolution; x++) {
for(let z = 0; z < patchResolution; z++) {
const blade = instance.createInstance(`blade${x}${z}`);
const randomCellPositionX = Math.random() * cellSize;
const randomCellPositionZ = Math.random() * cellSize;
blade.position.x = patchPosition.x + (x / patchResolution) * patchSize - patchSize / 2 + randomCellPositionX;
blade.position.z = patchPosition.z + (z / patchResolution) * patchSize - patchSize / 2 + randomCellPositionZ;
blade.rotation.y = Math.random() * 2 * Math.PI;
}
}
}

0 comments on commit 2453022

Please sign in to comment.