2
0
Эх сурвалжийг харах

Merge pull request #20831 from mrdoob/tiltbrush

Added TiltLoader
Mr.doob 4 жил өмнө
parent
commit
eb96029104

+ 1 - 0
examples/files.json

@@ -114,6 +114,7 @@
 		"webgl_loader_prwm",
 		"webgl_loader_stl",
 		"webgl_loader_svg",
+		"webgl_loader_tilt",
 		"webgl_loader_texture_basis",
 		"webgl_loader_texture_dds",
 		"webgl_loader_texture_exr",

+ 215 - 0
examples/jsm/loaders/TiltLoader.js

@@ -0,0 +1,215 @@
+import {
+	BufferAttribute,
+	BufferGeometry,
+	Color,
+	DoubleSide,
+	FileLoader,
+	Group,
+	Loader,
+	Mesh,
+	MeshBasicMaterial,
+	Quaternion,
+	Vector3
+} from '../../../build/three.module.js';
+import { JSZip } from '../libs/jszip.module.min.js';
+
+class TiltLoader extends Loader {
+
+	load( url, onLoad, onProgress, onError ) {
+
+		const scope = this;
+
+		const loader = new FileLoader( this.manager );
+		loader.setPath( this.path );
+		loader.setResponseType( 'arraybuffer' );
+		loader.setWithCredentials( this.withCredentials );
+
+		loader.load( url, function ( buffer ) {
+
+			try {
+
+				onLoad( scope.parse( buffer ) );
+
+			} catch ( e ) {
+
+				if ( onError ) {
+
+					onError( e );
+
+				} else {
+
+					console.error( e );
+
+				}
+
+				scope.manager.itemError( url );
+
+			}
+
+		}, onProgress, onError );
+
+	}
+
+	parse( buffer ) {
+
+		const group = new Group();
+		// https://docs.google.com/document/d/11ZsHozYn9FnWG7y3s3WAyKIACfbfwb4PbaS8cZ_xjvo/edit#
+
+		const zip = new JSZip( buffer.slice( 16 ) ); // eslint-disable-line no-undef
+
+		/*
+		const thumbnail = zip.files[ 'thumbnail.png' ].asArrayBuffer();
+		const img = document.createElement( 'img' );
+		img.src = URL.createObjectURL( new Blob( [ thumbnail ] ) );
+		document.body.appendChild( img );
+
+		const metadata = JSON.parse( zip.files[ 'metadata.json' ].asText() );
+		*/
+
+		/*
+		const blob = new Blob( [ zip.files[ 'data.sketch' ].asArrayBuffer() ], { type: 'application/octet-stream' } );
+		window.open( URL.createObjectURL( blob ) );
+		*/
+
+		const data = new DataView( zip.files[ 'data.sketch' ].asArrayBuffer() );
+
+		const num_strokes = data.getInt32( 16, true );
+
+		let offset = 20;
+
+		for ( let i = 0; i < num_strokes; i ++ ) {
+
+			// const brush_index = data.getInt32( offset, true );
+			const brush_color = [
+				data.getFloat32( offset + 4, true ),
+				data.getFloat32( offset + 8, true ),
+				data.getFloat32( offset + 12, true ),
+				data.getFloat32( offset + 16, true )
+			];
+			const brush_size = data.getFloat32( offset + 20, true );
+			const stroke_mask = data.getUint32( offset + 24, true );
+			const controlpoint_mask = data.getUint32( offset + 28, true );
+
+			let offset_stroke_mask = 0;
+			let offset_controlpoint_mask = 0;
+
+			for ( let j = 0; j < 4; j ++ ) {
+
+				// TOFIX: I don't understand these masks yet
+
+				const byte = 1 << j;
+				if ( ( stroke_mask & byte ) > 0 ) offset_stroke_mask += 4;
+				if ( ( controlpoint_mask & byte ) > 0 ) offset_controlpoint_mask += 4;
+
+			}
+
+			// console.log( { brush_index, brush_color, brush_size, stroke_mask, controlpoint_mask } );
+			// console.log( offset_stroke_mask, offset_controlpoint_mask );
+
+			offset = offset + 28 + offset_stroke_mask + 4; // TOFIX: This is wrong
+
+			const num_control_points = data.getInt32( offset, true );
+
+			// console.log( { num_control_points } );
+
+			const positions = new Float32Array( num_control_points * 3 );
+			const quaternions = new Float32Array( num_control_points * 4 );
+
+			offset = offset + 4;
+
+			for ( let j = 0, k = 0; j < positions.length; j += 3, k += 4 ) {
+
+				positions[ j + 0 ] = data.getFloat32( offset + 0, true );
+				positions[ j + 1 ] = data.getFloat32( offset + 4, true );
+				positions[ j + 2 ] = data.getFloat32( offset + 8, true );
+
+				quaternions[ k + 0 ] = data.getFloat32( offset + 12, true );
+				quaternions[ k + 1 ] = data.getFloat32( offset + 16, true );
+				quaternions[ k + 2 ] = data.getFloat32( offset + 20, true );
+				quaternions[ k + 3 ] = data.getFloat32( offset + 24, true );
+
+				offset = offset + 28 + offset_controlpoint_mask; // TOFIX: This is wrong
+
+			}
+
+			// console.log( positions, quaternions );
+
+			const color = new Color().fromArray( brush_color );
+			const opacity = brush_color[ 3 ];
+
+			const geometry = new StrokeGeometry( positions, quaternions, brush_size );
+			const material = new MeshBasicMaterial( {
+				color: color, opacity: opacity, transparent: opacity < 1, side: DoubleSide
+			} );
+			group.add( new Mesh( geometry, material ) );
+
+		}
+
+		return group;
+
+	}
+
+}
+
+class StrokeGeometry extends BufferGeometry {
+
+	constructor( positions, quaternions, size ) {
+
+		super();
+
+		const vertices = [];
+
+		const position = new Vector3();
+		const prevPosition = new Vector3().fromArray( positions, 0 );
+
+		const quaternion = new Quaternion();
+		const prevQuaternion = new Quaternion().fromArray( quaternions, 0 );
+
+		const vector1 = new Vector3();
+		const vector2 = new Vector3();
+		const vector3 = new Vector3();
+		const vector4 = new Vector3();
+
+		size = size / 2;
+
+		for ( let i = 3, j = 4; i <= positions.length; i += 3, j += 4 ) {
+
+			position.fromArray( positions, i );
+			quaternion.fromArray( quaternions, j );
+
+			vector1.set( - size, 0, 0 );
+			vector1.applyQuaternion( quaternion );
+			vector1.add( position );
+
+			vector2.set( size, 0, 0 );
+			vector2.applyQuaternion( quaternion );
+			vector2.add( position );
+
+			vector3.set( size, 0, 0 );
+			vector3.applyQuaternion( prevQuaternion );
+			vector3.add( prevPosition );
+
+			vector4.set( - size, 0, 0 );
+			vector4.applyQuaternion( prevQuaternion );
+			vector4.add( prevPosition );
+
+			vertices.push( vector1.x, vector1.y, - vector1.z );
+			vertices.push( vector2.x, vector2.y, - vector2.z );
+			vertices.push( vector4.x, vector4.y, - vector4.z );
+
+			vertices.push( vector2.x, vector2.y, - vector2.z );
+			vertices.push( vector3.x, vector3.y, - vector3.z );
+			vertices.push( vector4.x, vector4.y, - vector4.z );
+
+			prevPosition.copy( position );
+			prevQuaternion.copy( quaternion );
+
+		}
+
+		this.setAttribute( 'position', new BufferAttribute( new Float32Array( vertices ), 3 ) );
+
+	}
+
+}
+
+export { TiltLoader };

