Why does my implementation of a displacement map in Three.js disconnect vertices at the poles of a sphere?

StackOverflow https://stackoverflow.com/questions/15876848

  •  02-04-2022
  •  | 
  •  

Question

I am trying to create an asteroid by applying a displacement map with perlin noise to a sphere. Everything works as expected except that the poles of the sphere are distorted. It looks like as if the vertices on the poles are disconnected.

Frontview: looks as expected Asteroid frontview Topview: looks ugly ;-) Asteroid topview

At first, I thought this has something to do with my displacement map and the fact, that I am applying it on a spherical surface, but if I apply it on a cube there are also gaps between the faces.

I'm not sure, what I could do to close those gaps. In a later step, the displacement map should be generically generated by rendering to a texture and using random seeds for the noise, therefore I can't use external programs like Blender or Photoshop to modify the displacement map. Have I done something wrong in the shader, or is this a "normal" behaviour? Can I do anything to avoid that? I read about cubemaps. Could this probably be a solution? And if so, is there a working example for Three.js r57 or higher out there?

Here is my Shadercode:

 vertexShader: [
    'uniform sampler2D displacementMap;',
    'varying vec3 vColor;',

    'void main() {',
        'vec4 newVertexPos;',
        'vec4 dv;',
        'float df;',

        'dv = texture2D( displacementMap, uv.xy );',
        'df = 0.30*dv.x + 0.59*dv.y + 0.11*dv.z;',
        '//newVertexPos = vec4(normal * df * 1.0, 0.0) + vec4( position, 1.0 );',
        'newVertexPos = vec4( normalize( position ) * df * 1.0 ) + vec4( position, 1.0 );', 
        'vColor = vec3( dv.x, dv.y, dv.z );',

        'gl_Position = projectionMatrix * modelViewMatrix * newVertexPos;',
    '}'

].join( "\n" ),

fragmentShader: [
    'varying vec3 vColor;',

    'void main() {',
        'gl_FragColor = vec4( vColor.rgb, 1.0 );',
    '}'

].join( "\n" )

And here are the uniforms and the sphere code:

asteroidMaterial = new THREE.ShaderMaterial( {
    uniforms: {
        //"displacementMap": { type: "t", value: rtTexture },
        "displacementMap": { type: "t", value: THREE.ImageUtils.loadTexture( 'txt/asteroid1.png' ) },
    },
    vertexShader: asteroidShader.vertexShader,
    fragmentShader: asteroidShader.fragmentShader,
    blending: THREE.NormalBlending,
    depthWrite: false,
    depthTest: true,
    transparent: true,
    overdraw: true,
    //wrapS: THREE.RepeatWrapping,
    //wrapT: THREE.RepeatWrapping,
    minFilter: THREE.NearestFilter,
    magFilter: THREE.NearestFilter,
} );
var asteroidGeometry = new THREE.IcosahedronGeometry( 100, 4 );
asteroidGeometry.dynamic = true;
var asteroid = new THREE.Mesh( asteroidGeometry, asteroidMaterial );
asteroid.position = new THREE.Vector3( 0, 0, 200 );
asteroid.visible = true;
scene.add( asteroid );

I just saw, that the code uses a icosahedron instead of a sphere, but the same thing is happening with spheres too.

Was it helpful?

Solution

Do not use IcosahedronGeometry, it is buggy in r.57. Use SphereGeometry, instead.

The problem is your displacement map. It appears you are getting gaps along the entire seam.

To fix the vertical seam, your displacement map must have the same values on the right edge as it has on its left edge.

To fix the poles, it must have a constant value on the top edge, and a constant value on the bottom edge.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top