Last active
December 11, 2015 00:38
-
-
Save mrdoob/4517434 to your computer and use it in GitHub Desktop.
Revisions
-
mrdoob revised this gist
Jan 12, 2013 . 1 changed file with 2 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -152,6 +152,8 @@ THREE.SoftwareRenderer = function () { var y = Math.min( recty1, prevrecty1 ); var width = Math.max( rectx2, prevrectx2 ) - x; var height = Math.max( recty2, prevrecty2 ) - y; // debug; draw zbuffer for ( var i = 0, l = zbuffer.length; i < l; i += 4 ) { -
mrdoob created this gist
Jan 12, 2013 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,435 @@ /** * @author mrdoob / http://mrdoob.com/ * @author mraleph / http://mrale.ph/ */ THREE.SoftwareRenderer = function () { console.log( 'THREE.SoftwareRenderer', THREE.REVISION ); var canvas = document.createElement( 'canvas' ); var context = canvas.getContext( '2d' ); var canvasWidth = canvas.width; var canvasHeight = canvas.height; var canvasWidthHalf = canvasWidth / 2; var canvasHeightHalf = canvasHeight / 2; var imagedata = context.getImageData( 0, 0, canvas.width, canvas.height ); var data = imagedata.data; var zbuffer = new Float32Array( data.length ); var blocksize = 8; var canvasWBlocks = Math.floor( ( canvasWidth + blocksize - 1 ) / blocksize ); var canvasHBlocks = Math.floor( ( canvasHeight + blocksize - 1 ) / blocksize ); var blocks = new Float32Array( canvasWBlocks * canvasHBlocks ); var rectx1 = Infinity, recty1 = Infinity; var rectx2 = 0, recty2 = 0; var prevrectx1 = Infinity, prevrecty1 = Infinity; var prevrectx2 = 0, prevrecty2 = 0; var projector = new THREE.Projector(); this.domElement = canvas; this.autoClear = true; this.setSize = function ( width, height ) { canvasWidth = Math.floor( width / blocksize ) * blocksize; canvasHeight = Math.floor( height / blocksize ) * blocksize; canvasWidthHalf = canvasWidth / 2; canvasHeightHalf = canvasHeight / 2; canvas.width = canvasWidth; canvas.height = canvasHeight; imagedata = context.getImageData( 0, 0, canvasWidth, canvasHeight ); data = imagedata.data; zbuffer = new Float32Array( data.length ); canvasWBlocks = Math.floor( ( canvasWidth + blocksize - 1 ) / blocksize ); canvasHBlocks = Math.floor( ( canvasHeight + blocksize - 1 ) / blocksize ); blocks = new Float32Array( canvasWBlocks * canvasHBlocks ) }; this.clear = function () { clearRectangle( prevrectx1, prevrecty1, prevrectx2, prevrecty2 ); for ( var i = 0, l = blocks.length; i < l; i ++ ) { blocks[ i ] = 1; } for ( var i = 0, l = zbuffer.length; i < l; i ++ ) { zbuffer[ i ] = 1; } }; this.render = function ( scene, camera ) { rectx1 = Infinity; recty1 = Infinity; rectx2 = 0; recty2 = 0; if ( this.autoClear ) this.clear(); var renderData = projector.projectScene( scene, camera ); var elements = renderData.elements; for ( var e = 0, el = elements.length; e < el; e ++ ) { var element = elements[ e ]; if ( element instanceof THREE.RenderableFace3 ) { drawTriangle( element.v1.positionScreen, element.v2.positionScreen, element.v3.positionScreen, function ( offset, u, v ) { data[ offset ] = u; data[ offset + 1 ] = v; data[ offset + 2 ] = 0; data[ offset + 3 ] = 255; } ) } else if ( element instanceof THREE.RenderableFace4 ) { drawTriangle( element.v1.positionScreen, element.v2.positionScreen, element.v4.positionScreen, function ( offset, u, v ) { data[ offset ] = u; data[ offset + 1 ] = v; data[ offset + 2 ] = 0; data[ offset + 3 ] = 255; } ); drawTriangle( element.v2.positionScreen, element.v3.positionScreen, element.v4.positionScreen, function ( offset, u, v ) { data[ offset ] = u; data[ offset + 1 ] = v; data[ offset + 2 ] = 0; data[ offset + 3 ] = 255; } ); } } var x = Math.min( rectx1, prevrectx1 ); var y = Math.min( recty1, prevrecty1 ); var width = Math.max( rectx2, prevrectx2 ) - x; var height = Math.max( recty2, prevrecty2 ) - y; for ( var i = 0, l = zbuffer.length; i < l; i += 4 ) { data[ i ] = zbuffer[ i ] * 255; data[ i + 1 ] = zbuffer[ i ] * 255; data[ i + 2 ] = zbuffer[ i ] * 255; } if ( x !== Infinity ) { context.putImageData( imagedata, 0, 0, x, y, width, height ); } prevrectx1 = rectx1; prevrecty1 = recty1; prevrectx2 = rectx2; prevrecty2 = recty2; }; function numericalSort( a, b ) { return a.z - b.z; } function clearRectangle( x1, y1, x2, y2 ) { var xmin = Math.max( Math.min( x1, x2 ), 0 ); var xmax = Math.min( Math.max( x1, x2 ), canvasWidth ); var ymin = Math.max( Math.min( y1, y2 ), 0 ); var ymax = Math.min( Math.max( y1, y2 ), canvasHeight ); var offset = ( xmin + ymin * canvasWidth - 1 ) * 4 + 3; var linestep = ( canvasWidth - ( xmax - xmin ) ) * 4; for ( var y = ymin; y < ymax; y ++ ) { for ( var x = xmin; x < xmax; x ++ ) { data[ offset += 4 ] = 0; } offset += linestep; } } function drawTriangle( v1, v2, v3, shader ) { var z1 = v1.z; var z2 = v2.z; var z3 = v3.z; var dz12 = z1 - z2; var dz32 = z3 - z2; var minz = Math.min( z1, Math.min( z2, z3 ) ); var maxz = Math.max( z1, Math.max( z2, z3 ) ); // https://gist.github.com/2486101 // explanation: http://pouet.net/topic.php?which=8760&page=1 // 28.4 fixed-point coordinates var x1 = ( 16 * ( v1.x * canvasWidthHalf + canvasWidthHalf ) ) | 0; var x2 = ( 16 * ( v2.x * canvasWidthHalf + canvasWidthHalf ) ) | 0; var x3 = ( 16 * ( v3.x * canvasWidthHalf + canvasWidthHalf ) ) | 0; var y1 = ( 16 * ( - v1.y * canvasHeightHalf + canvasHeightHalf ) ) | 0; var y2 = ( 16 * ( - v2.y * canvasHeightHalf + canvasHeightHalf ) ) | 0; var y3 = ( 16 * ( - v3.y * canvasHeightHalf + canvasHeightHalf ) ) | 0; // Deltas var dx12 = x1 - x2, dy12 = y2 - y1; var dx23 = x2 - x3, dy23 = y3 - y2; var dx31 = x3 - x1, dy31 = y1 - y3; // Bounding rectangle var minx = Math.max( ( Math.min( x1, x2, x3 ) + 0xf ) >> 4, 0 ); var maxx = Math.min( ( Math.max( x1, x2, x3 ) + 0xf ) >> 4, canvasWidth ); var miny = Math.max( ( Math.min( y1, y2, y3 ) + 0xf ) >> 4, 0 ); var maxy = Math.min( ( Math.max( y1, y2, y3 ) + 0xf ) >> 4, canvasHeight ); rectx1 = Math.min( minx, rectx1 ); rectx2 = Math.max( maxx, rectx2 ); recty1 = Math.min( miny, recty1 ); recty2 = Math.max( maxy, recty2 ); // Block size, standard 8x8 (must be power of two) var q = blocksize; // Start in corner of 8x8 block minx &= ~(q - 1); miny &= ~(q - 1); // Constant part of half-edge functions var c1 = dy12 * ((minx << 4) - x1) + dx12 * ((miny << 4) - y1); var c2 = dy23 * ((minx << 4) - x2) + dx23 * ((miny << 4) - y2); var c3 = dy31 * ((minx << 4) - x3) + dx31 * ((miny << 4) - y3); // Correct for fill convention if ( dy12 > 0 || ( dy12 == 0 && dx12 > 0 ) ) c1 ++; if ( dy23 > 0 || ( dy23 == 0 && dx23 > 0 ) ) c2 ++; if ( dy31 > 0 || ( dy31 == 0 && dx31 > 0 ) ) c3 ++; // Note this doesn't kill subpixel precision, but only because we test for >=0 (not >0). // It's a bit subtle. :) c1 = (c1 - 1) >> 4; c2 = (c2 - 1) >> 4; c3 = (c3 - 1) >> 4; // Set up min/max corners var qm1 = q - 1; // for convenience var nmin1 = 0, nmax1 = 0; var nmin2 = 0, nmax2 = 0; var nmin3 = 0, nmax3 = 0; if (dx12 >= 0) nmax1 -= qm1*dx12; else nmin1 -= qm1*dx12; if (dy12 >= 0) nmax1 -= qm1*dy12; else nmin1 -= qm1*dy12; if (dx23 >= 0) nmax2 -= qm1*dx23; else nmin2 -= qm1*dx23; if (dy23 >= 0) nmax2 -= qm1*dy23; else nmin2 -= qm1*dy23; if (dx31 >= 0) nmax3 -= qm1*dx31; else nmin3 -= qm1*dx31; if (dy31 >= 0) nmax3 -= qm1*dy31; else nmin3 -= qm1*dy31; // Loop through blocks var linestep = ( canvasWidth - q ) * 4; var scale = 255.0 / (c1 + c2 + c3); var cb1 = c1; var cb2 = c2; var cb3 = c3; var qstep = -q; var e1x = qstep * dy12; var e2x = qstep * dy23; var e3x = qstep * dy31; var x0 = minx; for ( var y0 = miny; y0 < maxy; y0 += q ) { // New block line - keep hunting for tri outer edge in old block line dir while ( x0 >= minx && x0 < maxx && cb1 >= nmax1 && cb2 >= nmax2 && cb3 >= nmax3 ) { x0 += qstep; cb1 += e1x; cb2 += e2x; cb3 += e3x; } // Okay, we're now in a block we know is outside. Reverse direction and go into main loop. qstep = -qstep; e1x = -e1x; e2x = -e2x; e3x = -e3x; while ( 1 ) { // Step everything x0 += qstep; cb1 += e1x; cb2 += e2x; cb3 += e3x; // We're done with this block line when at least one edge completely out // If an edge function is too small and decreasing in the current traversal // dir, we're done with this line. if (x0 < minx || x0 >= maxx) break; if (cb1 < nmax1) if (e1x < 0) break; else continue; if (cb2 < nmax2) if (e2x < 0) break; else continue; if (cb3 < nmax3) if (e3x < 0) break; else continue; // We can skip this block if it's already fully covered var blockX = (x0 / q) | 0; var blockY = (y0 / q) | 0; var blockId = blockX + blockY * canvasWBlocks; if ( blocks[ blockId ] < minz ) continue; // Offset at top-left corner var offset = ( x0 + y0 * canvasWidth ) * 4; // Accept whole block when fully covered if ( cb1 >= nmin1 && cb2 >= nmin2 && cb3 >= nmin3 ) { var cy1 = cb1; var cy2 = cb2; for ( var iy = 0; iy < q; iy ++ ) { var cx1 = cy1; var cx2 = cy2; for ( var ix = 0; ix < q; ix ++ ) { var u = cx1 * scale; var v = cx2 * scale; var z = z1 + ( u * dz12 ) + ( v * dz32 ); zbuffer[ offset ] = z; shader( offset, u, v ); cx1 += dy12; cx2 += dy23; offset += 4; } cy1 += dx12; cy2 += dx23; offset += linestep; } blocks[ blockId ] = maxz; } else { // Partially covered block var cy1 = cb1; var cy2 = cb2; var cy3 = cb3; for ( var iy = 0; iy < q; iy ++ ) { var cx1 = cy1; var cx2 = cy2; var cx3 = cy3; for ( var ix = 0; ix < q; ix ++ ) { if ( ( cx1 | cx2 | cx3 ) >= 0 ) { var u = cx1 * scale; var v = cx2 * scale; var z = z1 + ( u * dz12 ) + ( v * dz32 ); // if ( zbuffer[ offset ] > z ) { zbuffer[ offset ] = z; shader( offset, u, v ); // } } cx1 += dy12; cx2 += dy23; cx3 += dy31; offset += 4; } cy1 += dx12; cy2 += dx23; cy3 += dx31; offset += linestep; } } } // Advance to next row of blocks cb1 += q*dx12; cb2 += q*dx23; cb3 += q*dx31; } } }; This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,512 @@ /** * @author Eberhard Graether / http://egraether.com/ */ THREE.TrackballControls = function ( object, domElement ) { THREE.EventDispatcher.call( this ); var _this = this; var STATE = { NONE: -1, ROTATE: 0, ZOOM: 1, PAN: 2, TOUCH_ROTATE: 3, TOUCH_ZOOM: 4, TOUCH_PAN: 5 }; this.object = object; this.domElement = ( domElement !== undefined ) ? domElement : document; // API this.enabled = true; this.screen = { width: 0, height: 0, offsetLeft: 0, offsetTop: 0 }; this.radius = ( this.screen.width + this.screen.height ) / 4; this.rotateSpeed = 1.0; this.zoomSpeed = 1.2; this.panSpeed = 0.3; this.noRotate = false; this.noZoom = false; this.noPan = false; this.staticMoving = false; this.dynamicDampingFactor = 0.2; this.minDistance = 0; this.maxDistance = Infinity; this.keys = [ 65 /*A*/, 83 /*S*/, 68 /*D*/ ]; // internals this.target = new THREE.Vector3(); var lastPosition = new THREE.Vector3(); var _state = STATE.NONE, _prevState = STATE.NONE, _eye = new THREE.Vector3(), _rotateStart = new THREE.Vector3(), _rotateEnd = new THREE.Vector3(), _zoomStart = new THREE.Vector2(), _zoomEnd = new THREE.Vector2(), _touchZoomDistanceStart = 0, _touchZoomDistanceEnd = 0, _panStart = new THREE.Vector2(), _panEnd = new THREE.Vector2(); // events var changeEvent = { type: 'change' }; // methods this.handleResize = function () { this.screen.width = window.innerWidth; this.screen.height = window.innerHeight; this.screen.offsetLeft = 0; this.screen.offsetTop = 0; this.radius = ( this.screen.width + this.screen.height ) / 4; }; this.handleEvent = function ( event ) { if ( typeof this[ event.type ] == 'function' ) { this[ event.type ]( event ); } }; this.getMouseOnScreen = function ( clientX, clientY ) { return new THREE.Vector2( ( clientX - _this.screen.offsetLeft ) / _this.radius * 0.5, ( clientY - _this.screen.offsetTop ) / _this.radius * 0.5 ); }; this.getMouseProjectionOnBall = function ( clientX, clientY ) { var mouseOnBall = new THREE.Vector3( ( clientX - _this.screen.width * 0.5 - _this.screen.offsetLeft ) / _this.radius, ( _this.screen.height * 0.5 + _this.screen.offsetTop - clientY ) / _this.radius, 0.0 ); var length = mouseOnBall.length(); if ( length > 1.0 ) { mouseOnBall.normalize(); } else { mouseOnBall.z = Math.sqrt( 1.0 - length * length ); } _eye.copy( _this.object.position ).sub( _this.target ); var projection = _this.object.up.clone().setLength( mouseOnBall.y ); projection.add( _this.object.up.clone().cross( _eye ).setLength( mouseOnBall.x ) ); projection.add( _eye.setLength( mouseOnBall.z ) ); return projection; }; this.rotateCamera = function () { var angle = Math.acos( _rotateStart.dot( _rotateEnd ) / _rotateStart.length() / _rotateEnd.length() ); if ( angle ) { var axis = ( new THREE.Vector3() ).crossVectors( _rotateStart, _rotateEnd ).normalize(), quaternion = new THREE.Quaternion(); angle *= _this.rotateSpeed; quaternion.setFromAxisAngle( axis, -angle ); _eye.applyQuaternion( quaternion ); _this.object.up.applyQuaternion( quaternion ); _rotateEnd.applyQuaternion( quaternion ); if ( _this.staticMoving ) { _rotateStart.copy( _rotateEnd ); } else { quaternion.setFromAxisAngle( axis, angle * ( _this.dynamicDampingFactor - 1.0 ) ); _rotateStart.applyQuaternion( quaternion ); } } }; this.zoomCamera = function () { if ( _state === STATE.TOUCH_ZOOM ) { var factor = _touchZoomDistanceStart / _touchZoomDistanceEnd; _touchZoomDistanceStart = _touchZoomDistanceEnd; _eye.multiplyScalar( factor ); } else { var factor = 1.0 + ( _zoomEnd.y - _zoomStart.y ) * _this.zoomSpeed; if ( factor !== 1.0 && factor > 0.0 ) { _eye.multiplyScalar( factor ); if ( _this.staticMoving ) { _zoomStart.copy( _zoomEnd ); } else { _zoomStart.y += ( _zoomEnd.y - _zoomStart.y ) * this.dynamicDampingFactor; } } } }; this.panCamera = function () { var mouseChange = _panEnd.clone().sub( _panStart ); if ( mouseChange.lengthSq() ) { mouseChange.multiplyScalar( _eye.length() * _this.panSpeed ); var pan = _eye.clone().cross( _this.object.up ).setLength( mouseChange.x ); pan.add( _this.object.up.clone().setLength( mouseChange.y ) ); _this.object.position.add( pan ); _this.target.add( pan ); if ( _this.staticMoving ) { _panStart = _panEnd; } else { _panStart.add( mouseChange.subVectors( _panEnd, _panStart ).multiplyScalar( _this.dynamicDampingFactor ) ); } } }; this.checkDistances = function () { if ( !_this.noZoom || !_this.noPan ) { if ( _this.object.position.lengthSq() > _this.maxDistance * _this.maxDistance ) { _this.object.position.setLength( _this.maxDistance ); } if ( _eye.lengthSq() < _this.minDistance * _this.minDistance ) { _this.object.position.addVectors( _this.target, _eye.setLength( _this.minDistance ) ); } } }; this.update = function () { _eye.subVectors( _this.object.position, _this.target ); if ( !_this.noRotate ) { _this.rotateCamera(); } if ( !_this.noZoom ) { _this.zoomCamera(); } if ( !_this.noPan ) { _this.panCamera(); } _this.object.position.addVectors( _this.target, _eye ); _this.checkDistances(); _this.object.lookAt( _this.target ); if ( lastPosition.distanceToSquared( _this.object.position ) > 0 ) { _this.dispatchEvent( changeEvent ); lastPosition.copy( _this.object.position ); } }; // listeners function keydown( event ) { if ( _this.enabled === false ) return; window.removeEventListener( 'keydown', keydown ); _prevState = _state; if ( _state !== STATE.NONE ) { return; } else if ( event.keyCode === _this.keys[ STATE.ROTATE ] && !_this.noRotate ) { _state = STATE.ROTATE; } else if ( event.keyCode === _this.keys[ STATE.ZOOM ] && !_this.noZoom ) { _state = STATE.ZOOM; } else if ( event.keyCode === _this.keys[ STATE.PAN ] && !_this.noPan ) { _state = STATE.PAN; } } function keyup( event ) { if ( _this.enabled === false ) return; _state = _prevState; window.addEventListener( 'keydown', keydown, false ); } function mousedown( event ) { if ( _this.enabled === false ) return; event.preventDefault(); event.stopPropagation(); if ( _state === STATE.NONE ) { _state = event.button; } if ( _state === STATE.ROTATE && !_this.noRotate ) { _rotateStart = _rotateEnd = _this.getMouseProjectionOnBall( event.clientX, event.clientY ); } else if ( _state === STATE.ZOOM && !_this.noZoom ) { _zoomStart = _zoomEnd = _this.getMouseOnScreen( event.clientX, event.clientY ); } else if ( _state === STATE.PAN && !_this.noPan ) { _panStart = _panEnd = _this.getMouseOnScreen( event.clientX, event.clientY ); } document.addEventListener( 'mousemove', mousemove, false ); document.addEventListener( 'mouseup', mouseup, false ); } function mousemove( event ) { if ( _this.enabled === false ) return; event.preventDefault(); event.stopPropagation(); if ( _state === STATE.ROTATE && !_this.noRotate ) { _rotateEnd = _this.getMouseProjectionOnBall( event.clientX, event.clientY ); } else if ( _state === STATE.ZOOM && !_this.noZoom ) { _zoomEnd = _this.getMouseOnScreen( event.clientX, event.clientY ); } else if ( _state === STATE.PAN && !_this.noPan ) { _panEnd = _this.getMouseOnScreen( event.clientX, event.clientY ); } } function mouseup( event ) { if ( _this.enabled === false ) return; event.preventDefault(); event.stopPropagation(); _state = STATE.NONE; document.removeEventListener( 'mousemove', mousemove ); document.removeEventListener( 'mouseup', mouseup ); } function mousewheel( event ) { if ( _this.enabled === false ) return; event.preventDefault(); event.stopPropagation(); var delta = 0; if ( event.wheelDelta ) { // WebKit / Opera / Explorer 9 delta = event.wheelDelta / 40; } else if ( event.detail ) { // Firefox delta = - event.detail / 3; } _zoomStart.y += ( 1 / delta ) * 0.05; } function touchstart( event ) { if ( _this.enabled === false ) return; switch ( event.touches.length ) { case 1: _state = STATE.TOUCH_ROTATE; _rotateStart = _rotateEnd = _this.getMouseProjectionOnBall( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); break; case 2: _state = STATE.TOUCH_ZOOM; var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; _touchZoomDistanceEnd = _touchZoomDistanceStart = Math.sqrt( dx * dx + dy * dy ); break; case 3: _state = STATE.TOUCH_PAN; _panStart = _panEnd = _this.getMouseOnScreen( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); break; default: _state = STATE.NONE; } } function touchmove( event ) { if ( _this.enabled === false ) return; event.preventDefault(); event.stopPropagation(); switch ( event.touches.length ) { case 1: _rotateEnd = _this.getMouseProjectionOnBall( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); break; case 2: var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; _touchZoomDistanceEnd = Math.sqrt( dx * dx + dy * dy ) break; case 3: _panEnd = _this.getMouseOnScreen( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); break; default: _state = STATE.NONE; } } function touchend( event ) { if ( _this.enabled === false ) return; switch ( event.touches.length ) { case 1: _rotateStart = _rotateEnd = _this.getMouseProjectionOnBall( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); break; case 2: _touchZoomDistanceStart = _touchZoomDistanceEnd = 0; break; case 3: _panStart = _panEnd = _this.getMouseOnScreen( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); break; } _state = STATE.NONE; } this.domElement.addEventListener( 'contextmenu', function ( event ) { event.preventDefault(); }, false ); this.domElement.addEventListener( 'mousedown', mousedown, false ); this.domElement.addEventListener( 'mousewheel', mousewheel, false ); this.domElement.addEventListener( 'DOMMouseScroll', mousewheel, false ); // firefox this.domElement.addEventListener( 'touchstart', touchstart, false ); this.domElement.addEventListener( 'touchend', touchend, false ); this.domElement.addEventListener( 'touchmove', touchmove, false ); window.addEventListener( 'keydown', keydown, false ); window.addEventListener( 'keyup', keyup, false ); this.handleResize(); }; This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,134 @@ <!DOCTYPE html> <html lang="en"> <head> <title>three.js - software renderer</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"> <style> body { font-family: Monospace; background-color: #f0f0f0; margin: 0px; overflow: hidden; } </style> </head> <body> <script src="three.min.js"></script> <script src="SoftwareRenderer.js"></script> <script src="TrackballControls.js"></script> <script src="stats.min.js"></script> <script> var container, stats; var camera, controls, scene, renderer; var sphere, plane; var start = Date.now(); init(); animate(); function init() { container = document.createElement( 'div' ); document.body.appendChild( container ); var info = document.createElement( 'div' ); info.style.position = 'absolute'; info.style.top = '10px'; info.style.width = '100%'; info.style.textAlign = 'center'; info.innerHTML = '<a href="https://github.com/mrdoob/three.js/" target="_blank">three.js<a/> - software renderer<br/>drag to change the point of view'; container.appendChild( info ); camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 5000 ); camera.position.y = 150; camera.position.z = 400; controls = new THREE.TrackballControls( camera ); scene = new THREE.Scene(); sphere = new THREE.Mesh( new THREE.TorusKnotGeometry( 150 ), new THREE.MeshBasicMaterial() ); // sphere = new THREE.Mesh( new THREE.IcosahedronGeometry( 150, 3 ), new THREE.MeshBasicMaterial() ); scene.add( sphere ); // Plane plane = new THREE.Mesh( new THREE.PlaneGeometry( 200, 200 ), new THREE.MeshBasicMaterial( { color: 0xe0e0e0 } ) ); plane.geometry.applyMatrix( new THREE.Matrix4().makeRotationX( - Math.PI / 2 ) ); plane.position.y = - 150; scene.add( plane ); var geometry = new THREE.Geometry(); geometry.vertices.push( new THREE.Vector3( - 125, 100, 0 ) ); geometry.vertices.push( new THREE.Vector3( - 300, -100, 0 ) ); geometry.vertices.push( new THREE.Vector3( 0, -100, 0 ) ); geometry.vertices.push( new THREE.Vector3( 125, 100, 0 ) ); geometry.vertices.push( new THREE.Vector3( 0, -100, 0 ) ); geometry.vertices.push( new THREE.Vector3( 300, -100, 0 ) ); geometry.faces.push( new THREE.Face3( 0, 1, 2 ) ); geometry.faces.push( new THREE.Face3( 3, 4, 5 ) ); var triangle = new THREE.Mesh( geometry, new THREE.MeshBasicMaterial( { color: 0xff0000 } ) ); scene.add( triangle ); renderer = new THREE.SoftwareRenderer(); renderer.setSize( window.innerWidth, window.innerHeight ); container.appendChild( renderer.domElement ); stats = new Stats(); stats.domElement.style.position = 'absolute'; stats.domElement.style.top = '0px'; container.appendChild( stats.domElement ); // window.addEventListener( 'resize', onWindowResize, false ); } function onWindowResize() { camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize( window.innerWidth, window.innerHeight ); } // function animate() { requestAnimationFrame( animate ); render(); stats.update(); } function render() { var timer = Date.now() - start; sphere.position.y = Math.abs( Math.sin( timer * 0.002 ) ) * 150; sphere.rotation.x = timer * 0.0003; sphere.rotation.z = timer * 0.0002; controls.update(); renderer.render( scene, camera ); } </script> </body> </html> This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,6 @@ // stats.js - https://github.com/mrdoob/stats.js var Stats=function(){var l=Date.now(),m=l,g=0,n=Infinity,o=0,h=0,p=Infinity,q=0,r=0,s=0,f=document.createElement("div");f.id="stats";f.addEventListener("mousedown",function(b){b.preventDefault();t(++s%2)},!1);f.style.cssText="width:80px;opacity:0.9;cursor:pointer";var a=document.createElement("div");a.id="fps";a.style.cssText="padding:0 0 3px 3px;text-align:left;background-color:#002";f.appendChild(a);var i=document.createElement("div");i.id="fpsText";i.style.cssText="color:#0ff;font-family:Helvetica,Arial,sans-serif;font-size:9px;font-weight:bold;line-height:15px"; i.innerHTML="FPS";a.appendChild(i);var c=document.createElement("div");c.id="fpsGraph";c.style.cssText="position:relative;width:74px;height:30px;background-color:#0ff";for(a.appendChild(c);74>c.children.length;){var j=document.createElement("span");j.style.cssText="width:1px;height:30px;float:left;background-color:#113";c.appendChild(j)}var d=document.createElement("div");d.id="ms";d.style.cssText="padding:0 0 3px 3px;text-align:left;background-color:#020;display:none";f.appendChild(d);var k=document.createElement("div"); k.id="msText";k.style.cssText="color:#0f0;font-family:Helvetica,Arial,sans-serif;font-size:9px;font-weight:bold;line-height:15px";k.innerHTML="MS";d.appendChild(k);var e=document.createElement("div");e.id="msGraph";e.style.cssText="position:relative;width:74px;height:30px;background-color:#0f0";for(d.appendChild(e);74>e.children.length;)j=document.createElement("span"),j.style.cssText="width:1px;height:30px;float:left;background-color:#131",e.appendChild(j);var t=function(b){s=b;switch(s){case 0:a.style.display= "block";d.style.display="none";break;case 1:a.style.display="none",d.style.display="block"}};return{REVISION:11,domElement:f,setMode:t,begin:function(){l=Date.now()},end:function(){var b=Date.now();g=b-l;n=Math.min(n,g);o=Math.max(o,g);k.textContent=g+" MS ("+n+"-"+o+")";var a=Math.min(30,30-30*(g/200));e.appendChild(e.firstChild).style.height=a+"px";r++;b>m+1E3&&(h=Math.round(1E3*r/(b-m)),p=Math.min(p,h),q=Math.max(q,h),i.textContent=h+" FPS ("+p+"-"+q+")",a=Math.min(30,30-30*(h/100)),c.appendChild(c.firstChild).style.height= a+"px",m=b,r=0);return b},update:function(){l=this.end()}}};