123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548 |
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <title>three.js webgl - Mesh Spray</title>
- <meta charset="utf-8">
- <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
- <link type="text/css" rel="stylesheet" href="main.css">
- <style>
- #glFullscreen {
- width: 100%;
- height: 100vh;
- min-width: 640px;
- min-height: 360px;
- position: relative;
- overflow: hidden;
- z-index: 0;
- }
- #example {
- width: 100%;
- height: 100%;
- top: 0;
- left: 0;
- background-color: #000000;
- }
- #feedback {
- color: darkorange;
- }
- #dat {
- user-select: none;
- position: absolute;
- left: 0;
- top: 0;
- z-Index: 200;
- }
- </style>
- </head>
- <body>
- <div id="glFullscreen">
- <canvas id="example"></canvas>
- </div>
- <div id="dat">
- </div>
- <div id="info">
- <a href="http://threejs.org" target="_blank">three.js</a> - Mesh Spray
- <div id="feedback"></div>
- </div>
- <script src="../build/three.js"></script>
- <script src="js/controls/TrackballControls.js"></script>
- <script src="js/libs/dat.gui.min.js"></script>
- <script src="js/loaders/LoaderSupport.js"></script>
- <script>
- 'use strict';
- var MeshSpray = {};
- MeshSpray.Loader = function ( manager ) {
- this.manager = THREE.LoaderSupport.Validator.verifyInput( manager, THREE.DefaultLoadingManager );
- this.logging = {
- enabled: true,
- debug: false
- };
- this.instanceNo = 0;
- this.loaderRootNode = new THREE.Group();
- this.meshBuilder = new THREE.LoaderSupport.MeshBuilder();
- this.callbacks = new THREE.LoaderSupport.Callbacks();
- this.workerSupport = null;
- };
- MeshSpray.Loader.prototype = {
- constructor: MeshSpray.Loader,
- setLogging: function ( enabled, debug ) {
- this.logging.enabled = enabled === true;
- this.logging.debug = debug === true;
- this.meshBuilder.setLogging( this.logging.enabled, this.logging.debug );
- },
- setStreamMeshesTo: function ( streamMeshesTo ) {
- this.loaderRootNode = THREE.LoaderSupport.Validator.verifyInput( streamMeshesTo, this.loaderRootNode );
- },
- setForceWorkerDataCopy: function ( forceWorkerDataCopy ) {
- // nothing to do here
- },
- run: function ( prepData, workerSupportExternal ) {
- if ( THREE.LoaderSupport.Validator.isValid( workerSupportExternal ) ) {
- this.workerSupport = workerSupportExternal;
- this.logging.enabled = this.workerSupport.logging.enabled;
- this.logging.debug = this.workerSupport.logging.debug;
- } else {
- this.workerSupport = THREE.LoaderSupport.Validator.verifyInput( this.workerSupport, new THREE.LoaderSupport.WorkerSupport() );
- }
- if ( this.logging.enabled ) console.time( 'MeshSpray' + this.instanceNo );
- this._applyPrepData( prepData );
- this.meshBuilder.init();
- var scope = this;
- var scopeBuilderFunc = function ( payload ) {
- var meshes = scope.meshBuilder.processPayload( payload );
- var mesh;
- for ( var i in meshes ) {
- mesh = meshes[ i ];
- scope.loaderRootNode.add( mesh );
- }
- };
- var scopeFuncComplete = function ( message ) {
- var callback = scope.callbacks.onLoad;
- if ( THREE.LoaderSupport.Validator.isValid( callback ) ) callback(
- {
- detail: {
- loaderRootNode: scope.loaderRootNode,
- modelName: scope.modelName,
- instanceNo: scope.instanceNo
- }
- }
- );
- if ( scope.logging.enabled ) console.timeEnd( 'MeshSpray' + scope.instanceNo );
- };
- var buildCode = function ( codeSerializer ) {
- var workerCode = '';
- workerCode += '/**\n';
- workerCode += ' * This code was constructed by MeshSpray buildCode.\n';
- workerCode += ' */\n\n';
- workerCode += 'THREE.LoaderSupport = {};\n\n';
- workerCode += 'MeshSpray = {};\n\n';
- workerCode += codeSerializer.serializeObject( 'THREE.LoaderSupport.Validator', THREE.LoaderSupport.Validator );
- workerCode += codeSerializer.serializeClass( 'MeshSpray.Parser', MeshSpray.Parser );
- return workerCode;
- };
- var libs2Load = [ 'build/three.min.js' ];
- this.workerSupport.validate( buildCode, 'MeshSpray.Parser', libs2Load, '../../' );
- this.workerSupport.setCallbacks( scopeBuilderFunc, scopeFuncComplete );
- this.workerSupport.run(
- {
- params: {
- dimension: prepData.dimension,
- quantity: prepData.quantity,
- globalObjectCount: prepData.globalObjectCount
- },
- materials: {
- serializedMaterials: this.meshBuilder.getMaterialsJSON()
- },
- logging: {
- enabled: this.logging.enabled,
- debug: this.logging.debug
- },
- data: {
- input: null,
- options: null
- }
- }
- );
- },
- _applyPrepData: function ( prepData ) {
- if ( THREE.LoaderSupport.Validator.isValid( prepData ) ) {
- this.setLogging( prepData.logging.enabled, prepData.logging.debug );
- this.setStreamMeshesTo( prepData.streamMeshesTo );
- this.meshBuilder.setMaterials( prepData.materials );
- this._setCallbacks( prepData.getCallbacks() );
- }
- },
- _setCallbacks: function ( callbacks ) {
- if ( THREE.LoaderSupport.Validator.isValid( callbacks.onProgress ) ) this.callbacks.setCallbackOnProgress( callbacks.onProgress );
- if ( THREE.LoaderSupport.Validator.isValid( callbacks.onReportError ) ) this.callbacks.setCallbackOnReportError( callbacks.onReportError );
- if ( THREE.LoaderSupport.Validator.isValid( callbacks.onMeshAlter ) ) this.callbacks.setCallbackOnMeshAlter( callbacks.onMeshAlter );
- if ( THREE.LoaderSupport.Validator.isValid( callbacks.onLoad ) ) this.callbacks.setCallbackOnLoad( callbacks.onLoad );
- if ( THREE.LoaderSupport.Validator.isValid( callbacks.onLoadMaterials ) ) this.callbacks.setCallbackOnLoadMaterials( callbacks.onLoadMaterials );
- this.meshBuilder._setCallbacks( this.callbacks );
- }
- };
- MeshSpray.Parser = function () {
- this.sizeFactor = 0.5;
- this.localOffsetFactor = 1.0;
- this.globalObjectCount = 0;
- this.debug = false;
- this.dimension = 200;
- this.quantity = 1;
- this.callbacks = {
- onAssetAvailable: null
- };
- this.serializedMaterials = null;
- this.logging = {
- enabled: true,
- debug: false
- };
- };
- MeshSpray.Parser.prototype = {
- constructor: MeshSpray.Parser,
- setCallbackOnAssetAvailable: function ( onAssetAvailable ) {
- if ( onAssetAvailable !== null && onAssetAvailable !== undefined ) {
- this.callbacks.onAssetAvailable = onAssetAvailable;
- }
- },
- setLogging: function ( enabled, debug ) {
- this.logging.enabled = enabled === true;
- this.logging.debug = debug === true;
- },
- parse: function () {
- var baseTriangle = [ 1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 0.0, -1.0, 1.0 ];
- var vertices = [];
- var colors = [];
- var normals = [];
- var uvs = [];
- var dimensionHalf = this.dimension / 2;
- var fixedOffsetX;
- var fixedOffsetY;
- var fixedOffsetZ;
- var s, t;
- // complete triangle
- var sizeVaring = this.sizeFactor * Math.random();
- // local coords offset
- var localOffsetFactor = this.localOffsetFactor;
- for ( var i = 0; i < this.quantity; i++ ) {
- sizeVaring = this.sizeFactor * Math.random();
- s = 2 * Math.PI * Math.random();
- t = Math.PI * Math.random();
- fixedOffsetX = dimensionHalf * Math.random() * Math.cos( s ) * Math.sin( t );
- fixedOffsetY = dimensionHalf * Math.random() * Math.sin( s ) * Math.sin( t );
- fixedOffsetZ = dimensionHalf * Math.random() * Math.cos( t );
- for ( var j = 0; j < baseTriangle.length; j += 3 ) {
- vertices.push( baseTriangle[ j ] * sizeVaring + localOffsetFactor * Math.random() + fixedOffsetX );
- vertices.push( baseTriangle[ j + 1 ] * sizeVaring + localOffsetFactor * Math.random() + fixedOffsetY );
- vertices.push( baseTriangle[ j + 2 ] * sizeVaring + localOffsetFactor * Math.random() + fixedOffsetZ );
- colors.push( Math.random() );
- colors.push( Math.random() );
- colors.push( Math.random() );
- }
- }
- var absoluteVertexCount = vertices.length;
- var absoluteColorCount = colors.length;
- var absoluteNormalCount = 0;
- var absoluteUvCount = 0;
- var vertexFA = new Float32Array( absoluteVertexCount );
- var colorFA = ( absoluteColorCount > 0 ) ? new Float32Array( absoluteColorCount ) : null;
- var normalFA = ( absoluteNormalCount > 0 ) ? new Float32Array( absoluteNormalCount ) : null;
- var uvFA = ( absoluteUvCount > 0 ) ? new Float32Array( absoluteUvCount ) : null;
- vertexFA.set( vertices, 0 );
- if ( colorFA ) {
- colorFA.set( colors, 0 );
- }
- if ( normalFA ) {
- normalFA.set( normals, 0 );
- }
- if ( uvFA ) {
- uvFA.set( uvs, 0 );
- }
- /*
- * This demonstrates the usage of embedded three.js in the worker blob and
- * the serialization of materials back to the Builder outside the worker.
- *
- * This is not the most effective way, but outlining possibilities
- */
- var materialName = 'defaultVertexColorMaterial_double';
- var defaultVertexColorMaterialJson = this.serializedMaterials[ 'defaultVertexColorMaterial' ];
- var loader = new THREE.MaterialLoader();
- var defaultVertexColorMaterialDouble = loader.parse( defaultVertexColorMaterialJson );
- defaultVertexColorMaterialDouble.name = materialName;
- defaultVertexColorMaterialDouble.side = THREE.DoubleSide;
- var newSerializedMaterials = {};
- newSerializedMaterials[ materialName ] = defaultVertexColorMaterialDouble.toJSON();
- var payload = {
- cmd: 'materialData',
- materials: {
- serializedMaterials: newSerializedMaterials
- }
- };
- this.callbacks.onAssetAvailable( payload );
- this.globalObjectCount++;
- this.callbacks.onAssetAvailable(
- {
- cmd: 'meshData',
- progress: {
- numericalValue: 1.0
- },
- params: {
- meshName: 'Gen' + this.globalObjectCount
- },
- materials: {
- multiMaterial: false,
- materialNames: [ materialName ],
- materialGroups: []
- },
- buffers: {
- vertices: vertexFA,
- colors: colorFA,
- normals: normalFA,
- uvs: uvFA
- }
- },
- [ vertexFA.buffer ],
- colorFA !== null ? [ colorFA.buffer ] : null,
- normalFA !== null ? [ normalFA.buffer ] : null,
- uvFA !== null ? [ uvFA.buffer ] : null
- );
- if ( this.logging.enabled ) console.info( 'Global output object count: ' + this.globalObjectCount );
- },
- setSerializedMaterials: function ( serializedMaterials ) {
- if ( THREE.LoaderSupport.Validator.isValid( serializedMaterials ) ) {
- this.serializedMaterials = serializedMaterials;
- }
- }
- };
- var MeshSprayApp = function ( elementToBindTo ) {
- this.renderer = null;
- this.canvas = elementToBindTo;
- this.aspectRatio = 1;
- this.recalcAspectRatio();
- this.scene = null;
- this.cameraDefaults = {
- posCamera: new THREE.Vector3( 500.0, 500.0, 1000.0 ),
- posCameraTarget: new THREE.Vector3( 0, 0, 0 ),
- near: 0.1,
- far: 10000,
- fov: 45
- };
- this.camera = null;
- this.cameraTarget = this.cameraDefaults.posCameraTarget;
- this.controls = null;
- this.cube = null;
- this.pivot = null;
- };
- MeshSprayApp.prototype = {
- constructor: MeshSprayApp,
- initGL: function () {
- this.renderer = new THREE.WebGLRenderer( {
- canvas: this.canvas,
- antialias: true,
- autoClear: true
- } );
- this.renderer.setClearColor( 0x050505 );
- this.scene = new THREE.Scene();
- this.camera = new THREE.PerspectiveCamera( this.cameraDefaults.fov, this.aspectRatio, this.cameraDefaults.near, this.cameraDefaults.far );
- this.resetCamera();
- this.controls = new THREE.TrackballControls( this.camera, this.renderer.domElement );
- var ambientLight = new THREE.AmbientLight( 0x404040 );
- var directionalLight1 = new THREE.DirectionalLight( 0xC0C090 );
- var directionalLight2 = new THREE.DirectionalLight( 0xC0C090 );
- directionalLight1.position.set( -100, -50, 100 );
- directionalLight2.position.set( 100, 50, -100 );
- this.scene.add( directionalLight1 );
- this.scene.add( directionalLight2 );
- this.scene.add( ambientLight );
- var helper = new THREE.GridHelper( 1200, 60, 0xFF4444, 0x404040 );
- this.scene.add( helper );
- var geometry = new THREE.BoxBufferGeometry( 10, 10, 10 );
- var material = new THREE.MeshNormalMaterial();
- this.cube = new THREE.Mesh( geometry, material );
- this.cube.position.set( 0, 0, 0 );
- this.scene.add( this.cube );
- this.pivot = new THREE.Object3D();
- this.pivot.name = 'Pivot';
- this.scene.add( this.pivot );
- },
- initContent: function () {
- var maxQueueSize = 1024;
- var maxWebWorkers = 4;
- var radius = 640;
- var workerDirector = new THREE.LoaderSupport.WorkerDirector( MeshSpray.Loader );
- workerDirector.setLogging( false, false );
- workerDirector.setCrossOrigin( 'anonymous' );
- var callbackOnLoad = function ( event ) {
- console.info( 'Worker #' + event.detail.instanceNo + ': Completed loading. (#' + workerDirector.objectsCompleted + ')' );
- };
- var reportProgress = function( event ) {
- document.getElementById( 'feedback' ).innerHTML = event.detail.text;
- console.info( event.detail.text );
- };
- var callbackMeshAlter = function ( event ) {
- var override = new THREE.LoaderSupport.LoadedMeshUserOverride( false, true );
- event.detail.side = THREE.DoubleSide;
- var mesh = new THREE.Mesh( event.detail.bufferGeometry, event.detail.material );
- mesh.name = event.detail.meshName;
- override.addMesh( mesh );
- return override;
- };
- var callbacks = new THREE.LoaderSupport.Callbacks();
- callbacks.setCallbackOnMeshAlter( callbackMeshAlter );
- callbacks.setCallbackOnLoad( callbackOnLoad );
- callbacks.setCallbackOnProgress( reportProgress );
- workerDirector.prepareWorkers( callbacks, maxQueueSize, maxWebWorkers );
- var prepData;
- var pivot;
- var s, t, r, x, y, z;
- var globalObjectCount = 0;
- for ( var i = 0; i < maxQueueSize; i++ ) {
- prepData = new THREE.LoaderSupport.PrepData( 'Triangles_' + i );
- pivot = new THREE.Object3D();
- s = 2 * Math.PI * Math.random();
- t = Math.PI * Math.random();
- r = radius * Math.random();
- x = r * Math.cos( s ) * Math.sin( t );
- y = r * Math.sin( s ) * Math.sin( t );
- z = r * Math.cos( t );
- pivot.position.set( x, y, z );
- this.scene.add( pivot );
- prepData.streamMeshesTo = pivot;
- prepData.setLogging( false, false );
- prepData.quantity = 8192;
- prepData.dimension = Math.max( Math.random() * 500, 100 );
- prepData.globalObjectCount = globalObjectCount++;
- workerDirector.enqueueForRun( prepData );
- }
- workerDirector.processQueue();
- },
- resizeDisplayGL: function () {
- this.controls.handleResize();
- this.recalcAspectRatio();
- this.renderer.setSize( this.canvas.offsetWidth, this.canvas.offsetHeight, false );
- this.updateCamera();
- },
- recalcAspectRatio: function () {
- this.aspectRatio = ( this.canvas.offsetHeight === 0 ) ? 1 : this.canvas.offsetWidth / this.canvas.offsetHeight;
- },
- resetCamera: function () {
- this.camera.position.copy( this.cameraDefaults.posCamera );
- this.cameraTarget.copy( this.cameraDefaults.posCameraTarget );
- this.updateCamera();
- },
- updateCamera: function () {
- this.camera.aspect = this.aspectRatio;
- this.camera.lookAt( this.cameraTarget );
- this.camera.updateProjectionMatrix();
- },
- render: function () {
- if ( ! this.renderer.autoClear ) this.renderer.clear();
- this.controls.update();
- this.cube.rotation.x += 0.05;
- this.cube.rotation.y += 0.05;
- this.renderer.render( this.scene, this.camera );
- }
- };
- var app = new MeshSprayApp( document.getElementById( 'example' ) );
- // init three.js example application
- var resizeWindow = function () {
- app.resizeDisplayGL();
- };
- var render = function () {
- requestAnimationFrame( render );
- app.render();
- };
- window.addEventListener( 'resize', resizeWindow, false );
- console.log( 'Starting initialisation phase...' );
- app.initGL();
- app.resizeDisplayGL();
- app.initContent();
- render();
- </script>
- </body>
- </html>
|