Three.js Custom Shader Object Coordinate

I have raymarching shader but when im moving the mesh the objects stay relative on world origin, i wanted it to move with the object.

1 Like

Hi!
Any chance to provide an example of what and how you do?

1 Like

Ok,im trying to make raymarching shader that i found on youtube and i found the tutorial to do it on unity. This is my code so far.

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>Ray Marching in three.js</title>
		<style>
			body { margin: 0; }
		</style>
	</head>
	<body>
		<script src="three.js"></script>
		<script src="three.module.js"></script>
		<script src="OrbitControls.js"></script>
		<script>
			const scene = new THREE.Scene();
			const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );

			const renderer = new THREE.WebGLRenderer();
			renderer.setSize( window.innerWidth, window.innerHeight );
			document.body.appendChild( renderer.domElement );

			camera.position.z = 2.5;
			camera.lookAt( 0, 0, 0 );

			//controls
			const controls = new OrbitControls( camera, renderer.domElement );
			controls.zoomSpeed = 2;
			controls.update();

			vShader = [
				'varying vec3 vPosition;',
				'varying vec2 vUv;',
				'void main() {',
				'	vPosition = (projectionMatrix * vec4( position, 1.0 )).xyz;',
				'	vUv = uv;',
				'	gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );',
				'}'
			].join( '\n' );

			fShader = [
				'uniform vec3 camPos;',
				'uniform vec2 resolution;',
				'varying vec3 vPosition;',
				'varying vec2 vUv;',
				'#define MAX_STEPS 1000',
				'#define MAX_DIST 100.',
				'#define SURF_DIST 1e-2',

				'float planeSDF(vec3 p) {',
				'	return p.y;',
				'}',

				'float sphereSDF(vec3 p, float r) {',
				'	return length(p)-r;',
				'}',

				'float GetDist(in vec3 p) {',
				'    float objectDist = sphereSDF(p-vec3(0, 1, 6), 1.);',
				'    float groundDist = p.y;',
				'    float d = min(objectDist, groundDist);',
				'    return d;',
				'}',

				'float RayMarch(vec3 ro, vec3 rd) {',
				'	float dO=0.;',
				'	for(int i = 0; i < MAX_STEPS; i++) {',
				'		vec3 p = ro + rd*dO;',
				'		float dS = GetDist(p);',
				'		dO += dS;',
				'		if(dO>MAX_DIST || dS<SURF_DIST) break;',
				'	}',
				'	return dO;',
				'}',

				'vec3 GetNormal(vec3 p) {',
				'	float d = GetDist(p);',
				'	vec2 e = vec2(SURF_DIST, 0);',

				'	vec3 n = d - vec3(',
				'		GetDist(p-e.xyy),',
				'		GetDist(p-e.yxy),',
				'		GetDist(p-e.yyx));',

				'	return normalize(n);',
				'}',

				'float GetShadow(in vec3 p, in vec3 l) {',
				'	float t = SURF_DIST;',
				'	float t_max = MAX_DIST;',

				'	float res = 1.0;',
				'	float ph = 1e20;',
				'	for(int i = 0; i < 256; ++i) {',
				'		if(t > t_max) break;',
				'		float h = GetDist(p+t*l);',
				'		if(h < SURF_DIST/10.) return 0.0;',
				'		float y = h*h/(2.0*ph);',
				'		float d = sqrt(h*h-y*y);',
				'		ph = h;',
				'		t += d;',
				'		res = min(res, 4.*d/max(0.,t-y));',
				'	}',
				'	return res;',
				'}',

				'float GetAo(vec3 p, vec3 n) {',
				'	float occ = 0.;',
				'	float sca = 1.;',
				'	for(int i = 0; i < 5; i++) {',
				'		float h = 0.001 + 0.15*float(i)/4.0;',
				'		float d = GetDist(p+h*n);',
				'		occ += (h-d)*sca;',
				'		sca *= 0.95;',
				'	}',
				'	return clamp( 1.0 - 1.5*occ, 0.0, 1.0 );',
				'}',

				'float GetLight(vec3 p, vec3 lPos) {',
				'	vec3 l = normalize(lPos-p);',
				'	vec3 n = GetNormal(p);',

				'	float dif = clamp(dot(n, l), 0., 1.);',
				'	float s = GetShadow(p, l);',
				'	dif *= s;',
					//float s = RayMarch(p+n*SURF_DIST*2., l);
					//if(s<length(lPos)) dif*= 0.;

				'	return dif;',
				'}',

				'void main() {',
				'	vec2 uv = vUv-.5;',
				'	vec3 ro = vec3(0, 1, 0);',
				'	vec3 rd = normalize(vec3(uv.x, uv.y, 1));',
				'	float d = RayMarch(ro, rd);',
				'	vec3 col = vec3(0);',

				'	vec3 p = ro + rd * d;',
				'	vec3 lightPos = vec3(3, 6, -6);',
				'	vec3 dir = vec3(GetLight(p, lightPos));',
				'	vec3 indir = vec3(.051*GetAo(p, GetNormal(p)));',
				'	col = dir+indir;',
				'	col = pow(col, vec3(.4545));',
				'	gl_FragColor = vec4( col, 0. );',
				'}'
			].join( '\n' );

			const geometry = new THREE.BoxGeometry( 1, 1, 1 );
			const material = new THREE.ShaderMaterial( {uniforms: {camPos: { value: new THREE.Vector3(camera.position.x, camera.position.y, camera.position.z) }, resolution: { value: new THREE.Vector2(window.innerWidth, window.innerHeight) }}, vertexShader: vShader, fragmentShader: fShader} );
			const cube = new THREE.Mesh( geometry, material );
			scene.add( cube );

			controls.addEventListener( 'change', render, false );
			window.addEventListener( 'resize', onWindowResize, false );
			function onWindowResize() {
				camera.aspect = window.innerWidth/ window.innerHeight;
				camera.updateProjectionMatrix();
				renderer.setSize( window.innerWidth, window.innerHeight );
				render();
			}

			function render() {
				//requestAnimationFrame( render );
				material.uniforms.camPos.value = new THREE.Vector3(camera.position.x, camera.position.y, camera.position.z);
				renderer.render( scene, camera );
			};
			render();
		</script>
	</body>
</html>

So it looks like im using a texture but its not, what im trying to do now i wanted to make it looks like a portal, Writing a raymarcher in unity basically he change the cube to a torus.

1 Like

Seems I’ve fixed it, watching the video from Martijn.
You’ve done most of work with porting, and this is really great :+1:

Camera position needs to be converted to cube’s local space:

  v.copy(camera.position);
  cube.worldToLocal(v);
  material.uniforms.camPos.value.copy(v);

In shaders, " vPosition = position;", - cube’s vertex position is in local space (no multiplications with matrices needed)

Thus, ray origin and ray direction set like this:

  "	vec3 ro = camPos; //vec3(0, 1, 0);",
  "	vec3 rd = normalize(vPosition - ro); //normalize(vec3(uv.x, uv.y, 1));",

And finally, shift the raymarching scene, that the sphere is in the center of it:

  "    float objectDist = sphereSDF(p, 0.25);",
  "    float groundDist = p.y + 0.25;",

Ah, and camera position is like that :camera.position.set(2, 1, 0);

Picture:

изображение

Example: https://codepen.io/prisoner849/full/YzpBPbm

4 Likes

aha thanks i thought

was a world coordinate, but it’s local coordinate. And i got it working now thanks.

You’re welcome :slight_smile: :beers:

position is always in local coordinates.

2 Likes