I'm trying to wrap a SphereBufferGeometry with a ShaderMaterial where I'm using noise to resemble the surface of Jupiter, but it's wrapping very oddly to the sphere geometry. All of the animated texture appears in a thin belt around one of the lines of latitude rather than wrapped around the 'planet' like a normal texture. I've attached images below.
It works well on a plane, but I was probably naive to think it would simply wrap like a texture would wrap, and I'm quite new to Shader programming so I'm a bit stuck.
this is the plane which is wrapping fine
this is not wrapping correctly
I've a feeling that maybe I can move the noise equations to the fragmentShader - but my knowledge isn't there yet, it broke when I tried. I even tried morphing the targets of the plane into a sphere but ShaderMaterial doesn't natively support morphTargets and I after a LOT of trying to inject the #include <morphtarget_pars_vertex>
using onBeforeCompile
I still couldn't get it to work. I've also tried THREE's wrapping equations on the uniform texture, but it yields similar results.
Here's all of my code, the shaderMaterial implementation is in addPlanet()
:
import * as THREE from '../../build/three.module';
import { OrbitControls } from '../../examples/jsm/controls/OrbitControls';
const displacementVert = `
precision mediump float;
varying vec2 vUv;
varying float vWave;
uniform float uTime;
//
// Description : Array and textureless GLSL 2D/3D/4D simplex
// noise functions.
// Author : Ian McEwan, Ashima Arts.
// Maintainer : ijm
// Lastmod : 20110822 (ijm)
// License : Copyright (C) 2011 Ashima Arts. All rights reserved.
// Distributed under the MIT License. See LICENSE file.
// https://github.com/ashima/webgl-noise
//
vec3 mod289(vec3 x) {
return x - floor(x * (1.0 / 289.0)) * 289.0;
}
vec4 mod289(vec4 x) {
return x - floor(x * (1.0 / 289.0)) * 289.0;
}
vec4 permute(vec4 x) {
return mod289(((x*34.0)+1.0)*x);
}
vec4 taylorInvSqrt(vec4 r)
{
return 1.79284291400159 - 0.85373472095314 * r;
}
float snoise(vec3 v) {
const vec2 C = vec2(1.0/6.0, 1.0/3.0) ;
const vec4 D = vec4(0.0, 0.5, 1.0, 2.0);
// First corner
vec3 i = floor(v + dot(v, C.yyy) );
vec3 x0 = v - i + dot(i, C.xxx) ;
// Other corners
vec3 g = step(x0.yzx, x0.xyz);
vec3 l = 1.0 - g;
vec3 i1 = min( g.xyz, l.zxy );
vec3 i2 = max( g.xyz, l.zxy );
// x0 = x0 - 0.0 + 0.0 * C.xxx;
// x1 = x0 - i1 + 1.0 * C.xxx;
// x2 = x0 - i2 + 2.0 * C.xxx;
// x3 = x0 - 1.0 + 3.0 * C.xxx;
vec3 x1 = x0 - i1 + C.xxx;
vec3 x2 = x0 - i2 + C.yyy; // 2.0*C.x = 1/3 = C.y
vec3 x3 = x0 - D.yyy; // -1.0+3.0*C.x = -0.5 = -D.y
// Permutations
i = mod289(i);
vec4 p = permute( permute( permute(
i.z + vec4(0.0, i1.z, i2.z, 1.0 ))
+ i.y + vec4(0.0, i1.y, i2.y, 1.0 ))
+ i.x + vec4(0.0, i1.x, i2.x, 1.0 ));
// Gradients: 7x7 points over a square, mapped onto an octahedron.
// The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294)
float n_ = 0.142857142857; // 1.0/7.0
vec3 ns = n_ * D.wyz - D.xzx;
vec4 j = p - 49.0 * floor(p * ns.z * ns.z); // mod(p,7*7)
vec4 x_ = floor(j * ns.z);
vec4 y_ = floor(j - 7.0 * x_ ); // mod(j,N)
vec4 x = x_ *ns.x + ns.yyyy;
vec4 y = y_ *ns.x + ns.yyyy;
vec4 h = 1.0 - abs(x) - abs(y);
vec4 b0 = vec4( x.xy, y.xy );
vec4 b1 = vec4( x.zw, y.zw );
//vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0;
//vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0;
vec4 s0 = floor(b0)*2.0 + 1.0;
vec4 s1 = floor(b1)*2.0 + 1.0;
vec4 sh = -step(h, vec4(0.0));
vec4 a0 = b0.xzyw + s0.xzyw*sh.xxyy ;
vec4 a1 = b1.xzyw + s1.xzyw*sh.zzww ;
vec3 p0 = vec3(a0.xy,h.x);
vec3 p1 = vec3(a0.zw,h.y);
vec3 p2 = vec3(a1.xy,h.z);
vec3 p3 = vec3(a1.zw,h.w);
// Normalise gradients
vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3)));
p0 *= norm.x;
p1 *= norm.y;
p2 *= norm.z;
p3 *= norm.w;
// Mix final noise value
vec4 m = max(0.6 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0);
m = m * m;
return 42.0 * dot( m*m, vec4( dot(p0,x0), dot(p1,x1),
dot(p2,x2), dot(p3,x3) ) );
}
void main() {
vUv = uv;
vec3 pos = position;
float noiseFreq = 3.5;
float noiseAmp = 0.15;
vec3 noisePos = vec3(pos.x * noiseFreq + uTime, pos.y, pos.z);
pos.z += snoise(noisePos) * noiseAmp;
vWave = pos.z;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.);
}
`;
const displacementFrag = `
precision mediump float;
varying vec2 vUv;
varying float vWave;
uniform sampler2D uTexture;
void main() {
float wave = vWave * 0.25;
vec3 texture = texture2D(uTexture, vUv + wave).rgb;
gl_FragColor = vec4(texture, 1.);
}`;
let width, height;
let scene, camera, renderer;
let controls;
let wireframe;
let clock;
let planetShaderMaterial;
let jupiterSphere;
const init = ( params ) => {
colors = params.colors;
model = params.model;
width = params.width;
height = params.height;
scene = new THREE.Scene();
clock = new THREE.Clock();
camera = new THREE.PerspectiveCamera( params.fov, width / height, params.near, params.far );
camera.position.set( params.cameraPos.x, params.cameraPos.y, params.cameraPos.z );
renderer = new THREE.WebGLRenderer({ antialias: true, logarithmicDepthBuffer: true });
renderer.setSize( width, height );
renderer.outputEncoding = THREE.sRGBEncoding;
wireframe = params.wireframe;
renderer.render( scene, camera );
controls = new OrbitControls( camera, renderer.domElement );
addLights();
addPlanet();
}
const addLights = () => {
const ambientLight = new THREE.AmbientLight( 0xffffff, 10 );
scene.add( ambientLight );
const dir = 1024;
const light = new THREE.DirectionalLight( 0xffffff, 1 );
light.position.set( 100, 100, 50 );
light.castShadow = true;
light.shadow.camera.left = -dir;
light.shadow.camera.right = dir;
light.shadow.camera.top = dir;
light.shadow.camera.bottom = -dir;
light.shadow.camera.near = 0.1;
light.shadow.camera.far = 1000;
light.shadow.mapSize.x = 1024;
light.shadow.mapSize.y = 1024;
scene.add( light );
}
// ******** HERE'S THE ShaderMaterial implementation
const addPlanet = () => {
const texture = new THREE.TextureLoader().load( './assets/textures/disp/jupiter.jpg' );
planetShaderMaterial = new THREE.ShaderMaterial( {
uniforms: {
uTime: { value: 0.0 },
uTexture: { value: texture }
},
wireframe: false,
side: THREE.FrontSide,
vertexShader: displacementVert,
fragmentShader: displacementFrag,
});
// these have no effect. Repeat Wrapping just repeats the current effect
planetShaderMaterial.uniforms.uTexture.value.wrapS = THREE.ClampToEdgeWrapping;
planetShaderMaterial.uniforms.uTexture.value.wrapT = THREE.ClampToEdgeWrapping;
jupiterSphere = new THREE.Mesh( new THREE.SphereBufferGeometry( 25, 32, 32), planetShaderMaterial );
scene.add( jupiterSphere );
}
const render = () => {
planetShaderMaterial.uniforms.uTime.value = clock.getElapsedTime();
renderer.render( scene, camera );
}
const resize = ( width, height ) => {
windowWidth = width;
windowHeight = height;
camera.aspect = width / height;
camera.updateProjectionMatrix();
renderer.setSize( width, height );
}
const getRenderer = () => {
return renderer;
}
const TestWorld = {
init,
render,
resize,
getRenderer
};
export default TestWorld;
Via Active questions tagged javascript - Stack Overflow https://ift.tt/2FdjaAW
Comments
Post a Comment