Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions examples/files.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
215 changes: 215 additions & 0 deletions examples/jsm/loaders/TiltLoader.js
Original file line number Diff line number Diff line change
@@ -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 };
Binary file added examples/models/tilt/BRUSH_DOME.tilt
Binary file not shown.
Binary file added examples/screenshots/webgl_loader_tilt.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
81 changes: 81 additions & 0 deletions examples/webgl_loader_tilt.html
Original file line number Diff line number Diff line change
@@ -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>