How to get continuous noise across a normalized cube within the shader?

Hi, post this question on StackOverflow with no avail so I thought I’ll to come to the score to ask it.

I’m working on a project where I need to texture a cubed sphere using noise in Three.js, so that the texture is continuous across all six sides. I’ve already created the cube using six planes for each side, but I’m having trouble getting the noise to be continuous across the cubed sphere.

Can anyone provide some guidance on how to texture a cubed sphere using noise in Three.js, so that the texture is continuous across all six sides?

WORKING EXAMPLE:EXAMPLE

Here is the cube with noise:

L0Hz5

Here is the cube transformed into a sphere (as you can see the noise isn’t continuous between each side):

Here is an image of what I want the outcome to look like:
frCIB

this is how the cube this created

 var front = buildMesh(texture);
    var fg = new THREE.Group(front)
    fg.add(front)
  
    var back = buildMesh(texture);
    var bg = new THREE.Group(back)
    bg.add(back)
    bg.position.z = -w;
    bg.rotation.y=(Math.PI)

    var right = buildMesh(texture);
    var rg = new THREE.Group(right)
    rg.add(right)
    rg.position.z = -((w)/2);
    rg.position.x =  ((w)/2);
    rg.rotation.y = (Math.PI/2)


    var left = buildMesh(texture);
    var lg = new THREE.Group(left)
    lg.add(left)
    lg.position.z = -((w)/2);
    lg.position.x = -((w)/2);
    lg.rotation.y=(-Math.PI/2)

    var top = buildMesh(texture);
    var tg = new THREE.Group(top)
    tg.add(top)
    tg.position.z = -((w)/2);
    tg.position.y = ((w)/2);
    tg.rotation.x=(-Math.PI/2)

    var bot = buildMesh(texture);
    var bog = new THREE.Group(bot)
    bog.add(bot)
    bog.position.z = -((w)/2);
    bog.position.y = -((w)/2);
    bog.rotation.x=(Math.PI/2)

    var g = new THREE.Group()
    g.add(fg)
    g.add(bg)
    g.add(lg)
    g.add(rg)
    g.add(tg)
    g.add(bog)
    
  scene.add(g)

  function buildMesh(t){
    let geometry = new THREE.PlaneGeometry(w, w,50,50);
    uniforms = {u_tex: {value: t },wTl:{value:new THREE.Vector3()},ps:{value:new THREE.Vector3()}}; 
    let material = new THREE.ShaderMaterial({
      uniforms: uniforms,
      fragmentShader: fragmentShader(),
      vertexShader: vertexShader(),
      wireframe:false
    });

    var mesh = new THREE.Mesh(geometry, material);
    return mesh
  }

this is how i’m calculating my ‘localceter’ vertex shader variable to normalize each plane.


    var sides = [
      ...fg.children,
      ...bg.children,
      ...rg.children,
      ...lg.children,
      ...tg.children,
      ...bog.children,
    ]

    var cnt = centerPosition(g)
    var localCenter = new THREE.Vector3();
    for (let index = 0; index < sides.length; index++) {
      const element = sides[index];
      element.worldToLocal(localCenter.copy(cnt))
      element.material.uniforms['wTl'].value = localCenter
    }

  function centerPosition(g) {
    bbox.expandByObject(g);
    var center = new THREE.Vector3();
    bbox.getCenter(center);
    return center
  }

the fragment and vertex shader

function vertexShader(){
  return `
  varying vec2 vUv;
  uniform vec3 wTl;

 vec3 planeToSphere(vec3 p, vec3 localCenter){
    p = p - localCenter;
    p=normalize(p);
    float length = -length(p);
    p = p * length * (localCenter.z*1.0);
    p = p+localCenter;
    return p;
  }

    
varying vec3 v3n;
    void main() {
      vUv = uv;
      vec3 newPosition   =  planeToSphere(position,wTl) ;
      vec3 worldp = ( modelMatrix * vec4(newPosition,1.0)).xyz;
      float n = snoise(worldp*.04);
      v3n=vec3(n,n,n);
      vec3 finalp = newPosition+normal*n;
      gl_Position = projectionMatrix  * modelViewMatrix * vec4( finalp, 1.0 ) ;
    }
  
  `
}

function fragmentShader(){
  return `
    varying vec2 vUv;
    varying vec3 v3n;

    
    void main() {

      gl_FragColor  = vec4(v3n,1.0);

    }
`
}

Is this what you want? The noise height is increased only for demonstration purpose.

https://codepen.io/boytchev/full/QWZdRmR
image

1 Like

yes, this seems to work but there is this issue. Any idea of what causing it?

Screenshot 2023-04-23 134758

It appears this is an issue with the noise generation. Does it work for you if line 112 is changed from:

float n = snoise(worldp*.04);

to

float n = snoise(worldp*.03);

yes, that does work it seems that any value >= .4 causes that vertex to protrude. hmm ill try a different noise library

check here for a couple of options

2 Likes

The value 0.04 looks fine when w=101 (instead of 100). My advice would be to find the cause, otherwise, if you pick another noise generator, it may work for you now, but one day it might fail for some other value.

For example, you can try one big plane – fill it with noise and check whether it is continuous.

If it is continuous, then the noise library is innocent. Probably.

When I want to paint something with noise, I use noise in fragment shader. Cabochons (CabochonGeometry)

Hm. So if I’m understanding you correctly I would to have one nise generator in the vertex shader and another in the fragment shader? Because not only do I need to paint but displace the vertices

If you’re okay with that pattern of squares, then you can use just one noise generator in vertex shader.