[EDIT:请参阅此jsfiddle以获取实时示例和附带代码]
使用three.js,我试图渲染出一些具有突出特征的天体。
不幸的是,没有提供关于如何使用threejs应用球面高度图的示例,但他们确实有一个将高度图应用于平面的示例。
我举了这个例子,并将其修改为使用SphereGeometry();
而不是PlaneGeometry();
显然,球体的几何体与平面的几何体有很大不同,当渲染结果时,球体显示为一块平坦的纹理。
飞机的高度图代码:
var plane = new THREE.PlaneGeometry( 2000, 2000, quality - 1, quality - 1 );
plane.applyMatrix( new THREE.Matrix4().makeRotationX( - Math.PI / 2 ) );
for ( var i = 0, l = plane.vertices.length; i < l; i ++ ) {
var x = i % quality, y = ~~ ( i / quality );
plane.vertices[ i ].y = data[ ( x * step ) + ( y * step ) * 1024 ] * 2 - 128;
}
现在我猜解决方案相对简单:它必须在三维空间中找到球体的表面坐标,而不是在for循环中映射到平面的二维坐标。不幸的是,我并不是一个真正的三维数学专家,所以我在这一点上几乎陷入了困境。
应用于球体的heightmap示例和所有代码都放在这个jsfiddle中。更新后的jsfiddle显示了一个更改后的球体,但使用了随机数据而不是高度图数据。
我知道你可以扭曲球体的三维点来生成这些表面细节,但我想使用高度贴图。这个JSFiddle是我所得到的——它会随机改变点,给球体一个岩石的外观,但显然看起来不是很自然。
编辑:以下是我希望实现的将高度贴图数据映射到球体所需的逻辑。
为了将数据映射到球体,我们需要将坐标从简单的球面坐标系(经度φ、纬度θ、半径r)映射到笛卡尔坐标系(x,y,z)。正如在法线高度映射中,(x,y)处的数据值映射到z,我们将(φ,θ)处的值映射到r。这种转换可以归结为:
x = r × cos φ × sin θ
y = r × sin φ × sin θ
z = r × cos θ
r = Rdefault + Rscale × d(φ, θ)
参数Rdefault和Rscale可用于控制球体的大小及其上的高度图。
使用vector3移动每个顶点:
var vector = new THREE.Vector3()
vector.set(geometry.vertices[i].x, geometry.vertices[i].y, geometry.vertices[i].z);
vector.setLength(h);
geometry.vertices[i].x = vector.x;
geometry.vertices[i].y = vector.y;
geometry.vertices[i].z = vector.z;
示例:http://jsfiddle.net/damienlabat/b3or4up3/
如果要将2D贴图应用到3D球体曲面上,则需要使用球体的UV。幸运的是,默认情况下UV附带THREE.SphereGeometry
。
不过,UV是按面存储的,因此需要遍历faces
阵列。
对于几何图形中的每个面:
- 读取
FaceVertexUvs
阵列中每个关联顶点的相应UV值 - 使用该UV位置读取高度贴图值
- 将顶点沿顶点法线移动该值。
faces
数组提供顶点索引,您可以使用该索引到vertices
数组中以获取/设置顶点位置
完成所有操作后,将verticesNeedUpdate
设置为true
以更新顶点。