BIN
examples/models/tilt/BRUSH_DOME.tilt


BIN
examples/screenshots/webgl_loader_tilt.jpg


+ 81 - 0
examples/webgl_loader_tilt.html

@@ -0,0 +1,81 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<title>three.js webgl - tilt loader</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">
+	</head>
+	<body>
+		<div id="info">
+			<a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> - tilt loader<br/>
+			<a href="https://poly.google.com/view/ewUb8s99x_k" target="_blank" rel="noopener">TILTSPHERE</a> by <a href="https://poly.google.com/user/8CZPjCt8LvV" target="_blank" rel="noopener">Rosie Summers</a>
+		</div>
+
+		<script type="module">
+
+			import * as THREE from '../build/three.module.js';
+
+			import { OrbitControls } from './jsm/controls/OrbitControls.js';
+			import { TiltLoader } from './jsm/loaders/TiltLoader.js';
+
+			let camera, scene, renderer;
+
+			init();
+
+			function init() {
+
+				scene = new THREE.Scene();
+
+				camera = new THREE.PerspectiveCamera( 35, window.innerWidth / window.innerHeight, 1, 500 );
+
+				camera.position.y = 43;
+				camera.position.z = 100;
+
+				scene.add( camera );
+
+				const grid = new THREE.GridHelper( 50, 50, 0xffffff, 0x555555 );
+				scene.add( grid );
+
+				renderer = new THREE.WebGLRenderer( { antialias: true } );
+				renderer.setPixelRatio( window.devicePixelRatio );
+				renderer.setSize( window.innerWidth, window.innerHeight );
+				document.body.appendChild( renderer.domElement );
+
+				const loader = new TiltLoader();
+				loader.load( './models/tilt/BRUSH_DOME.tilt', function ( object ) {
+
+					scene.add( object );
+					render();
+
+				} );
+
+				const controls = new OrbitControls( camera, renderer.domElement );
+				controls.addEventListener( 'change', render );
+				controls.target.y = camera.position.y;
+				controls.update();
+
+				window.addEventListener( 'resize', onWindowResize, false );
+
+			}
+
+			function onWindowResize() {
+
+				camera.aspect = window.innerWidth / window.innerHeight;
+				camera.updateProjectionMatrix();
+
+				renderer.setSize( window.innerWidth, window.innerHeight );
+
+				render();
+
+			}
+
+			function render() {
+
+				renderer.render( scene, camera );
+
+			}
+
+		</script>
+	</body>
+</html>