webGPU高效渲染任意形状草地
书接上回《webGPU实现游戏中的绿植和随风摆动效果》,今天我们来看一看如何实现3D游戏中常见的草地效果,并且让这些草可以按照我们的需要形成任意的形状,甚至可以根据地形的起伏来生成。
生成大量的草地
要生成大量的草地又要考虑渲染性能,首先想到的是用instanceMesh来实现,网上也有一些通过该方法实现的教程,但比instanceMesh更高效的方法是只用一个Mesh来实现。

我们使用BufferGeometry来生成大量的三角形顶点来模拟草叶,先随机生成三角形的中心点,然后通过中心点找该三角形的三个顶点。之所以需要中心点的位置,是因为方便我们后面在TSL里旋转该三角形,同时也方便我们生成任意形状的草地,后面你会看到这样做的好处。
const positions = new Float32Array(count * 3 * 3);
const centers = new Float32Array(count * 3 * 2);
for (let i = 0; i < count; i++) {
const bw = bladeW + bladeW * randFloat(0, bladeWRandomness);
const bh = bladeH + bladeH * randFloat(0, bladeHRandomness);
const bfw = bw * 0.5;
positions[stride9 + 0] = -bfw;
positions[stride9 + 1] = 0;
positions[stride9 + 2] = 0;
positions[stride9 + 3] = 0;
positions[stride9 + 4] = bh;
positions[stride9 + 5] = 0;
positions[stride9 + 6] = bfw;
positions[stride9 + 7] = 0;
positions[stride9 + 8] = 0;
const maxRadius = randFloat(tileRadius, tileRadius + randFloat(0, 1));
const centerX = randFloatSpread(maxRadius);
const centerZ = randFloatSpread(maxRadius);
centers[stride6 + 0] = centerX;
centers[stride6 + 1] = centerZ;
centers[stride6 + 2] = centerX;
centers[stride6 + 3] = centerZ;
centers[stride6 + 4] = centerX;
centers[stride6 + 5] = centerZ;
}
this.geometry = new BufferGeometry();
this.geometry.setAttribute("position", new Float32BufferAttribute(positions, 3));
this.geometry.setAttribute("center", new Float32BufferAttribute(centers, 2));

生成任意形状的草地
首先在photoshop中用纯绿色画出你需要的草地形状图形,这里的颜色可以RGB三色中的任意一种,也可以是alpha透明通道。

原理也很简单,首先将草叶顶点的世界坐标转换到这张贴图中的uv坐标,然后根据贴图中的绿色通道的值来移动草叶的位置。
const x = linearstep(-25, 25, center.x);
const y = linearstep(-25, 25, center.y).oneMinus();
const grassTex = texture(this.grassTexture, vec2(x, y));
If(grassTex.g.lessThan(0.1), () => {
newPos.y.assign(999);
});
