How to access the any property of imported point-cloud object - three.js

I’m trying to access any property of my imported point-cloud model.
When I console.log the model within the function loader.load it works. The first problem is that I don’t know how to get the same result outside the function. I did it only with the last three lines of code but initializing the object with different name.
I used the code for point-cloud models from three.js docs and everything works fine except when I want to change the size of the points. I guess it is due to the different structure of my model (photo attached).
Here’s the code that I use.
import './style.css'
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
import { PCDLoader } from 'three/examples/jsm/loaders/PCDLoader'
import { BufferAttribute, BufferGeometry } from 'three';
let camera, scene, renderer;
init();
render();
function init() {
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 30, window.innerWidth / window.innerHeight, 0.01, 40 );
camera.position.set( 0, 0, 7 );
scene.add( camera );
const controls = new OrbitControls( camera, renderer.domElement );
controls.addEventListener( 'change', render ); // use if there is no animation loop
controls.minDistance = 0.5;
controls.maxDistance = 10;
//scene.add( new THREE.AxesHelper( 1 ) );
const loader = new PCDLoader();
loader.load( 'pointcloud.pcd', function ( points ) {
points.geometry.center();
points.geometry.rotateY( Math.PI );
points.geometry.rotateX( Math.PI );
points.geometry.rotateZ( Math.PI );
scene.add( points );
console.log(points)
render();
} );
window.addEventListener( 'resize', onWindowResize );
window.addEventListener( 'keypress', keyboard );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function keyboard( ev ) {
const points = scene.getObjectByProperty( 'pointcloud.pcd' );
switch ( ev.key || String.fromCharCode( ev.keyCode || ev.charCode ) ) {
case '+':
points.material.size *= 1.2;
break;
case '-':
points.material.size /= 1.2;
break;
}
render();
}
function render() {
renderer.render( scene, camera );
}
// I used this to acces the object
const points2 = scene.getObjectByProperty( 'points' );
console.log(points2)
enter image description here

change let camera, scene, renderer; to let camera, scene, renderer, points
to make 'points' global.

because the 'points' object only live inside the function, try create a variable outside the loader.load function, then assign the 'points' object to the new variable before render(); now you can access the 'points' from outside this function

Related

Not able to plot pcd file from PCDLoader in 3js

I am trying to plot pcd file following the example mentioned here. WIth the given pcd I am able to plot but the pcd I have I am not able to plot. I cross checked the format and there were no errors as well in browser. Here is my pcd file. I am not getting whats going wrong.
I have tested your PCD file on my computer and it renders find. However, just replacing the PCD file in the mentioned example won't work since the spatial distribution of the data set is totally different. Hence you need a different camera and control setting. You should be able to see the point cloud with the following basic code:
var camera, container, scene, renderer;
init();
animate();
function init() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 15, window.innerWidth / window.innerHeight, 0.1, 1000 );
camera.position.z = 700;
scene.add( camera );
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
var loader = new THREE.PCDLoader();
loader.load( './models/pcd/binary/test.pcd', function ( points ) {
points.material.size = 5;
scene.add( points );
} );
container = document.createElement( 'div' );
document.body.appendChild( container );
container.appendChild( renderer.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 );
renderer.render( scene, camera );
}

How do I import code from THREE.js examples?

