我正在尝试生成一些矩阵,以便在GPU上的行星上放置树。每棵树的位置都是预先确定的——基于生物群落图和各种高度图数据——但这些数据是GPU驻留的,所以我不能在CPU上完成这项工作。目前,我正在使用几何着色器实例化-如果性能不好,这将改为传统的实例化,然后我会在计算着色器上计算每棵树的模型矩阵。
我甚至试图使用lookAt((的修改版本,但我无法使其工作,即使我这样做了,树也会垂直于地球,而不是直立的。我知道我可以用3轴来定义一个,所以球体的法线,一个切线和一个双切,但如果我不在乎这些切线和双切现在在哪个方向,在GLSL中计算这个矩阵的快速方法是什么?谢谢
void drawInstance(vec3 offset)
{
//Grab the model's position from the model matrix
vec3 modelPos = vec3(modelMatrix[3][0],modelMatrix[3][1],modelMatrix[3][2]);
//Add the offset
modelPos +=offset;
//Eye = where the new pos is, look in x direction for now, planet is at origin so up is just the modelPos normalized
mat4 m = lookAt(modelPos, modelPos + vec3(1,0,0), normalize(modelPos));
//Lookat is intended as a camera matrix, fix this
m = inverse(m);
vec3 pos = gl_in[0].gl_Position.xyz;
gl_Position = vp * m *vec4(pos, 1.0);
EmitVertex();
pos = gl_in[1].gl_Position.xyz ;
gl_Position = vp * m *vec4(pos, 1.0);
EmitVertex();
pos = gl_in[2].gl_Position.xyz;
gl_Position = vp * m * vec4(pos, 1.0);
EmitVertex();
EndPrimitive();
}
void main()
{
vp = proj * view;
mvp = proj * view * modelMatrix;
drawInstance(vec3(0,20,0));
// drawInstance(vec3(0,20,0));
// drawInstance(vec3(0,20,-40));
// drawInstance(vec3(40,40,0));
// drawInstance(vec3(-40,0,0));
}
我建议采取完全不同的方法。
首先,不要使用几何体着色器来复制几何体。这就是glDrawArraysInstanced
的作用。
其次,很难从程序上定义这样一个矩阵。这与毛球定理有关。
相反,我会在CPU上生成一堆随机旋转。使用此方法可以创建均匀分布的四元数。将该四元数作为单个vec4
实例化属性传递到顶点着色器。在顶点着色器中:
- 将树顶点偏移
(0, 0, radiusOfThePlanet)
,使其位于北极(假设Z轴向上( - 应用四元数旋转(它将围绕行星中心旋转,使树保持在曲面上(
- 像往常一样应用行星模型视图和相机投影矩阵
这将产生一个无偏的均匀分布随机树集。
找到了一个问题的解决方案,可以将对象放置在面向正确方向的球体表面上。这是代码:
mat4 m = mat4(1);
vec3 worldPos = getWorldPoint(sphericalCoords);
//Add a random number to the world pos, then normalize it so that it is a point on a unit sphere slightly different to the world pos. The vector between them is a tangent. Change this value to rotate the object once placed on the sphere
vec3 xAxis = normalize(normalize(worldPos + vec3(0.0,0.2,0.0)) - normalize(worldPos));
//Planet is at 0,0,0 so world pos can be used as the normal, and therefore the y axis
vec3 yAxis = normalize(worldPos);
//We can cross the y and x axis to generate a bitangent to use as the z axis
vec3 zAxis = normalize(cross(yAxis, xAxis));
//This is our rotation matrix!
mat3 baseMat = mat3(xAxis, yAxis, zAxis);
//Fill this into our 4x4 matrix
m = mat4(baseMat);
//Transform m by the Radius in the y axis to put it on the surface
mat4 m2 = transformMatrix(mat4(1), vec3(0,radius,0));
m = m * m2;
//Multiply by the MVP to project correctly
m = mvp* m;
//Draw an instance of your object
drawInstance(m);