Skip to main content

Creating a scene

The goal of this section is to give a brief introduction to glre.js. We will start by setting up a scene, with a spinning cube.

Before we started

Before you can use glre.js, you need somewhere to display it. Save the following HTML to a file on your computer.

<canvas id="myCanvas"></canvas>
<script type="module">
        import self from 'https://cdn.skypack.dev/[email protected]'

        // Our GLSL and Javascript will go here.
        const frag = `
                ...
        `

        document.addEventListener('DOMContentLoaded', setup)

        function setup() {
                // ...
        }
        function draw() {
                // ...
        }
</script>

Creating Fragment Shader

precision highp float;
uniform vec2 iResolution; // canvas size
uniform vec3 up;          // camera up direction
uniform vec3 eye;         // camera position
uniform vec3 focus;       // camera focus point
uniform float focal;      // camera focal length
uniform float size;       // object size

Creating Box

float boxSDF(vec3 p, float side) {
        vec3 d = abs(p) - side;
        return min(max(d.x, max(d.y, d.z)), 0.) + length(max(d, 0.));
}

Raymarch Setup

  • Calculate this particular pixel's normalized coordinates
  • Calculate the direction that the ray through this pixel goes
  • Calculate eye directions
void main() {
        /**
         * Ray marching setup
         */
        vec3 look = normalize(focus - eye);
        vec3 right = normalize(cross(look, up));
        vec2 scr = gl_FragCoord.xy - iResolution * .5;
        vec3 dir = normalize(focal * look + scr.x * right + scr.y * up);
        /**
        * Ray marching
        */
        vec3 p = eye + dir;
        vec3 e = vec3(.0005, .0, .0);
        float d = boxSDF(p, size);
        for (int i = 0; i < 50; i++) {
                if (d <= e.x) {
                        float dx = boxSDF(p + e.xyy, size) - d;
                        float dy = boxSDF(p + e.yxx, size) - d;
                        float dz = boxSDF(p + e.yyx, size) - d;
                        vec3 norm = normalize(vec3(dx, dy, dz));
                        gl_FragColor = vec4(norm * .5 + .5, 1.);
                        return;
                }
                p = p + d * dir;
                d = boxSDF(p, size);
        }
}

Setup glre

document.addEventListener('DOMContentLoaded', setup)

function setup() {
        self.el = document.getElementById('id')
        self.gl = self.el.getContext('webgl2')
        self.frag = frag
        self.init()
        self.resize()
        self.uniform({
                up: [0, 1, 0],
                focus: [0, 0, 0],
                focal: 500,
                size: 50,
        })
        draw()
}

Rendering the scene

function draw() {
        requestAnimationFrame(draw)
        const t = performance.now() / 1000
        const x = 200 * Math.cos(t)
        const z = 200 * Math.sin(t)
        self.uniform({ eye: [x, 0, z] })
        self.render()
        self.viewport()
        self.clear()
        self.drawArrays()
}

The result

<canvas id="id" style="top: 0; left: 0; position: fixed" />
<script type="module">
        import self from 'https://cdn.skypack.dev/[email protected]'
        const frag = `
                precision highp float;
                uniform vec2 iResolution; // canvas size
                uniform vec3 up;          // camera up direction
                uniform vec3 eye;         // camera position
                uniform vec3 focus;       // camera focus point
                uniform float focal;      // camera focal length
                uniform float size;       // object size
                /**
                 * boxSDF
                 */
                float boxSDF(vec3 p, float side) {
                        vec3 d = abs(p) - side;
                        return min(max(d.x, max(d.y, d.z)), 0.) + length(max(d, 0.));
                }
                /**
                 * main
                 */
                void main() {
                        /**
                         * Ray marching setup
                         */
                        vec3 look = normalize(focus - eye);
                        vec3 right = normalize(cross(look, up));
                        vec2 scr = gl_FragCoord.xy - iResolution * .5;
                        vec3 dir = normalize(focal * look + scr.x * right + scr.y * up);
                        /**
                         * Ray marching
                         */
                        vec3 p = eye + dir;
                        vec3 e = vec3(.0005, 0., 0.);
                        float d = boxSDF(p, size);
                        for (int i = 0; i < 50; i++) {
                                if (d <= e.x) {
                                        float dx = boxSDF(p + e.xyy, size) - d;
                                        float dy = boxSDF(p + e.yxx, size) - d;
                                        float dz = boxSDF(p + e.yyx, size) - d;
                                        vec3 norm = normalize(vec3(dx, dy, dz));
                                        gl_FragColor = vec4(norm * .5 + .5, 1.);
                                        return;
                                }
                                p = p + d * dir;
                                d = boxSDF(p, size);
                        }
                }
        `

        document.addEventListener('DOMContentLoaded', setup)

        function setup() {
                self.el = document.getElementById('id')
                self.gl = self.el.getContext('webgl2')
                self.frag = frag
                self.init()
                self.resize()
                self.uniform({
                        up: [0, 1, 0],
                        focus: [0, 0, 0],
                        focal: 500,
                        size: 50,
                })
                draw()
        }

        function draw() {
                requestAnimationFrame(draw)
                const t = performance.now() / 1000
                const x = 200 * Math.cos(t)
                const z = 200 * Math.sin(t)
                self.uniform({ eye: [x, 0, z] })
                self.render()
                self.viewport()
                self.clear()
                self.drawArrays()
        }
</script>