4
votes

[EDIT: see this jsfiddle for a live example plus accompanying code]

Using three.js I'm trying to render out some celestial bodies with prominent features.

Unfortunately no examples are provided on how to apply spherical heightmaps with threejs but they do have an example where a heightmap is applied to a plane.

I took said example and modified it to use a SphereGeometry(); instead of a PlaneGeometry();

Obviously the geometry of a sphere is critically different from that of a plane, and when rendering out the results the sphere shows as a flat piece of texture.

The heightmap code for planes:

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;
}

Now I'm guessing the solution is relatively simple: instead of mapping to the plane's 2d coordinate in the for loop, it has to find the surface coordinate of the sphere in 3d space. Unfortunately I'm not really a pro at 3d maths so I'm pretty much stuck at this point.

An example of the heightmap applied to the sphere and all code is put together in this jsfiddle. An updated jsfiddle shows an altered sphere but with random data instead of the height map data.

I know for a fact you can distort the sphere's 3d points to generate these surface details, but I'd like to do so using a heightmap. This JSFiddle is as far as I got- it'll randomly alter points to give a rocky appearance to the sphere, but obviously doesnt look very natural.

EDIT: The following is the logic required I wish to implement that maps heightmap data to a sphere.

In order to map the data to a sphere, we will need to map coordinates from a simple spherical coordinate system (longitude φ, latitude θ, radius r) to Cartesian coordinates (x, y, z). Just as in normal height-mapping the data value at (x, y) is mapped to z, we will map the value at (φ, θ) to r. This transformation comes down to:

x = r × cos φ × sin θ

y = r × sin φ × sin θ

z = r × cos θ

r = Rdefault + Rscale × d(φ, θ) 

The parameters Rdefault and Rscale can be used to control the size of the sphere and the height map on it.

2
FYI, you can create inline code spans by surrounding the code with backticks. That way you don't need a separate line just for the name of a single function.Adi Inbar
Can you show your live example, and then ask a specific question?WestLangley

2 Answers

1
votes

Uses vector3 to move each vertices:

  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;

Example: http://jsfiddle.net/damienlabat/b3or4up3/

0
votes

If you want to apply a 2D map onto the 3D sphere surface, you will need to use UVs of the sphere. Fortunately, UVs come with THREE.SphereGeometry by default.

The UVs are stored per-face though, so you will need to iterate through the faces array.

For each face in the geometry:

  • Read the corresponding UV value in the FaceVertexUvs array for each associated vertex.
  • Read the height map value using that UV location.
  • Shift the vertex along the vertex normal by that value. The faces array gives the vertex index, which you can use to index into the vertices array to get/set the vertex position.

After this is all done, set verticesNeedUpdate to true to update the vertices.