<br />
<b>Warning</b>:  Declaration of Jetpack_IXR_Client::query() should be compatible with IXR_Client::query(...$args) in <b>/home/clients/7267bc096562fcdb78c0ab60d3ac51fb/web/blog/wp-content/plugins/jetpack/class.jetpack-ixr-client.php</b> on line <b>91</b><br />
{"id":575,"date":"2015-12-08T17:45:47","date_gmt":"2015-12-08T17:45:47","guid":{"rendered":"http:\/\/barradeau.com\/blog\/?p=575"},"modified":"2015-12-10T17:37:41","modified_gmt":"2015-12-10T17:37:41","slug":"raymarchine-with-three-js","status":"publish","type":"post","link":"http:\/\/barradeau.com\/blog\/?p=575","title":{"rendered":"ray marching (with THREE.js)"},"content":{"rendered":"<p>Ray marching is a technique used to render complex shapes and lightings, it&#8217;s been around for years but got some huge momentum in the past 5 years.\u00a0I had some spare time and decided to give it a\u00a0spin.<\/p>\n<p>there are some really good online tools\u00a0if you want to play around :<\/p>\n<ul>\n<li><a href=\"https:\/\/www.shadertoy.com\/\" target=\"_blank\">shadertoy<\/a><\/li>\n<li><a href=\"http:\/\/glslsandbox.com\/\" target=\"_blank\">glslsandbox<\/a><\/li>\n<li><a href=\"http:\/\/shdr.bkcore.com\/\" target=\"_blank\">shdr<\/a><\/li>\n<li><a href=\"http:\/\/glslb.in\/\" target=\"_blank\">glslb.in<\/a><\/li>\n<\/ul>\n<p>the latter being the most interesting to get started as it&#8217;s part\u00a0of the\u00a0<a href=\"http:\/\/stack.gl\/\" target=\"_blank\">stackgl<\/a>\u00a0project and has support for\u00a0<a href=\"http:\/\/github.com\/stackgl\/glslify\" target=\"_blank\">glslify<\/a>\u00a0(a modular set of shader\u00a0utilities), this is what I used to understand better how things work.<\/p>\n<p>this being said, I thought I&#8217;d\u00a0use <a href=\"http:\/\/threejs.org\/\" target=\"_blank\">THREE.js<\/a> rather than the above\u00a0WebGL boilerplates because it\u00a0allows users to easily add\u00a0uniforms\u00a0and post process passes. it is on\u00a0<a href=\"https:\/\/github.com\/nicoptere\/raymarching-for-THREE\" target=\"_blank\">a github repo<\/a><\/p>\n<p>Ray Tracing (or rather Ray <em>Casting<\/em>) is a technique used to render high quality 3D images. a\u00a0blunt\u00a0description goes like:<\/p>\n<blockquote><p>for each &#8220;pixel&#8221; of the screen, a &#8220;ray&#8221; is sent from the camera through the 3d scene and returns the color for that pixel.<\/p><\/blockquote>\n<p>the oldest ray tracing\u00a0engine I know of is <a href=\"http:\/\/hof.povray.org\/\" target=\"_blank\">POV-Ray<\/a>\u00a0which allows this\u00a0type of\u00a0glorious render:<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"aligncenter size-full wp-image-589\" src=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2015\/12\/povray.png\" alt=\"povray\" width=\"800\" height=\"600\" srcset=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2015\/12\/povray.png 800w, http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2015\/12\/povray-300x225.png 300w\" sizes=\"(max-width: 800px) 100vw, 800px\" \/><\/p>\n<p>so\u00a0simple as it seems,\u00a0it displays some already complex behaviours such as shadow casting, reflections,\u00a0light bouncing and <a href=\"https:\/\/twitter.com\/DerSchmale\/status\/674979636288319488\" target=\"_blank\">not fog<\/a>\u00a0but rather the Fresnel effect of the reflections.<\/p>\n<p>ray tracing is\u00a0a well known and well documented technique.\u00a0it&#8217;s also computationally expensive, suited for pre-rendered images rather than real-time rendering\u00a0(even\u00a0though more\u00a0and more attempts are made to go towards real-time in games and architecture visualization).<\/p>\n<p>Ray Marching is a variation of the ray tracing\u00a0; instead of evaluating if\u00a0a &#8220;ray&#8221; hits the\u00a0surface of a &#8220;model&#8221; of the &#8220;scene&#8221; in the direction of the ray and at a <em>linear step size<\/em>, the &#8220;scene&#8221; will return the <em>shortest distance<\/em> to the &#8220;model&#8221; in any direction and use this distance as\u00a0the &#8220;step size&#8221; along the &#8220;ray&#8221;.<\/p>\n<p>a visual\u00a0explanation\u00a0may be better:<\/p>\n<p>&nbsp;<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"aligncenter size-full wp-image-611\" src=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2015\/12\/difference.png\" alt=\"difference\" width=\"800\" height=\"800\" srcset=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2015\/12\/difference.png 800w, http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2015\/12\/difference-150x150.png 150w, http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2015\/12\/difference-300x300.png 300w\" sizes=\"(max-width: 800px) 100vw, 800px\" \/><\/p>\n<p>the\u00a0&#8220;airquotes&#8221; around <em>scene\u00a0<\/em>and<em>\u00a0model<\/em>, are there to emphasize the fact that there is no <em>geometry<\/em> involved but rather<em> a mathematical description<\/em> of the geometry.<\/p>\n<p>indeed, as the only goal of\u00a0the <em>signed\u00a0distance function<\/em>\u00a0(or <em>SDF<\/em> the function that tells us if and at which distance the ray has reached the surface of something in the scene) is to return the shortest distance to the\u00a0<em>model<\/em> being computed, the only information we need is therefore a distance ; a float. as we only need a distance,\u00a0using a mathematical description of our scene is the way to go.<\/p>\n<p>for instance, a sphere centered at (0,0,0) is described as:<\/p>\n<pre class=\"lang:js decode:true\">float sphere( vec3 pos, float radius )\r\n{\r\n    return length( pos ) - radius;\r\n}<\/pre>\n<p>where <em>pos<\/em> is the position along the ray &amp; <em>radius<\/em> the radius of the sphere.<\/p>\n<p><strong>update:\u00a0<\/strong><strong style=\"line-height: 1.5;\">after a spontaneous and much appreciated proofread by <a href=\"https:\/\/twitter.com\/hector_arellano\" target=\"_blank\">Hector Arellano<\/a><\/strong><\/p>\n<p>the main difference between ray casting and ray marching, is the\u00a0fact that ray casting uses explicit\u00a0equations while ray marching uses implicit equations to\u00a0render the scene.<\/p>\n<p>in other words, when rendering a scene, a ray caster will find the exact intersection point between the ray being casted and the explicit equation of the geometry while<span class=\"message_body\">\u00a0ray marching uses the steps because the equations used to evaluate the boundaries of the geometry can not be evaluated in one step like collisions.<\/span><\/p>\n<div class=\"message_content\"><span class=\"message_body\">with ray marching, we\u00a0evaluate the distance using the <em>SDF<\/em>\u00a0to get to a point where the distance is close to zero while with ray tracing, we know where this point is (it is the intersection between the ray and \u00a0the shape).<\/span><i class=\"copy_only\"><\/i><\/div>\n<p>also a variable\u00a0step size is good to for\u00a0lower steps count but when the ray reaches\u00a0the\u00a0borders, it tend to get lost, for that case it\u2019s better to use a fixed size and play with the threshold.<\/p>\n<p><strong>end of\u00a0update<\/strong><\/p>\n<p>the downside of ray marching\u00a0lies in the complexity of the <em>SDF<\/em>\u00a0as it needs to be computed at each step,\u00a0the downside of ray casting lies in the complexity of handling numerous intersection tests.<\/p>\n<p>of course, there are ways to bail out early and\u00a0spare computations, it&#8217;s very frequent in ray tracing to test the bounding volumes first and cast\u00a0the ray only if there is something in the path.<\/p>\n<p>in practice there are 4\u00a0steps to follow:<\/p>\n<ol>\n<li>get the screen position : the pixel we wan to evaluate<\/li>\n<li>get the ray direction<\/li>\n<li>loop through the <em>SDF <\/em>to get the pixel color<\/li>\n<li>shade the\u00a0fragment<\/li>\n<\/ol>\n<p>it&#8217;s important to note that the only required uniform is the resolution (a vec2), here&#8217;s\u00a0a\u00a0bare bones implementation:<\/p>\n<pre class=\"lang:js decode:true\">uniform vec2 resolution;\r\n\r\n\/\/the signed distance field function\r\n\/\/used in the ray march loop\r\nfloat sdf(vec3 p) {\r\n\r\n    \/\/a sphere of radius 1.\r\n    return length( p ) - 1.;\r\n}\r\n\r\nvoid main( void ) {\r\n\r\n\/\/1 : retrieve the fragment's coordinates\r\n\tvec2 uv = ( gl_FragCoord.xy \/ resolution.xy ) * 2.0 - 1.0;\r\n\t\/\/preserve aspect ratio\r\n\tuv.x *= resolution.x \/ resolution.y;\r\n\r\n\r\n\/\/2 : camera position and ray direction\r\n\tvec3 pos = vec3( 0.,0.,-3.);\r\n\tvec3 dir = normalize( vec3( uv, 1. ) );\r\n\r\n\r\n\/\/3 : ray march loop\r\n    \/\/ip will store where the ray hits the surface\r\n\tvec3 ip;\r\n\r\n\t\/\/variable step size\r\n\tfloat t = 0.0;\r\n\tfor( int i = 0; i &lt; 32; i++) {\r\n\r\n        \/\/update position along path\r\n        ip = pos + dir * t;\r\n\r\n        \/\/gets the shortest distance to the scene\r\n\t\tfloat temp = sdf( ip );\r\n\r\n        \/\/break the loop if the distance was too small\r\n        \/\/this means that we are close enough to the surface\r\n\t\tif( temp &lt; 0.01 ) break;\r\n\r\n\t\t\/\/increment the step along the ray path\r\n\t\tt += temp;\r\n\r\n\t}\r\n\r\n\/\/4 : apply color to this fragment\r\n    \/\/we use the result position as the color\r\n\tgl_FragColor = vec4( ip, 1.0);\r\n\r\n}<\/pre>\n<p>this should give this incredible result:<\/p>\n<p><iframe loading=\"lazy\" width=\"800\" height=\"600\" frameborder=\"0\" src=\"https:\/\/www.shadertoy.com\/embed\/ldtGD4?gui=true&amp;t=10&amp;paused=true&amp;muted=false\" allowfullscreen=\"allowfullscreen\"><\/iframe><\/p>\n<p>WOW !!!<\/p>\n<p>this\u00a0is a good start nonetheless :)<\/p>\n<p>of course, spheres are boring and there are plenty of other primitives to play with, <a href=\"http:\/\/www.iquilezles.org\/\">\u00cd\u00f1go Qu\u00edlez<\/a>&#8216; <a href=\"http:\/\/iquilezles.org\/www\/articles\/distfunctions\/distfunctions.htm\">distance functions<\/a>\u00a0became the defacto reference, note that he did a <a href=\"https:\/\/www.shadertoy.com\/view\/Xds3zN\" target=\"_blank\">handy scene on shadertoy<\/a> that displays all the shapes\u00a0at once (+lights, shadows, AO, reflections etc.). the methods below describe a sphere\u00a0and\u00a0a box with rounded corners (I&#8217;ve added a vec3 center to position the object in space).<\/p>\n<pre class=\"lang:js decode:true\">float sphere( vec3 pos, vec3 center, float radius )\r\n{\r\n    return length( pos - center ) - radius;\r\n}\r\n\r\nfloat box( vec3 pos, vec3 center, vec3 size, float corner )\r\n{\r\n    return length( max( abs( pos-center )-size, 0.0 ) )-corner;\r\n}\r\n<\/pre>\n<p>if you understood\u00a0the idea behind ray marching, you\u00a0remember that we&#8217;re only interested in retrieving a distance &#8211;\u00a0a float\u00a0&#8211;\u00a0each time we move along the ray. things gets really interesting when you start combining different\u00a0shapes ; two or more shapes will be more or less close to the point in space being evaluated and that&#8217;s where we can decide\u00a0how to combine them. the\u00a0generic name for this kind of operations is <em><a href=\"https:\/\/en.wikipedia.org\/wiki\/Constructive_solid_geometry\" target=\"_blank\">Constructive Solid Geometry<\/a><\/em> (CSG) and consists in performing\u00a0boolean operations on\u00a0geometric primitives\u00a0to build complex shapes.<\/p>\n<p>these are the basic operations: union, subtraction\u00a0and\u00a0intersection.<\/p>\n<pre class=\"lang:js decode:true\">float unite( float a, float b){return min(a, b);}\r\nfloat subtract( float a, float b ){ return max(-a, b); }\r\nfloat intersect( float a, float b ){ return max(a, b); }<\/pre>\n<p>they can be used in the <em>SDF<\/em>\u00a0function like so:<\/p>\n<pre class=\"lang:js decode:true\">float sdf(vec3 p) {\r\n\r\n    \/\/we build a sphere\r\n    float s = sphere( p, vec3( 0. ), 1.25 );\r\n\r\n    \/\/we build a box\r\n    float b = box( p, vec3( 0. ), vec3( 1. ), .0 );\r\n\r\n    \/\/we return the combination of both:\r\n    \/\/ subtracting the sphere from the box\r\n    return subtract( s,b  );\r\n}\r\n<\/pre>\n<p>this now gives the result below:<\/p>\n<p><iframe loading=\"lazy\" width=\"800\" height=\"600\" frameborder=\"0\" src=\"https:\/\/www.shadertoy.com\/embed\/MdtGD4?gui=true&#038;t=10&#038;paused=true&#038;muted=false\" allowfullscreen><\/iframe><\/p>\n<p>there are other ways to blend objects together, the most useful <a href=\"http:\/\/iquilezles.org\/www\/articles\/smin\/smin.htm\" target=\"_blank\">is described here<\/a>.<\/p>\n<p>I&#8217;ll just leave you with some demos of where a week of work led me (all demos are also on <a href=\"https:\/\/github.com\/nicoptere\/raymarching-for-THREE\" target=\"_blank\">the repo<\/a>):<\/p>\n<p><a href=\"http:\/\/barradeau.com\/one-trick-ponies\/20\/\"><img decoding=\"async\" loading=\"lazy\" class=\"aligncenter wp-image-595 size-full\" src=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2015\/12\/cover.jpg\" alt=\"cover\" width=\"801\" height=\"801\" srcset=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2015\/12\/cover.jpg 801w, http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2015\/12\/cover-150x150.jpg 150w, http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2015\/12\/cover-300x300.jpg 300w\" sizes=\"(max-width: 801px) 100vw, 801px\" \/><\/a><\/p>\n<p style=\"text-align: center;\">day 3\u00a0<a href=\"http:\/\/barradeau.com\/one-trick-ponies\/20\/\" target=\"_blank\">mouse interactions<\/a><\/p>\n<p><a href=\"http:\/\/barradeau.com\/one-trick-ponies\/22\/\"><img decoding=\"async\" loading=\"lazy\" class=\"aligncenter wp-image-596 size-full\" src=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2015\/12\/halibut.jpg\" alt=\"halibut\" width=\"801\" height=\"801\" srcset=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2015\/12\/halibut.jpg 801w, http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2015\/12\/halibut-150x150.jpg 150w, http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2015\/12\/halibut-300x300.jpg 300w\" sizes=\"(max-width: 801px) 100vw, 801px\" \/><\/a><\/p>\n<p style=\"text-align: center;\">day 4\u00a0<a href=\"http:\/\/barradeau.com\/one-trick-ponies\/22\/\" target=\"_blank\">something moving<\/a>\u00a0(and a bit gross)<\/p>\n<p><a href=\"http:\/\/barradeau.com\/one-trick-ponies\/23\/\"><img decoding=\"async\" loading=\"lazy\" class=\"aligncenter wp-image-597 size-full\" src=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2015\/12\/hulkbuster.jpg\" alt=\"hulkbuster\" width=\"800\" height=\"800\" srcset=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2015\/12\/hulkbuster.jpg 800w, http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2015\/12\/hulkbuster-150x150.jpg 150w, http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2015\/12\/hulkbuster-300x300.jpg 300w\" sizes=\"(max-width: 800px) 100vw, 800px\" \/><\/a><\/p>\n<p style=\"text-align: center;\">day 5\u00a0<a href=\"http:\/\/barradeau.com\/one-trick-ponies\/23\/\" target=\"_blank\">something moving<\/a><\/p>\n<p style=\"text-align: center;\"><a href=\"http:\/\/barradeau.com\/one-trick-ponies\/24\/\"><img decoding=\"async\" loading=\"lazy\" class=\"aligncenter wp-image-600 size-full\" src=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2015\/12\/walker.jpg\" alt=\"walker\" width=\"800\" height=\"800\" srcset=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2015\/12\/walker.jpg 800w, http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2015\/12\/walker-150x150.jpg 150w, http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2015\/12\/walker-300x300.jpg 300w\" sizes=\"(max-width: 800px) 100vw, 800px\" \/><\/a><br \/>\nday 7\u00a0<a href=\"http:\/\/barradeau.com\/one-trick-ponies\/24\/\" target=\"_blank\">a walker<\/a><\/p>\n<p>&nbsp;<\/p>\n<p>the platforms I mentioned at the beginning of the article are\u00a0basically gold mines to find advanced techniques, with brillant people sharing brillant tricks.<\/p>\n<p>but otherwise, that&#8217;s all there is to ray marching, now you can go BANANA and make\u00a0some pretty pictures\u00a0:)<\/p>\n<p>cheers!<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Ray marching is a technique used to render complex shapes and lightings, it&#8217;s been around for years but got some huge momentum in the past 5 years.\u00a0I had some spare time and decided to give it a\u00a0spin. there are some really good online tools\u00a0if you want to play around : shadertoy glslsandbox shdr glslb.in the &#8230; <span class=\"more\"><a class=\"more-link\" href=\"http:\/\/barradeau.com\/blog\/?p=575\">[Read more&#8230;]<\/a><\/span><\/p>\n","protected":false},"author":1,"featured_media":597,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"sharing_disabled":false,"spay_email":"","jetpack_publicize_message":""},"categories":[3],"tags":[],"jetpack_featured_media_url":"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2015\/12\/hulkbuster.jpg","jetpack_publicize_connections":[],"jetpack_shortlink":"https:\/\/wp.me\/p4oXhx-9h","_links":{"self":[{"href":"http:\/\/barradeau.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/575"}],"collection":[{"href":"http:\/\/barradeau.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/barradeau.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/barradeau.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/barradeau.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=575"}],"version-history":[{"count":26,"href":"http:\/\/barradeau.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/575\/revisions"}],"predecessor-version":[{"id":577,"href":"http:\/\/barradeau.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/575\/revisions\/577"}],"wp:featuredmedia":[{"embeddable":true,"href":"http:\/\/barradeau.com\/blog\/index.php?rest_route=\/wp\/v2\/media\/597"}],"wp:attachment":[{"href":"http:\/\/barradeau.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=575"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/barradeau.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=575"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/barradeau.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=575"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}