Browse Source

Merge pull request #12792 from gam0022/improve-raymarching-example

Improve raymarching example
Mr.doob 7 năm trước cách đây
mục cha
commit
26ba94fae4
1 tập tin đã thay đổi với 52 bổ sung46 xóa
  1. 52 46
      examples/webgl_raymarching_reflect.html

+ 52 - 46
examples/webgl_raymarching_reflect.html

@@ -46,15 +46,19 @@
 			precision highp float;
 
 			uniform vec2 resolution;
-			uniform vec3 cameraPos;
-			uniform vec3 cameraDir;
+
+			uniform mat4 viewMatrix;
+			uniform vec3 cameraPosition;
+
+			uniform mat4 cameraWorldMatrix;
+			uniform mat4 cameraProjectionMatrixInverse;
 
 			const float EPS = 0.01;
 			const float OFFSET = EPS * 100.0;
 			const vec3 lightDir = vec3( -0.48666426339228763, 0.8111071056538127, -0.3244428422615251 );
 
 			// distance functions
-			vec3 onRep( vec3 p, float interval ) {
+			vec3 opRep( vec3 p, float interval ) {
 
 				vec2 q = mod( p.xz, interval ) - interval * 0.5;
 				return vec3( q.x, p.y, q.y );
@@ -63,7 +67,7 @@
 
 			float sphereDist( vec3 p, float r ) {
 
-				return length( onRep( p, 3.0 ) ) - r;
+				return length( opRep( p, 3.0 ) ) - r;
 
 			}
 
@@ -155,18 +159,18 @@
 
 			}
 
-			vec3 getRayColor( vec3 origin, vec3 ray, out vec3 p, out vec3 normal, out bool hit ) {
+			vec3 getRayColor( vec3 origin, vec3 ray, out vec3 pos, out vec3 normal, out bool hit ) {
 
 				// marching loop
 				float dist;
 				float depth = 0.0;
-				p = origin;
+				pos = origin;
 
 				for ( int i = 0; i < 64; i++ ){
 
-					dist = sceneDist( p );
+					dist = sceneDist( pos );
 					depth += dist;
-					p = origin + depth * ray;
+					pos = origin + depth * ray;
 
 					if ( abs(dist) < EPS ) break;
 
@@ -177,11 +181,11 @@
 
 				if ( abs(dist) < EPS ) {
 
-					normal = getNormal(p);
+					normal = getNormal( pos );
 					float diffuse = clamp( dot( lightDir, normal ), 0.1, 1.0 );
 					float specular = pow( clamp( dot( reflect( lightDir, normal ), ray ), 0.0, 1.0 ), 10.0 );
-					float shadow = getShadow( p + normal * OFFSET, lightDir );
-					color = ( sceneColor( p ).rgb * diffuse + vec3( 0.8 ) * specular ) * max( 0.5, shadow );
+					float shadow = getShadow( pos + normal * OFFSET, lightDir );
+					color = ( sceneColor( pos ).rgb * diffuse + vec3( 0.8 ) * specular ) * max( 0.5, shadow );
 
 					hit = true;
 
@@ -197,34 +201,34 @@
 
 			void main(void) {
 
-				// fragment position
-				vec2 p = ( gl_FragCoord.xy * 2.0 - resolution ) / min( resolution.x, resolution.y );
+				// screen position
+				vec2 screenPos = ( gl_FragCoord.xy * 2.0 - resolution ) / min( resolution.x, resolution.y );
+
+				// convert ray direction from screen coordinate to world coordinate
+				vec3 ray = (cameraWorldMatrix * cameraProjectionMatrixInverse * vec4( screenPos.xy, 1.0, 1.0 )).xyz;
+				ray = normalize( ray );
 
-				// camera and ray
-				vec3 cPos  = cameraPos;
-				vec3 cDir  = cameraDir;
-				vec3 cSide = normalize( cross( cDir, vec3( 0.0, 1.0 ,0.0 ) ) );
-				vec3 cUp   = normalize( cross( cSide, cDir ) );
-				float targetDepth = 1.3;
-				vec3 ray = normalize( cSide * p.x + cUp * p.y + cDir * targetDepth );
+				// camera position
+				vec3 cPos = cameraPosition;
 
+				// cast ray
 				vec3 color = vec3( 0.0 );
-				vec3 q, normal;
+				vec3 pos, normal;
 				bool hit;
 				float alpha = 1.0;
 
 				for ( int i = 0; i < 3; i++ ) {
 
-					color += alpha * getRayColor( cPos, ray, q, normal, hit );
+					color += alpha * getRayColor( cPos, ray, pos, normal, hit );
 					alpha *= 0.3;
 					ray = normalize( reflect( ray, normal ) );
-					cPos = q + normal * OFFSET;
+					cPos = pos + normal * OFFSET;
 
 					if ( !hit ) break;
 
 				}
 
-				gl_FragColor = vec4(color, 1.0);
+				gl_FragColor = vec4( color, 1.0 );
 
 			}
 
@@ -250,7 +254,7 @@
 
 		<script>
 
-			var camera, dummyCamera, scene, controls, renderer;
+			var camera, scene, controls, renderer;
 			var geometry, material, mesh;
 			var mouse = new THREE.Vector2( 0.5, 0.5 );
 			var canvas;
@@ -261,7 +265,7 @@
 			var config = {
 				saveImage: function() {
 
-					renderer.render( scene, dummyCamera );
+					renderer.render( scene, camera );
 					window.open( canvas.toDataURL() );
 
 				},
@@ -274,40 +278,42 @@
 
 			function init() {
 
+				renderer = new THREE.WebGLRenderer();
+				renderer.setPixelRatio( window.devicePixelRatio );
+				renderer.setSize( config.resolution, config.resolution );
+
+				canvas = renderer.domElement;
+				canvas.addEventListener( 'mousemove', onMouseMove );
+				window.addEventListener( 'resize', onWindowResize );
+				document.body.appendChild( canvas );
+
+				// Scene
 				scene = new THREE.Scene();
-				camera = new THREE.Camera();
-				dummyCamera = new THREE.Camera();
-				camera.lookAt( new THREE.Vector3( 0.0, -0.3, 1.0 ) );
+				camera = new THREE.PerspectiveCamera( 60, canvas.width / canvas.height, 1, 2000 );
+				camera.lookAt( new THREE.Vector3( 0.0, - 0.3, 1.0 ) );
 
 				geometry = new THREE.PlaneBufferGeometry( 2.0, 2.0 );
 				material = new THREE.RawShaderMaterial( {
 					uniforms: {
-						resolution: { value: new THREE.Vector2( 512, 512 ) },
-						cameraPos:  { value: camera.getWorldPosition() },
-						cameraDir:  { value: camera.getWorldDirection() }
+						resolution: { value: new THREE.Vector2( canvas.width, canvas.height ) },
+						cameraWorldMatrix: { value: camera.matrixWorld },
+						cameraProjectionMatrixInverse: { value: new THREE.Matrix4().getInverse( camera.projectionMatrix ) }
 					},
 					vertexShader: document.getElementById( 'vertex_shader' ).textContent,
 					fragmentShader: document.getElementById( 'fragment_shader' ).textContent
 				} );
 				mesh = new THREE.Mesh( geometry, material );
+				mesh.frustumCulled = false;
 				scene.add( mesh );
 
-				renderer = new THREE.WebGLRenderer();
-				renderer.setPixelRatio( window.devicePixelRatio );
-				renderer.setSize( 512, 512 );
-
-				canvas = renderer.domElement;
-				canvas.addEventListener( 'mousemove', onMouseMove );
-				window.addEventListener( 'resize', onWindowResize );
-				document.body.appendChild( canvas );
-
+				// Controls
 				controls = new THREE.FlyControls( camera, canvas );
-
 				controls.autoForward = true;
 				controls.dragToLook = false;
 				controls.rollSpeed = Math.PI / 12;
 				controls.movementSpeed = 0.5;
 
+				// GUI
 				var gui = new dat.GUI();
 				gui.add( config, 'saveImage' ).name( 'Save Image' );
 				gui.add( config, 'freeCamera' ).name( 'Free Camera' );
@@ -347,10 +353,10 @@
 
 				if ( camera.position.y < 0 ) camera.position.y = 0;
 
-				material.uniforms.resolution.value = new THREE.Vector2( canvas.width, canvas.height );
-				material.uniforms.cameraPos.value = camera.getWorldPosition();
-				material.uniforms.cameraDir.value = camera.getWorldDirection();
-				renderer.render( scene, dummyCamera );
+				material.uniforms.resolution.value.set( canvas.width, canvas.height );
+				material.uniforms.cameraProjectionMatrixInverse.value.getInverse( camera.projectionMatrix );
+
+				renderer.render( scene, camera );
 
 				stats.end();
 				requestAnimationFrame( render );