第 12 课:Grass - Projecting into Flattening Map
实现
uniform float iTime;
uniform sampler2D iChannel0;
uniform sampler2D iChannel1;
uniform vec2 iResolution;
attribute int index;
out float vH;
out vec3 vNormal;
out float vX;
out vec3 vColor;
out vec2 uvByNdc;
vec3 bezier3D(vec3 p0, vec3 p1, vec3 p2, float t) {
float u = 1.0 - t;
float tt = t * t;
float uu = u * u;
vec3 p = uu * p0;
p += 2.0 * u * t * p1;
p += tt * p2;
return p;
}
vec2 random2(vec2 st){
float d1 = dot(st, vec2(12.3, 32.1));
float d2 = dot(st, vec2(45.6, 65.4));
st = vec2(d1, d2);
return fract(sin(st) * 78.9) * 2.0 - 1.0;
}
float random(float x) {
float r = fract(sin(x * 12.34) * 1234.5678);
return r * 2.0 - 1.0;
}
mat3 rotationYMatrix(float angle) {
float cosAngle = cos(angle);
float sinAngle = sin(angle);
return mat3(
vec3(cosAngle, 0, -sinAngle),
vec3(0, 1, 0),
vec3(sinAngle, 0, cosAngle)
);
}
mat3 rotationXMatrix(float angle) {
float cosAngle = cos(angle);
float sinAngle = sin(angle);
return mat3(
1.0, 0, 0,
0, cosAngle, sinAngle,
0, -sinAngle, cosAngle
);
}
float noise(vec3 st) {
vec2 offset = vec2(st.z, 0.0);
return texture(iChannel0, fract(st.xy + offset)).r * 2.0 - 1.0;
}
mat4 getOrhtoProjection() {
// Apply the ratio for visual demo.
// Before generating the map you need to remove it.
float ratio = iResolution.x / iResolution.y;
float size = 3.5;
float left = -size * ratio;
float right = size * ratio;
float top = size;
float bottom = -size;
float far = 8.0;
float near = 0.1;
mat4 projection;
projection[0][0] = 2.0 / (right - left);
projection[1][0] = 0.0;
projection[2][0] = 0.0;
projection[3][0] = -(right + left) / (right - left);
projection[0][1] = 0.0;
projection[1][1] = 2.0 / (top - bottom);
projection[2][1] = 0.0;
projection[3][1] = -(top + bottom) / (top - bottom);
projection[0][2] = 0.0;
projection[1][2] = 0.0;
projection[2][2] = -2.0 / (far - near);
projection[3][2] = -(far + near) / (far - near);
projection[0][3] = 0.0;
projection[1][3] = 0.0;
projection[2][3] = 0.0;
projection[3][3] = 1.0;
return projection;
}
mat4 getOrthoView() {
vec3 viewPos = vec3(0.0, 5.0, 0.0);
vec3 front = vec3(0.0, 1.0, 0.0);
vec3 up = vec3(0.0, 0.0, -1.0);
vec3 right = normalize(cross(up, front));
vec3 fixedUp = normalize(cross(front, right));
// column major
mat4 view;
// row 0 = dot(right, vertex_pos)
view[0][0] = right.x;
view[1][0] = right.y;
view[2][0] = right.z;
view[3][0] = -dot(viewPos, right);
// row 1 = dot(fixedUp, vertex_pos)
view[0][1] = fixedUp.x;
view[1][1] = fixedUp.y;
view[2][1] = fixedUp.z;
view[3][1] = -dot(viewPos, fixedUp);
// row 2 = dot(-front, vertex_pos)
view[0][2] = front.x;
view[1][2] = front.y;
view[2][2] = front.z;
view[3][2] = -dot(viewPos, front);
//row 3
view[0][3] = 0.0;
view[1][3] = 0.0;
view[2][3] = 0.0;
view[3][3] = 1.0;
return view;
}
void main() {
int instance = index / 40;
float instanceHash = random(float(instance));
int localIndex = index % 20;
float h = float(localIndex / 2) / 9.0;
float sideX = mod(float(localIndex), 2.0) * 2.0 - 1.0;
float bend = sin(iTime) * 0.2;
vec2 worldPos = random2(vec2(instance)) * 3.0;
mat3 rotateY = rotationYMatrix(instanceHash * 3.14);
// FIX IT:
vec4 clipPosFlatteningMap = getOrhtoProjection()
* getOrthoView()
* vec4(worldPos.x, 0.0, worldPos.y, 1.0);
vec2 uvFlatteningMap = clipPosFlatteningMap.xy * 0.5 + 0.5;
vColor = vec3(uvFlatteningMap, 0.0);
float windStrength = noise(vec3(worldPos * 0.05, 0.0) + iTime * 0.1) * h * 0.2;
mat3 windRot = rotationXMatrix(windStrength);
vec3 curve = bezier3D(
vec3(0.0, 0.0, 0.0),
vec3(0.0, 0.5, 0.0),
vec3(0.0, cos(bend), sin(bend)),
h
);
vec3 pos = curve;
pos.x += sideX * mix(0.05, 0.0, h * h);
pos = windRot * rotateY * pos;
pos += vec3(worldPos.x, 0.0, worldPos.y);
vH = h;
vX = sideX;
gl_Position = getOrhtoProjection() * getOrthoView() * vec4(pos, 1.0);
}