(Move your mouse to paint some light into the darkness)

Light Painter

					
Painter = function( container, width, height )
{
    var _container = container;
    var _width = width;
    var _height = height;

    var _mouse = { x: 0, y: 0 };
    var _down = false;

    var _3DClock = null;
    var _3DRenderer = null;
    var _3DScene = null;
    var _3DCamera = null;
    var _3DRaycaster = null;
    var _3DMouse = null;
    var _3DObjects = [];

    function init()
    {
        init3D();

        _container.onmouseup = onMouseUp;
        _container.onmousedown = onMouseDown;
        _container.onmousemove = onMouseMove;

        render();
    }

    function init3D()
    {
        _3DClock = new THREE.Clock();
        _3DRaycaster = new THREE.Raycaster();
        _3DMouse = new THREE.Vector2();

        _3DRenderer = new THREE.WebGLRenderer();
        _3DRenderer.setSize( _width, _height );
        _3DRenderer.setPixelRatio( window.devicePixelRatio );

        _3DScene = new THREE.Scene();
        _3DCamera = new THREE.PerspectiveCamera( 45, _width / _height, 1, 1000 );
        _3DCamera.lookAt( _3DScene.position );

        _3DObjects.push( createCube( 4, 0, 0, 10, 10, 10 ) );

        //...

        container.appendChild( _3DRenderer.domElement );
    }

    this.resizeTo = function( width, height )
    {
        _width = width;
        _height = height;

        _3DCamera.aspect = _width / _height;
        _3DCamera.updateProjectionMatrix();
        _3DRenderer.setSize( _width, _height );
    };

    function render()
    {
       _3DRenderer.render( _3DScene, _3DCamera );

       //...

        if( _down )
        {
            paint();
        }

        requestAnimationFrame( render );
    }

    function getMouse( event )
    {
        var rect = event.currentTarget.getBoundingClientRect();

        // normalized coordinates
        _mouse.x = ( event.clientX - rect.left ) / rect.width;
        _mouse.y = ( event.clientY - rect.top ) / rect.height;

        // 3d space
        _3DMouse.x = ( _mouse.x * 2 ) - 1;
        _3DMouse.y = -( _mouse.y * 2 ) + 1;
    }

    var paint = function()
    {
        _3DRaycaster.setFromCamera( _3DMouse, _3DCamera );

        var intersects = _3DRaycaster.intersectObjects( _3DScene.children );

        for( var i = 0; i < intersects.length; i++ )
        {
            var intersect = intersects[ i ];

            var index = Math.floor( intersect.faceIndex / 2 );
            var canvas = intersect.object.meta.canvases[ index ];

            var uv = intersect.uv;

            canvas.draw( uv.x, 1 - uv.y );
        }
    };

    function onMouseDown( event )
    {
        getMouse( event );

        _down = true;
    }

    function onMouseUp( event )
    {
        getMouse( event );

        _down = false;
    }

    function onMouseMove( event )
    {
        getMouse( event );
    }

    init();
};

PaintTexture = function( parentTexture )
{
    this.main = document.createElement( "canvas" );
    this.main.width = 512;
    this.main.height = 512;

    this.temp = document.createElement( "canvas" );
    this.temp.width = 512;
    this.temp.height = 512;

    this.mainContext = this.main.getContext( "2d" );
    this.tempContext = this.temp.getContext( "2d" );

    this.parentTexture = parentTexture;
    this.parentTexture.image = this.main;
};

PaintTexture.prototype.draw = function( x, y )
{
    if( !this.mainContext || !this.tempContext )
    {
        return;
    }

    // from normalized to absolute space
    x = x * this.main.width;
    y = y * this.main.height;

    var n = 10;

    while( --n > 0 )
    {
        var ang = Math.random() * Math.PI * 2;
        var rad = Math.random() * 70;
        var dot = ( Math.random() > 0.5 ) ? 2 + Math.random() * 8 : 2;

        this.tempContext.beginPath();
        this.tempContext.arc( x + rad * Math.cos( ang ), y + rad * Math.sin( ang ), dot, 0, Math.PI * 2 );
        this.tempContext.closePath();
        this.tempContext.fillStyle = "white";
        this.tempContext.fill();
    }

    this.mainContext.drawImage( this.temp, 0, 0 );
    this.tempContext.clearRect( 0, 0, this.main.width, this.main.height );

    this.parentTexture.needsUpdate = true;
};