Overview

This is a work-in-progress example to create the following:

A particle system of "raining" spheres on a curved surface that bounce in a (relatively) physically correct manner against the surface and each other.

It is intended to demonstrate the following:

  • Separation of the graphics subsystem from the main engine
  • A basic particle system
  • Physics with large number of interactions
  • Shared geometry between entities
  • Engine performance

Example Code

/*-----------------------------------------------------------------------------*
 *  Copyright (c) 2013 Benjamin Cronin                                         *
 *  Licensed under the MIT license (http://opensource.org/licenses/MIT)        *
 *-----------------------------------------------------------------------------*/

$(function()
{   
    var sc3 = require("surfacecurve-gfx");   
    
    var sceneParser = new sc3.SceneParserJson;        
    
    function Physics()
    {
        this._engine = null;
    }
    _.extend(Physics.prototype, 
    {
        initialize : function (engine)
        {
            this._engine = engine;
        },
        trace : function(inst)
        {
            var engine = this._engine;
            
            // Hard-coded stub for dev purposes
            var pos = inst.position;
            var end = vec3.addC(pos, vec3.C(0,0,-.25));
            
            var res =
            {
                start   : { time : 0, position : pos },
                end     : { time : 1, position : end }
            };

            return res;
        }
    });
    
    function TracerPlugin()
    {

    }
    _.extend(TracerPlugin.prototype,
    {
        initialize : function (engine)
        {
            var physics = engine.physics;
            
            engine.on("add", function (inst) {
                if (inst.hasClass("trace"))
                {
                    var res = physics.trace(inst);
                    
                    var x = res.end.position[0];
                    var y = res.end.position[1];
                    var z = res.end.position[2];
                    var obj = 
                    { linestrip : {
                        classes : [ "renderable" ],
                        vertices   : [
                            res.start.position,
                            res.end.position
                        ],
                        material   : "solid-green" 
                    }};
                    engine.add("object", obj);
                }
            });
        }
    });
    
    
    var sceneDesc = 
    {
        camera :
        {
            type        : "spinning_camera",
            target      : [ 0, 0, .1 ],
            radius      : 1,
            height      : .35
        },
        materials :
        {
            "@urls" : 
            {
                base : "/data/resources/shaderbuilder/materials/",
                list :
                [
                    "checker-simple",
                    "checker-redblack",
                    "checker-worldxy",
                    "solid-green"
                ]
            },        
            "simple" : {
                solid : { color : [ .2, .2, .7 ] }
            },           
        },
        objects : 
        [
            { heightmap : {
                position    : [ 0, 0, 0.0 ],
                material    : "checker-worldxy",
                scale       : 8,
                width       : 64,
                height      : 64,
                sampler     : function (x, y, w, h) {
                    var hx =  Math.cos(4 * Math.PI * x/w);
                    var hy = Math.sin(4 * Math.PI * y/h);
                    return (hx + hy) / 64;
                }
            }},
        ]
    };
    
    var canvas = $("#canvas").get(0);
    
    var engine = new sc3.Engine;
    engine.renderer = new sc3.Renderer(canvas);
    engine.renderer.loadBundle("/data/resources/shaderbuilder/shaderbuilder-bundle.json");
    engine.add("scene", sceneDesc);
        
    var dataUrl = "/data/resources/shaders/";    
    engine.renderer.loadShader(dataUrl, "simple.vert", "simple-blue.frag");
    engine.renderer.ready(function()
    {            
        var camera = _.first( engine.select(".camera") );
    
        engine.interval(function(ctx) {
            var instances = engine.select(".renderable");
            camera.update(2 * Math.PI * ctx.virttime / 20000);
            engine.renderer.renderScene(camera, instances);
        }, 1000 / 30);
        
        
        engine.physics = new Physics;        
        engine.tracer = new TracerPlugin;
        
        _.each([engine.physics, engine.tracer], function (system, key) {
            if (system.initialize)
                system.initialize(engine);
        });

        function addRandomSphere()
        {
            var x = sc3.math.randomf(-2, 2);
            var y = sc3.math.randomf(-2, 2);
            var z = .5;
            var obj = { unit_sphere :
            {
                 classes    : [ "trace renderable" ],
                 position   : [ x, y, z ], 
                 scale      : .1,
                 material   : "checker-redblack" 
            }};
            engine.add("object", obj);
        }
        
        sc3.util.async_repeat(0, 64, { delay : 100 }, addRandomSphere);
    });
});

Setup