I'm trying to apply MeshStandardMaterial to a mesh of a GLTF imported model. The GLTF model for testing is a simple cube exported from Blender.
After succesfully load the GLTF model I did:
this.material = new THREE.MeshStandardMaterial({
map: this.texture,
})
this.cubePost2Model = this.resources.items.cubePost2.scene
this.cubePost2Model.traverse((child) =>
{
if(child instanceof THREE.Mesh)
{
child.castShadow = true
child.material = this.material // This line throw the error
console.log(child) // Returns succesfully one mesh
}
})
this.scene.add(this.cubePost2Model)
In the previous code, this line: child.material = this.material throw an error in the console:
Uncaught TypeError: Cannot read properties of undefined (reading 'visible')
When an error happens at that point in projectObject(), it means you are assigning undefined to child.material. So it seems this.material does not point to the intended material object.
Related
been stuck for hours trying to figure out how to make my 3d model spin like a coin spinning. my code is below anything help i really appreciate you guys.
// add a light
const light = new THREE.AmbientLight(0xffffff,5)
scene.add(light);
// controls
// load object
const loader = new THREE.GLTFLoader();
loader.load('yattee.gltf', function (gltf) {
scene.add(gltf.scene);
})
const render = function() {
requestAnimationFrame(render)
// camera.rotation.z += .0010
renderer.render(scene, camera);
}
render();
Try it like so:
let myModel;
const loader = new GLTFLoader();
loader.load( 'model.gltf', function ( gltf ) {
myModel = gltf.scene;
scene.add( myModel );
} );
const render = function() {
requestAnimationFrame(render)
if ( myModel ) {
myModel.rotation.z += 0.01;
}
renderer.render(scene, camera);
}
The problem is, you are defining the model gltf inside a function, which means that it cannot be accessed from render(). In order to spin the model, you need to define the variable gltf prior to loading the model, so it can be stored inside of it:
const loader = new THREE.GLTFLoader();
var gltf; //By defining it prior to loading, it is now in global scope.
loader.load('yattee.gltf', function (gltf) {
scene.add(gltf.scene);
})
Then, you can add the flipping effect in the render() loop. Make sure that you add the given if statement so it doesn't crash before the model even loads!
const render = function() {
requestAnimationFrame(render);
if(gltf) {
gltf.rotation.z += .0010; //Make sure you rotate the gltf, not the camera.
}
renderer.render(scene, camera);
}
And that should do it!
Note: I've taken a look at some of the other answers, and it seems like they either don't work, or they don't explain what they are doing properly. I think that this should help you achieve what you want.
this.loadMyModel = function(){
const loader2 = new THREE.GLTFLoader();
// Load a glTF resource
loader2.load(
// resource URL
'Duck.gltf',
// called when the resource is loaded
function ( gltf ) {
//alert('success');
this.scene.add( gltf.scene );
})
};
The js files have been included.
I got an error, but I don't know why:
TypeError:undefined is not an object (evaluating 'this,scene.add')
Inside of your callback function, this is not the same as outside of the function. For more information on how this works in JS, I'd suggest this article: http://www.digital-web.com/articles/scope_in_javascript/
To fix the issue, you should save a reference to the scene outside the callback:
var scene = this.scene;
this.loadMyModel = function () {
// ...
loader.load( 'foo.glb', function ( gltf ) {
scene.add( gltf.scene );
} );
}
Alternatively, using newer JS features like arrow functions will also get around this problem.
I tried to merge two geometries pre-loaded from two PLY files, the console of the browser told me should be use the BufferGeometryUtils.mergeBufferGeometries() for merge de two geometries into one, but I some problems for call this from the class.
Here is my code:
var scene = new THREE.Scene();
var singleGeometry, material, mesh;
var loader = new THREE.PLYLoader();
function loadPLY(path) {
return new Promise(resolve => {
loader.load(path, result => {
console.log('Success');
resolve(result);
});
});
}
init();
Promise.all([
loadPLY("ply/Paso_1_mandible.ply"),
loadPLY("ply/maxila.ply")
])
.then(geometries => {
geometries.forEach(geometry => geometry.computeVertexNormals());
singleGeometry = new THREE.BufferGeometry();
singleGeometry = THREE.BufferGeometryUtils.mergeBufferGeometries(geometries);
material = new THREE.MeshPhongMaterial({color: 0x0055ff });
mesh = new THREE.Mesh(singleGeometry, material);
mesh.position.y = 1;
mesh.position.z = 1;
mesh.position.x = 1;
mesh.scale.multiplyScalar( 0.0001 );
mesh.castShadow = true;
mesh.receiveShadow = true;
scene.add(mesh);
})
.then(() => {
animate();
})
.catch(err => {console.error(err);});
but I got this error:
TypeError: "THREE.BufferGeometryUtils is undefined"
here is the link to the documentation:
class BufferGeometryUtils
It's in examples/js/BufferGeometryUtils.js in the THREE master distro.
https://github.com/mrdoob/three.js/archive/master.zip
The error TypeError: "THREE.BufferGeometryUtils is undefined" is quite clear.
You need to include the BufferGeometryUtils class / file in your code.
As it is in the examples folder, it is not included in the main Three.js library.
I have pb with threeJS obj, I loaded 3d object and want show only one side of this object not full,
export function loadObjWithMaterial(mtlFile, objFile, imgPath) {
let mtlLoader = new MTLLoader();
mtlLoader.setTexturePath(imgPath);
let url = mtlFile;
return new Promise((resolve, reject) => {
mtlLoader.load(url, materials => {
materials.preload();
let objLoader = new OBJLoader();
objLoader.setMaterials(materials);
objLoader.load(objFile, object => resolve(object));
objLoader.load(objFile, function(object){
resolve(object)
});
});
});
}
and now I tried to show only one side of the object and add this one
mtlLoader.setMaterialOptions({side: 1});
seems now it should show only one side of object but its not.
what i want
what i have now
You can try this one. Anyway 'THREE.FrontSide' is the default value for the side property.
mtlLoader.setMaterialOptions( { side : THREE.FrontSide } );
Here you can see the documentation
i'm trying to load my .obj & MTL file into threejs and apply simple wall collision using raycaster. The scene has walls and other objects.
Used pointer control example
the loading and texturing are in place
problem is when using raycaster it throws an error "cannot read property visible of undefined" I guess my referencing is bad.
i used scene.children for passing objects in raycaster
here is the code for ray caster and obj loader. please let me know where im going wrong
var mtlLoader = new THREE.MTLLoader();
mtlLoader.setBaseUrl( 'neavik/' );
mtlLoader.setPath( 'neavik/' );
mtlLoader.load( 'room.mtl', function( materials ) {
materials.preload();
var objLoader = new THREE.OBJLoader();
objLoader.setMaterials( materials );
objLoader.setPath( 'neavik/' );
objLoader.load( 'room.obj', function ( object ) {
object.position.y = - 5;
object.scale.x=object.scale.y=object.scale.z=0.05
object.traverse( function( child ) { if ( child instanceof THREE.Mesh ) {
if (child.material.name == "Interior_wall") {
child.material = innerwall;
child.castShadow = true;
child.receiveShadow = true;
}
if (child.material.name == "Loby") {
child.material = innerwall1;
child.castShadow = true;
child.receiveShadow = true;
}
if (child.material.name == "TV_Black_Plastic") {
child.material = Black;
child.castShadow = true;
child.receiveShadow = true;
}});
object.name = "object";
scene.add( object );
});
} );
//Raycast
var rayCaster = new THREE.Raycaster(controls.getObject().position, cameraDirection);
var intersects = rayCaster.intersectObject(scene.children, true); //getting error on this line
$("#status").html("camera direction x: " + cameraDirection.x + " , z: " + cameraDirection.z);
// rest of the code
I had the same error and in my case the reason was that the object to be intersected was not existing yet or found at time of intersection.
Therefore I added a kind of null check to prevent this error message:
if (typeof scene != "undefined")