I am currently building a React application that utilizes THREE.js.
I want to import some code from THREE.js library, which is not part of the official distribution. Under the official repo for THREE.js, there are some modules under the examples folder, which the official doc for THREE.js makes use of to showcase examples.
How can I make use of these modules and use them in my own code?
In my app, I wanted to use the THREE.STLExporter module.
(https://github.com/mrdoob/three.js/blob/master/examples/js/exporters/STLExporter.js)
Because I already installed three as a dependency for my app, I first tried simply doing import * as THREE from 'three', which did not seem to do the trick.
Then I tried to access the examples folder directly and grab the module manually by doing `require('three/examples/js/exporters/STLExporter'), but this did not work either.
I have checked the source code for the official docs and noticed that the examples directly include the necessary modules in tags, but I don't want to do that because I am building a React app. I want to be able to include modules either via NPM or storing the code for the module within my app.
Please help out a noob here. Thank you!
You can create a separate three.js file that will import "three", add any examples code to it and export as an object, here is a snippet that works with THREE.OrbitControls:
import * as THREE from 'three';
window.THREE = THREE; // THREE.OrbitControls expects THREE to be a global object
require('three/examples/js/controls/OrbitControls');
export default window.THREE;
Then use three.js file in your app like this:
import React, { Component } from "react";
import ReactDOM from "react-dom";
import THREE from "./three";
class App extends Component {
componentDidMount() {
// BASIC THREE.JS THINGS: SCENE, CAMERA, RENDERER
// Three.js Creating a scene tutorial
// https://threejs.org/docs/index.html#manual/en/introduction/Creating-a-scene
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
);
camera.position.z = 5;
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
// MOUNT INSIDE OF REACT
this.mount.appendChild(renderer.domElement); // mount a scene inside of React using a ref
// CAMERA CONTROLS
// https://threejs.org/docs/index.html#examples/controls/OrbitControls
this.controls = new THREE.OrbitControls(camera);
// ADD CUBE AND LIGHTS
// https://threejs.org/docs/index.html#api/en/geometries/BoxGeometry
// https://threejs.org/docs/scenes/geometry-browser.html#BoxGeometry
var geometry = new THREE.BoxGeometry(2, 2, 2);
var material = new THREE.MeshPhongMaterial( {
color: 0x156289,
emissive: 0x072534,
side: THREE.DoubleSide,
flatShading: true
} );
var cube = new THREE.Mesh(geometry, material);
scene.add(cube);
var lights = [];
lights[ 0 ] = new THREE.PointLight( 0xffffff, 1, 0 );
lights[ 1 ] = new THREE.PointLight( 0xffffff, 1, 0 );
lights[ 2 ] = new THREE.PointLight( 0xffffff, 1, 0 );
lights[ 0 ].position.set( 0, 200, 0 );
lights[ 1 ].position.set( 100, 200, 100 );
lights[ 2 ].position.set( - 100, - 200, - 100 );
scene.add( lights[ 0 ] );
scene.add( lights[ 1 ] );
scene.add( lights[ 2 ] );
// SCALE ON RESIZE
// Check "How can scene scale be preserved on resize?" section of Three.js FAQ
// https://threejs.org/docs/index.html#manual/en/introduction/FAQ
// code below is taken from Three.js fiddle
// http://jsfiddle.net/Q4Jpu/
// remember these initial values
var tanFOV = Math.tan( ( ( Math.PI / 180 ) * camera.fov / 2 ) );
var windowHeight = window.innerHeight;
window.addEventListener( 'resize', onWindowResize, false );
function onWindowResize( event ) {
camera.aspect = window.innerWidth / window.innerHeight;
// adjust the FOV
camera.fov = ( 360 / Math.PI ) * Math.atan( tanFOV * ( window.innerHeight / windowHeight ) );
camera.updateProjectionMatrix();
camera.lookAt( scene.position );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.render( scene, camera );
}
// ANIMATE THE SCENE
var animate = function() {
requestAnimationFrame(animate);
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render(scene, camera);
};
animate();
}
render() {
return <div ref={ref => (this.mount = ref)} />;
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
working demo on stackblitz https://stackblitz.com/edit/react-three-example-import?file=index.js
You should import the full path of the module:
import { STLExporter } as THREE from 'three/examples/jsm/STLExporter

How to animate a Collada model's children in three.js?

I'm trying to find a way to animate the children in a Collada model of the Canadarm2. The model contains 7 arm segments whose angles need to be set by reading in rotation angle data from each of 7 spreadsheet columns one row at a time. Each line holds 7 columns of data representing each second's angles in an hour, or longer, mission.
I'm hoping someone might suggest a solution to get me started -- perhaps something like the guesswork I've tried inside the animate() function below.
if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
var container, stats, clock;
var camera, scene, renderer, canadarm2;
init();
animate();
function init() {
container = document.getElementById( 'container' );
camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.1, 2000 );
camera.position.set( 8, 10, 80 );
camera.lookAt( new THREE.Vector3( 0, 3, 0 ) );
scene = new THREE.Scene();
clock = new THREE.Clock();
// loading manager
var loadingManager = new THREE.LoadingManager( function() {
scene.add( canadarm2 );
} );
// collada
var loader = new THREE.ColladaLoader( loadingManager );
//loader.load( 'examples/models/collada/elf/elf.dae', function ( collada ) {
loader.load( 'canadarm2.dae', function ( collada ) {
canadarm2 = collada.scene;
} );
//
var ambientLight = new THREE.AmbientLight( 0xcccccc, 0.4 );
scene.add( ambientLight );
var directionalLight = new THREE.DirectionalLight( 0xffffff, 0.8 );
directionalLight.position.set( 1, 1, 0 ).normalize();
scene.add( directionalLight );
//
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
//
stats = new Stats();
container.appendChild( stats.dom );
//
window.addEventListener( 'resize', onWindowResize, false );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function animate() {
/*
//#######################################
// doesn't work
var armEP = canadarm2.getChildByName("EP", true);// EP is one of 7 arms
armEP.position.x += 0.01;
armEP.rotation.y += 45;
//#######################################
*/
render();
stats.update();
}
function render() {
var delta = clock.getDelta();
if ( canadarm2 !== undefined ) {
canadarm2.rotation.z += delta * 0.5;
}
renderer.render( scene, camera );
}
This seems to work although it seems an awfully roundabout way to locate the arms.
scene.traverse(function (child) {
switch(child.name) {
case "SR":
child.rotation.x += 0.01;
break;
case "SP":
child.rotation.y += 0.01;
break;
case "SY":
child.rotation.y += 0.01;
break;
case "EP":
child.rotation.y += 0.01;
break;
case "WP":
child.rotation.x += 0.01;
break;
case "WY":
child.rotation.y += 0.01;
break;
case "WR":
child.rotation.x += 0.01;
break;
}
});

Collada load in THREE.js

I want to load collada file using three.js. I tried but the file is not showing. No error is also showing. I tried some other dae file but this dae file is not working. What's the issue i could not find. Is there problem with file or code ?
<script src="build/three.js"></script>
<script src="js/controls/TrackballControls.js"></script>
<script src="js/renderers/CSS3DRenderer.js"></script>
<script src="js/loaders/ColladaLoader.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, clock;
var camera, scene, renderer, elf;
init();
animate();
function init() {
container = document.getElementById( 'container' );
camera = new THREE.PerspectiveCamera( 100, window.innerWidth / window.innerHeight, 0.1, 10000 );
camera.position.set( 0, 0, 3000 );
//camera.position.z = 3000;
//camera.position.y = 150;
camera.lookAt( new THREE.Vector3( 0, 0, 0 ) );
scene = new THREE.Scene();
clock = new THREE.Clock();
// loading manager
var loadingManager = new THREE.LoadingManager( function() {
scene.add( elf );
} );
// collada
var loader = new THREE.ColladaLoader( loadingManager );
loader.load( 'textures/sketup/pack.dae', function ( collada ) {
elf = collada.scene;
} );
//
var ambientLight = new THREE.AmbientLight( 0xcccccc, 0.4 );
scene.add( ambientLight );
var directionalLight = new THREE.DirectionalLight( 0xffffff, 0.8 );
directionalLight.position.set( 1, 1, 0 ).normalize();
scene.add( directionalLight );
//
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
//
stats = new Stats();
container.appendChild( stats.dom );
//
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 delta = clock.getDelta();
if ( elf !== undefined ) {
elf.rotation.y += delta * 0.5;
}
renderer.render( scene, camera );
}
</script>
I tried this code. But this code is not showing the collada file. What's the issue?
here is the file link
https://drive.google.com/file/d/0BxtPLq6DiFBkajVjRWJGaVBFSzNkbkdlQWdhMTkzQ0hQY0hR/view

Three.js Applying Repeated Texture to JSON Scene Object

I have a basic json scene exported from the three.js/editor. I want to add a repeated texture wrap to an object in this scene but I do not know how to do so since the only examples I have found add the wrap in the creation of the object.
I have already tried accessing the texture and giving it a wrap, but I think I might need to add a texture to the object from the JavaScript then declare the texture wrap instead of trying to add it to an already loaded texture.
<script>
var camera, scene, renderer;
var mesh;
init();
animate();
function init() {
camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 1000 );
camera.position.z = 400;
scene = new THREE.Scene();
var objectLoader = new THREE.ObjectLoader();
objectLoader.load( "models/cube.json", function ( obj ) {
scene.add( obj )
obj.traverse(function(child) {
if (child instanceof THREE.Mesh) {
child.castShadow = true;
child.receiveShadow = true;
}
});
obj.name = "cube";
obj.position.set(0,0,0);
obj.scale.set(200,200,200);
});
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
//
window.addEventListener( 'resize', onWindowResize, false );
while (scene.getObjectByName('Box 1')){
var texture = scene.getObjectByName('Box 1').material;
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
texture.repeat.set( 2, 2 );
}
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function animate() {
requestAnimationFrame( animate );
if (scene.getObjectByName('Box 1') ){
scene.getObjectByName('Box 1').material.map.offset.x += 0.001;
}
renderer.render( scene, camera );
}
</script>
You need to set the wrap and repeat properties of the texture/map and not of the material. Docs also say it's important to set needsUpdate to true, if wrap settings changed. And you are trying to set the properties before the json is loaded (in a while loop?). You should do it within the load callback.
objectLoader.load( "models/cube.json", function ( obj ) {
scene.add( obj )
obj.traverse(function(child) {
if (child instanceof THREE.Mesh) {
child.castShadow = true;
child.receiveShadow = true;
}
});
obj.name = "cube";
obj.position.set(0,0,0);
obj.scale.set(200,200,200);
var box1 = scene.getObjectByName('Box 1');
if (box1) {
var texture = box1.material.map;
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
texture.repeat.set( 2, 2 );
texture.needsUpdate = true;
}
});

Resources