提交 be44e73a 编写于 作者: M Mr.doob

Merge pull request #8043 from filipecaixeta/dev

Loader for PCD files
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<base href="../../" />
<script src="list.js"></script>
<script src="page.js"></script>
<link type="text/css" rel="stylesheet" href="page.css" />
</head>
<body>
<h1>[name]</h1>
<div class="desc">A loader for <em>PCD</em> files. Loads ascii and binary. Compressed binary files are not suported.</div>
<h2>Constructor</h2>
<h3>[name]( [page:LoadingManager manager] )</h3>
<div>
[page:LoadingManager manager] — The [page:LoadingManager loadingManager] for the loader to use. Default is [page:LoadingManager THREE.DefaultLoadingManager].
</div>
<div>
Creates a new [name].
</div>
<h2>Properties</h2>
<h3>[page:Boolean littleEndian]</h3>
<div>
Default value is true.
</div>
<h2>Methods</h2>
<h3>[method:null load]( [page:String url], [page:Function onLoad], [page:Function onProgress], [page:Function onError] )</h3>
<div>
[page:String url] — required<br />
[page:Function onLoad] — Will be called when load completes. The argument will be the loaded [page:Object3D].<br />
[page:Function onProgress] — Will be called while load progresses. The argument will be the XmlHttpRequest instance, that contain .[page:Integer total] and .[page:Integer loaded] bytes.<br />
[page:Function onError] — Will be called when load errors.<br />
</div>
<div>
Begin loading from url and call onLoad with the parsed response content.
</div>
<h3>[method:Object3D parse]( [page:Arraybuffer data],[page:String url] )</h3>
<div>
[page:Arraybuffer data] — The binary structure to parse.
</div>
<div>
[page:String url] — The file name or file url.
</div>
<div>
Parse an <em>pcd</em> binary structure and return an [page:Object3D].<br />
The object is converted to [page:Points] with a [page:BufferGeometry] and a [page:PointsMaterial].
</div>
<h2>Example</h2>
<code>
// instantiate a loader
var loader = new THREE.PCDLoader();
// load a resource
loader.load(
// resource URL
'pointcloud.pcd' ,
// Function when resource is loaded
function ( mesh ) {
scene.add( mesh );
}
);
</code>
[example:webgl_loader_pcd]
<h2>Source</h2>
[link:https://github.com/mrdoob/three.js/blob/master/examples/js/loaders/PCDLoader.js examples/js/loaders/PCDLoader.js]
</body>
</html>
/**
* @author Filipe Caixeta / http://filipecaixeta.com.br
*
* Description: A THREE loader for PCD ascii and binary files.
*
* Limitations: Compressed binary files are not supported.
*
*/
THREE.PCDLoader = function( manager ) {
this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
this.littleEndian = true;
};
THREE.PCDLoader.prototype = {
constructor: THREE.PCDLoader,
load: function( url, onLoad, onProgress, onError ) {
var scope = this;
var loader = new THREE.XHRLoader( scope.manager );
loader.setResponseType( 'arraybuffer' );
loader.load( url, function( data ) {
onLoad( scope.parse( data, url ) );
}, onProgress, onError );
},
binarryToStr: function( data ) {
text = "";
var charArray = new Uint8Array( data );
for ( var i = 0; i < data.byteLength; i ++ ) {
text += String.fromCharCode( charArray[ i ] );
}
return text;
},
parseHeader: function( data ) {
var PCDheader = {};
var result1 = data.search( /[\r\n]DATA\s(\S*)\s/i );
var result2 = /[\r\n]DATA\s(\S*)\s/i.exec( data.substr( result1 - 1 ) );
PCDheader.data = result2[ 1 ];
PCDheader.headerLen = result2[ 0 ].length + result1;
PCDheader.str = data.substr( 0, PCDheader.headerLen );
// Remove comments
PCDheader.str = PCDheader.str.replace( /\#.*/gi, "" );
PCDheader.version = /VERSION (.*)/i.exec( PCDheader.str );
if ( PCDheader.version != null )
PCDheader.version = parseFloat( PCDheader.version[ 1 ] );
PCDheader.fields = /FIELDS (.*)/i.exec( PCDheader.str );
if ( PCDheader.fields != null )
PCDheader.fields = PCDheader.fields[ 1 ].split( " " );
PCDheader.size = /SIZE (.*)/i.exec( PCDheader.str );
if ( PCDheader.size != null )
PCDheader.size = PCDheader.size[ 1 ].split( " " ).map( function( x ) {
return parseInt( x, 10 );
} );
PCDheader.type = /TYPE (.*)/i.exec( PCDheader.str );
if ( PCDheader.type != null )
PCDheader.type = PCDheader.type[ 1 ].split( " " );
PCDheader.count = /COUNT (.*)/i.exec( PCDheader.str );
if ( PCDheader.count != null )
PCDheader.count = PCDheader.count[ 1 ].split( " " ).map( function( x ) {
return parseInt( x, 10 );
} );
PCDheader.width = /WIDTH (.*)/i.exec( PCDheader.str );
if ( PCDheader.width != null )
PCDheader.width = parseInt( PCDheader.width[ 1 ] );
PCDheader.height = /HEIGHT (.*)/i.exec( PCDheader.str );
if ( PCDheader.height != null )
PCDheader.height = parseInt( PCDheader.height[ 1 ] );
PCDheader.viewpoint = /VIEWPOINT (.*)/i.exec( PCDheader.str );
if ( PCDheader.viewpoint != null )
PCDheader.viewpoint = PCDheader.viewpoint[ 1 ];
PCDheader.points = /POINTS (.*)/i.exec( PCDheader.str );
if ( PCDheader.points != null )
PCDheader.points = parseInt( PCDheader.points[ 1 ], 10 );
if ( PCDheader.points == null )
PCDheader.points = PCDheader.width * PCDheader.height;
if ( PCDheader.count == null ) {
PCDheader.count = [];
for ( var i = 0; i < PCDheader.fields; i ++ )
PCDheader.count.push( 1 );
}
PCDheader.offset = {}
var sizeSum = 0;
for ( var i = 0; i < PCDheader.fields.length; i ++ ) {
if ( PCDheader.data == "ascii" ) {
PCDheader.offset[ PCDheader.fields[ i ]] = i;
} else {
PCDheader.offset[ PCDheader.fields[ i ]] = sizeSum;
sizeSum += PCDheader.size[ i ];
}
}
// For binary only
PCDheader.rowSize = sizeSum;
return PCDheader;
},
parse: function( data, url ) {
textData = this.binarryToStr( data );
// Parse the header
// Header is always ascii format
var PCDheader = this.parseHeader( textData );
// Parse the data
var position = false;
if ( PCDheader.offset.x != undefined )
position = new Float32Array( PCDheader.points * 3 );
var color = false;
if ( PCDheader.offset.rgb != undefined)
color = new Float32Array( PCDheader.points * 3 );
var normal = false;
if ( PCDheader.offset.normal_x != undefined )
normal = new Float32Array( PCDheader.points * 3 );
if ( PCDheader.data == "ascii" ) {
var offset = PCDheader.offset;
var pcdData = textData.substr( PCDheader.headerLen );
var lines = pcdData.split( '\n' );
var i3 = 0;
for ( var i = 0; i < lines.length; i ++, i3 += 3 ) {
var line = lines[ i ].split( " " );
if ( offset.x != undefined ) {
position[ i3 + 0 ] = parseFloat( line[ offset.x ] );
position[ i3 + 1 ] = parseFloat( line[ offset.y ] );
position[ i3 + 2 ] = parseFloat( line[ offset.z ] );
}
if ( offset.rgb != undefined ) {
var c = new Float32Array([parseFloat( line[ offset.rgb ] )]);
var dataview = new DataView( c.buffer, 0 );
color[ i3 + 0 ] = dataview.getUint8(0)/255.0;
color[ i3 + 1 ] = dataview.getUint8(1)/255.0;
color[ i3 + 2 ] = dataview.getUint8(2)/255.0;
}
if ( offset.normal_x != undefined ) {
normal[ i3 + 0 ] = parseFloat( line[ offset.normal_x ] );
normal[ i3 + 1 ] = parseFloat( line[ offset.normal_y ] );
normal[ i3 + 2 ] = parseFloat( line[ offset.normal_z ] );
}
}
}
if ( PCDheader.data == "binary_compressed" ) {
console.error( 'THREE.PCDLoader: binary_compressed files are not supported' );
return;
}
if ( PCDheader.data == "binary" ) {
var row = 0;
var dataview = new DataView( data, PCDheader.headerLen );
var i = 0;
var offset = PCDheader.offset;
for ( var i3 = 0; i < PCDheader.points; i3 += 3, row += PCDheader.rowSize, i ++ ) {
if ( offset.x != undefined ) {
position[ i3 + 0 ] = dataview.getFloat32( row + offset.x, this.littleEndian );
position[ i3 + 1 ] = dataview.getFloat32( row + offset.y, this.littleEndian );
position[ i3 + 2 ] = dataview.getFloat32( row + offset.z, this.littleEndian );
}
if ( offset.rgb != undefined ) {
color[ i3 + 0 ] = dataview.getUint8( row + offset.rgb + 0 ) / 255.0;
color[ i3 + 1 ] = dataview.getUint8( row + offset.rgb + 1 ) / 255.0;
color[ i3 + 2 ] = dataview.getUint8( row + offset.rgb + 2 ) / 255.0;
}
if ( offset.normal_x != undefined ) {
normal[ i3 + 0 ] = dataview.getFloat32( row + offset.normal_x, this.littleEndian );
normal[ i3 + 1 ] = dataview.getFloat32( row + offset.normal_y, this.littleEndian );
normal[ i3 + 2 ] = dataview.getFloat32( row + offset.normal_z, this.littleEndian );
}
}
}
var geometry = new THREE.BufferGeometry();
if ( position != false )
geometry.addAttribute( 'position', new THREE.BufferAttribute( position, 3 ) );
if ( color != false )
geometry.addAttribute( 'color', new THREE.BufferAttribute( color, 3 ) );
if ( normal != false )
geometry.addAttribute( 'normal', new THREE.BufferAttribute( normal, 3 ) );
geometry.computeBoundingSphere();
var material = new THREE.PointsMaterial( { size: 0.005,
vertexColors: !(color == false) } );
if ( color == false )
material.color.setHex( Math.random() * 0xffffff );
var mesh = new THREE.Points( geometry, material );
var name = url.split( '' ).reverse().join( '' );
name = /([^\/]*)/.exec( name );
name = name[ 1 ].split( '' ).reverse().join( '' );
mesh.name = name;
mesh.PCDheader = PCDheader;
return mesh;
},
};
THREE.EventDispatcher.prototype.apply( THREE.PCDLoader.prototype );
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js webgl - PCD</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: #000000;
margin: 0px;
overflow: hidden;
}
#info {
color: #fff;
position: absolute;
top: 10px;
width: 100%;
text-align: center;
z-index: 100;
display:block;
}
a { color: #d14826 }
.button { background:#999; color:#eee; padding:0.2em 0.5em; cursor:pointer }
.highlight { background:orange; color:#fff; }
span {
display: inline-block;
width: 60px;
float: left;
text-align: center;
}
</style>
</head>
<body>
<div id="info">
<a href="http://threejs.org" target="_blank">three.js</a>
<a href="http://pointclouds.org/documentation/tutorials/pcd_file_format.php#pcd-file-format" target="_blank">PCD File format</a>
<div>PCD loader test by <a href="http://filipecaixeta.com.br" target="_blank">Filipe Caixeta</a></div>
<div>+/-: Increase/Decrease point size</a></div>
<div>c: Toggle color</a></div>
</div>
<script src="../build/three.min.js"></script>
<script src="js/loaders/PCDLoader.js"></script>
<script src="js/controls/TrackballControls.js"></script>
<script src="js/Detector.js"></script>
<script src="js/libs/stats.min.js"></script>
<script>
if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
var container, stats;
var camera, controls, scene, renderer;
init();
animate();
function init() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 15, window.innerWidth / window.innerHeight, 0.01, 40 );
camera.position.x = 0.4;
camera.position.z = -2;
camera.up.set(0,0,1);
controls = new THREE.TrackballControls( camera );
controls.rotateSpeed = 2.0;
controls.zoomSpeed = 0.3;
controls.panSpeed = 0.2;
controls.noZoom = false;
controls.noPan = false;
controls.staticMoving = true;
controls.dynamicDampingFactor = 0.3;
controls.minDistance = 0.3;
controls.maxDistance = 0.3 * 100;
scene.add( camera );
var axisHelper = new THREE.AxisHelper( 0.1 );
scene.add( axisHelper );
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setClearColor( 0x000000 );
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
var loader = new THREE.PCDLoader();
loader.load( './models/pcd/Zaghetto.pcd', function ( mesh ) {
scene.add( mesh );
var center = mesh.geometry.boundingSphere.center;
controls.target.set( center.x, center.y, center.z);
controls.update();
} );
container = document.createElement( 'div' );
document.body.appendChild( container );
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 );
window.addEventListener('keydown', keyboard);
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
controls.handleResize();
}
function keyboard (ev)
{
var ZaghettoMesh = scene.getObjectByName( "Zaghetto.pcd" );
switch (ev.key)
{
case '+':
ZaghettoMesh.material.size*=1.2;
ZaghettoMesh.material.needsUpdate = true;
break;
case '-':
ZaghettoMesh.material.size/=1.2;
ZaghettoMesh.material.needsUpdate = true;
break;
case 'c':
ZaghettoMesh.material.color.setHex(Math.random()*0xffffff);
ZaghettoMesh.material.needsUpdate = true;
break;
default:
break;
}
}
function animate() {
requestAnimationFrame( animate );
controls.update();
renderer.render( scene, camera );
stats.update();
}
</script>
</body>
</html>
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册