I have several models in Clara.io, according to their help if you export selection, then it will be file for JSONLoader, and if you export full scene it will be file for ObjectLoader. However non of export function working with JSONLoader (https://forum.clara.io/t/export-to-three-js-json-export-all-and-export-selected-both-export-scene-object/3709).
In my app I need only geometry from model to build Points object. So I'm looking for either methods to convert loaded object to Mesh, or some king of geometry subtraction from object itself. In helps and examples(both three and clara) I see only one action with loaded object - scene.add(object).
import THREE from 'three/build/three.module';
import {Scene,PerspectiveCamera,Fog,WebGLRenderer,ObjectLoader,Geometry} from 'three/build/three.module';
....
var loader = new ObjectLoader();
loader.load( 'assets/models/rabbit.json', function ( object ) {
//I don't need to add object here but this is the only thing that works
//scene.add(object);
//I need to do something like this
geometry2 = new Geometry();
geometry2.vertices = object.geometry.vertices; // ???
particles = new Points( geometry2, new PointsMaterial( { color: 0xff0000, size:5 } ) );
scene.add(particles)
});
So clara.io seems to export single object in scene. So the way to extract mesh from it is something like:
loader.load( 'assets/models/rabbit.json', function ( object ) {
//I don't need to add object here but this is the only thing that works
//scene.add(object);
//I need to do something like this
geometry2 = new Geometry();
geometry2.vertices = object.children[0].geometry.vertices;
//object.children[0] - the first mesh in exported object
particles = new Points( geometry2, new PointsMaterial( { color: 0xff0000, size:5 } ) );
scene.add(particles)
});
Related
I've got a gltf file. When I import it inside the Three.js editor (https://threejs.org/editor/) I get a correct result when I add an environment map.
On the other hand, when I import my gltf in my project scene I've a different result. Even when I use the very same HDRI image. The metalness is way too shinny in this case.
Does anyone know what I'm missing? Thank you.
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure = 1;
renderer.outputEncoding = THREE.sRGBEncoding;
new RGBELoader()
.load( 'royal_esplanade_1k.hdr', function ( texture ) {
texture.mapping = THREE.EquirectangularReflectionMapping;
scene.environment = texture;
} );
loader.load(
'./gltf/canette.glb',
// called when the resource is loaded
function ( gltf ) {
obj = gltf.scene;
mixer = new THREE.AnimationMixer( gltf.scene );
action = mixer.clipAction( gltf.animations[ 0 ] );
//obj
scene.add( obj );
}
);
EDIT :
Here's a live demo.
Here's the gltf model.
Unfortunately, you are using a code snippet which does not match your actual three.js version. You have to use at least r131 (or better the latest one r141). Right now, you are using r129.
If you use three.js versions below r131, you have to use PMREMGenerator to prepare the environment map that you apply to PBR materials. Starting from r131, the engine is doing this for you so you don't have to worry about PMREMGenerator at all.
I'm trying to recreate a classroom with individual students and furniture. It should be individual group of models that can be later assigned to a database to toggle on and off at will to simulate who's attending and who's missing in class. This is my block of code to load one native threejs model called "desk" and one animated GLTF model into the scene:
import {GLTFLoader} from "./GLTFLoader.js"
import * as THREE from 'three'
var unit = new THREE.Group();
var deskGeometry = new THREE.BoxBufferGeometry(10, 2, 50 );
var deskMaterial = new THREE.MeshPhongMaterial({ color: 0x49311c, side: THREE.DoubleSide });
var desk = new THREE.Mesh(deskGeometry, deskMaterial);
unit.add(desk);
//IMPORT GLTF MODEL
var loader = new GLTFLoader();
var clock, mixer;
clock = new THREE.Clock();
loader.load("./models/salary/scene.gltf", function(gltf){
gltf.scene.traverse( function( node ){
if(node.isMesh){node.castShadow = true, node.receiveShadow = false;}
});
//add and position the GLTF model
var obj = gltf.scene;
gltf.scene.scale.set( 8, 8, 8 );
gltf.scene.position.x = -10;
gltf.scene.position.y = -5;
gltf.scene.position.z = 3;
gltf.scene.rotation.y = 1.07;
scene.add(obj);
unit.add(obj); // unit is part of an array that the model is nested in,
//to create a THREE.group consisted of the student's desk, pc and the student
//Playing Animation
mixer = new THREE.AnimationMixer( gltf.scene );
console.log( gltf.animations );
mixer.clipAction( gltf.animations[ 0 ] ).play();
});
return unit;
}
function animate(){
requestAnimationFrame(animate);
renderer.setAnimationLoop(()=>renderer.tick());
//for GLTF
if ( mixer ) mixer.update( clock.getDelta() );
}
The above code also implies that the GLTF model is part of a group of model called "unit", and that there are native threejs models mixed in. In the near future I wish to replace "desk" with a proper GLTF model. So I tried using promise to load multiple models like this https://redstapler.co/load-multiple-model-three-js-promise/ , however, it only showed how to import static models without animations.
How should I use promise to load multiple animations as well, while nested inside a THREE group?
I am trying to work with javascript, classes, and threejs to make a project. I have an idea to have a singular function create a new threejs object, but not sure how to implement it.
Let me go a bit more in detail. I have a class that creates a cube using threejs:
class Cube {
constructor(geometry, material, /*position variables*/, scene) {
this.geometry = geometry;
this.material = material;
/* this.positions */
}
createMesh() {
//creates a mesh for the cube
this.mesh = new THREE.Mesh( this.geometry, this.materials );
}
addToScene() {
this.scene.add( this.mesh );
/* changes position with variables */
}
}
This class works nicely, but I am wanting to create a new function that makes a unique cube, and with a custom variable. I want to create something like this:
var createCube = function ( name, geometry, material, /*position*/, scene) {
name = new Cube(geometry, material, /*position*/, scene;
}
Then after I use this function, I can use the name in the parameter as such:
createCube( customName, cubeGeometry, cubeMaterial, /*position*/, threeScene);
customName.createMesh();
customName.addToScene();
I realize I can always hard code the name for the cube, however, I will be passing it through loops to create multiple.
I gave a lot of explanation for a likely simple solution, but I hope this helps give a picture of what I am trying to do. If you need more explanation, I am open to do so.
I'm not entirely sure I understand the problem here. I might be missing something.
If a Cube needs to be identified by name, could you add it as a property of the Cube?
class Cube {
constructor(name, /* other properties */) {
this.name = name;
/* other properties */
}
createMesh() {
}
addToScene() {
}
}
const names = ['cube1', 'cube2', 'cube3'];
const cubes = names.map(name => new Cube(name, geometry, material, /*position*/, scene));
cubes.forEach(cube => {
console.log(`cube: ${cube.name}`);
cube.createMesh();
cube.addToScene();
});
You can't do that, JS does not allow passing references as method arguments.
What you want to eventually achieve is unclear to me, here is my attempt to have custom named cubes on a cubesObject.
const cubesObject = {};
for (const name of ['a', 'b', 'c']) {
cubesObject[name] = new Cube(geometry, material, /* position */, scene);
}
console.log(cubesObject.a, cubesObject.b, cubesObject.c)
A better way to do this dynamically is to create an array and push an object to it. I got a similar output when working with node applications.
var cubesArray = []
function createCube(name, geometry, material, /*position*/, scene) {
let thisCube = new Cube(geometry, material, /*position*/, scene);
cubesArray[name] = thisCube;
}
Now we can do all the functions and access properties with: cubesArray[name].property or cubesArray[name].function()
I am using ThreeJS to load OBJs into a webpage, which I have done succesfully, but now I want to add buttons to my page that will swap out the displayed OBJ file for a different one. I have attempted to name the object when loading it:
object.name = "selectedObject";
so that I can remove it from the scene when the new button is clicked
scene.remove( selectedObject );
and attach the new object:
scene.add(newobject);
But I am getting lost in how to implement this into the general code/what the correct syntax would be.
Here's the code for loading the model:
var objectloading = 'obj/male02/new.obj';
var loader = new THREE.OBJLoader( manager );
loader.load( objectloading, function ( object ) {
object.traverse( function ( child ) {
if ( child instanceof THREE.Mesh ) {
child.material.map = texture;
}
} );
object.position.y = -30;
scene.add( object );
}, onProgress, onError );
Any help is apreciated, thanks!
Well there's many ways to go about it. What it comes down to is that your code needs to account for what has been loaded. You can traverse a scene, but capturing and listing your obj files into specific lists on your own is much cleaner, especially later when implementing things like raycasting.
I would write some functions, perhaps even a class if I planned on supporting other mesh types in the future and wanted a single interface. Importantly, you do not pass the mesh name as the parameter to scene.add and scene.remove, you pass a reference to the actual object. Three.js does this so that it can nullify the parent and call the object "removed" dispatch event in the Three.js library.
So for example purposes, one way is to store your objects in a hash, and use the url to the mesh as the parameter for adding and removal.
var meshes = {};
addObj = function(url){
var objectloading = url;
var loader = new THREE.OBJLoader( manager );
loader.load( objectloading, function ( object ) {
object.traverse( function ( child ) {
if ( child instanceof THREE.Mesh ) {
child.material.map = texture;
}
} );
object.position.y = -30;
meshes[url] = object;
scene.add(object);
}, onProgress, onError );
}
removeObj = function(url){
scene.remove(meshes[url]);
delete meshes[url];
}
for example, toggle between two models,
in a button click:
removeObj('obj/male02/old.obj');
addObj('obj/male02/new.obj');
and then in another button click:
removeObj('obj/male02/new.obj');
addObj('obj/male02/old.obj');
Although any String can be used for member names in "meshes," using urls could become problematic if the application grows and the url is actually a service uri utilizing a POST request, then you'll need another layer of references, possibly and usually using the UUID give to each object added to Three.js.
I'm trying to use three.js to import and render an object I made. Everything was find, I even succeded to apply a wireframe texture.
But i wanted to apply a Point cloud texture (here) but either it just display a color on my object either i get an error like writte non the tittle
my code is like that
var loader = new THREE.OBJLoader( manager );
loader.load( 'obj/moimeme2.obj', function ( object ) {
object.traverse( function ( child ) {
if ( child instanceof THREE.Mesh ) {
child.material = new THREE.PointCloudMaterial( {color: 0x6FF060 } );
}
} );
/*object.scale.y = 5;
object.scale.x = 5;
object.scale.z = 5;*/
scene.add( object );
}, onProgress, onError );
I'm kinda a beginner in JS and i don't really get what is the problem this
Thank you for reading !
Point cloud material is for point cloud geometry. Not for regular geometry.