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.
Hi!
Any chance to provide an example of what and how you do?
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.
Seems I’ve fixed it, watching the video from Martijn.
You’ve done most of work with porting, and this is really great
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:
aha thanks i thought
was a world coordinate, but it’s local coordinate. And i got it working now thanks.
You’re welcome
position
is always in local coordinates.