spotLightHelper not pointing to target when loaded from json scene - three.js

I am using the latest version of Three.js(82) and importing my spot light from blender exporter(json). I have the following code when looping over all the scene objects after loading:
// loop
if(object instanceof THREE.SpotLight){
lightHelper = new THREE.SpotLightHelper(object);
scene.add(lightHelper);
}
// after loop
spot = scene.getObjectByName("Spot",true);
spot.target = scene.getObjectByName("Cube",true);
// in render() funcition
lightHelper.update();
The spotlight helper shows up but it never points to the target. If I try to add a spotlight to the scene manually, it works fine. I think it has to do something with the spotlight being in the child scene. Can anyone suggest a fix for this?

Related

Problem to get correct bounding box around the mesh and raycasting for gltf model with skinnedmesh

The idea is to import a gltf model into my scene and enclose all the children object of it inside a single bounding box. In most of the cases, these works without any issue. But in some cases when some of the children are skinnedmesh, bounding box is not covering all the children.
Please try with Test.glb - Google Drive so you can understand the issue. Even the issue can be seen in Three.js Editor too.
Also I can not raycast it correctly.
Can you please help me to sort out? I have already read about having manual bounding box or/and frustumCulled=false of skinned mesh and I need to load models dynamically sothat can not manually define the Bounding Box.
loader.load(filename,
function (gltf) {
let mgroup = new THREE.Group();
while (gltf.scene.children.length > 0) {
var child = gltf.scene.children[0];
if (child.isObject3D) {
mgroup.add(child);
}
}
scene.add(mgroup);
const aabb = new THREE.BoxHelper(mgroup);
scene.add(aabb);
});

Aframe Load lightmap after loading GLTF - lightmap not showing

I'm trying to add a lightmap to some mesh after loading them from a GLTF file.
All my objects have 2UV channel.
I'm waiting 'object3dset' and here is my code :
const mesh = this.el.getObject3D('mesh');
var textureLoader = new THREE.TextureLoader();
textureLoader.load("lightmap.png", function(lmap){
mesh.traverse((node) => {
if (!node.isMesh) return;
node.material.lightMap = lmap;
lmap.flipY = node.material.map.flipY; //needed to flip the texture
node.material.needsUpdate = true;
});
});
If I replace the material with a new one and set the lightmap, it's working.
But I want to find a way without recreating all materials.
The lightmap was loaded, but not easy to see.
By default metalness from Khronos Blender Exporter converted in threejs after loading GLTF result to a level 1.0. With this configuration, the lightmap is hard to see and is not corresponding to what we see in Blender.
I hope my mistake can help someone else losing too much time.

THREE.js repeating UV texture using JSONLoader

I need help for getting UV Textures to be rendered correctly in three.js. I've created a model with repeating tile texture in Blender. The tile texture is applied using UV mapping, and it looks like this if it is being rendered correctly:
Render image using Blender
.However, when it is loaded using JSONLoader by three.js, the tiles are just stretched to fill each polygon, giving weird result like this:Screenshot of render using three.js
. I've tried setting THREE.RepeatWrapping in my code but nothing changed:
bodyLoader = new THREE.JSONLoader();
bodyLoader.load('./starofthesea_threejs.json', function(geometry, materials) {
mainBodyMaterials = new THREE.MeshFaceMaterial(materials);
console.log(materials);
mainBodyMaterials.wrapS = THREE.RepeatWrapping;
mainBodyMaterials.wrapT = THREE.RepeatWrapping;
mainBodyMaterials.needsUpdate = true;
mainBody = new THREE.Mesh(geometry, mainBodyMaterials);
mainBody.traverse ( function (child) {
if (child instanceof THREE.Mesh) {
child.castShadow = true;
child.receiveShadow = true;
}
});
mainBody.scale.x = mainBody.scale.y = mainBody.scale.z = 1;
geometry.computeBoundingBox();
geometry.computeFaceNormals();
geometry.computeFlatVertexNormals();
scene.add(mainBody);
});
Is there anything wrong in my code, or workaround to get it rendered correctly? All help is deeply appreciated.
Finally I've figured out the problem by myself, where both the Blender model and JS are misconfigured. RepeatWrapping should be applied to texture but not material. I need to study the structure of THREE.MeshFaceMaterial to find the handle for the underlying textures. I need to traverse through the materials to find out all materials with image textures:
mainBodyMaterials = new THREE.MeshFaceMaterial(materials);
for(prop in mainBodyMaterials.materials) {
if(mainBodyMaterials.materials[prop].map != null) {
mainBodyMaterials.materials[prop].map.wrapS = THREE.RepeatWrapping;
mainBodyMaterials.materials[prop].map.wrapT = THREE.RepeatWrapping;
tex.push(mainBodyMaterials.materials[prop].map.clone());
tex[tex_sequence].needsUpdate = true;
tex_sequence++;
}
}
After applying wrapS and wrapT to textures correctly, one of the tile materials get rendered correctly, but 'Texture marked for update but image is undefined' error keep throwing out. I need to clone the texture to get rid of the error, according to another question: Three.js r72 - Texture marked for update but image is undefined?
As there are several materials with repeating tiles, I need to create a global array at the beginning of the JS routine, and push the modified textures one by one when looping through the materials:
var tex = new Array();
var tex_sequence = 0;
After fixing the JS calls, one of the textures are still not working. I forgot that only ONE UV slot is allowed for three.js. I need to unwrap the UVs again under the same UV slot in Blender. Everything works like a charm, and I hope my painful experience can help those who are getting mad by similar problems.

Clean up Threejs WebGl contexts

I have a problem while cleaning up my WebGl-Scenes. I'm using Three.js with a WebGlRenderer. In my application I have to change the views quite often and therefore need to render new scenes all the time. Uptil now I destroy and reinitialize the entire Threejs scene. After switching the scenes about 15 - 20 times I get following warning:
WARNING: Too many active WebGL contexts. Oldest context will be lost.
After switching a couple of times more the context is lost completly and the application crashes.
Is there a way to destroy the current WebGl context, when cleaning up? Or does the WebGlRenderer always create a new WebGl context when being instantiated?
I'm using Three.js R64.
I've got same problem, but i couldn't solve it using SPA, because of requirements.
There is .forceContextLoss() method in WebGLRenderer (rev 71, maybe was early) for this situations.
So, my code in 'deallocate' method is somemethig like
_self.renderer.forceContextLoss();
_self.renderer.context = null;
_self.renderer.domElement = null;
_self.renderer = null;
You can keep the same renderer for different scenes. The renderer does not care what scene it will render. You can supply a different Scene everytime you call render() if you like.
// instantiate only once and keep it
var renderer = new THREE.WebGLRenderer();
// current scene and camera. Switch whenever you like
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(...);
fillScene(scene);
// rendering always uses current scene
function render() {
renderer.render(scene, camera);
requestAnimationFrame(render);
}
/* ...
* somewhere in your application
* ...
*/
if(condition) {
// switch scene
scene = new THREE.Scene();
fillOtherScene(scene);
}
You should create and use only one WebGlRenderer. In my SPA (single page application) I had weird problem with camera/scene in THREE.js after few redirects. It was because WebGlRenderer was created every time when one particular page was rendered. There was no error in console log (only the warning you wrote).
Bug appeared as change in camera position and problems with rendering.

Can't seem to make a functional THREE.js collada loader

I'm having issues getting a custom made collada object with no built in camera or lighting to render. I more or less copied what I had seen in a few collada examples to create my own loader, which looks like this:
var loader = new THREE.ColladaLoader();
var room, scene, stats;
loader.load('../Models/Rooms/boot.dae', function colladaReady( collada ){
collada.scene.getChildByName('Cube',true).doubleSided = true;
room = collada.scene;
room.scale.x = room.scale.y = room.scale.z = 1;
room.updateMatrix();
init();
});
The init function is fairly basic and looks like this
scene = new THREE.Scene();
scene.add( room );
scene.add( camera );
renderer.render(scene, camera);
Here is the actual object I'm trying to render. I have also tried it out with the monster.dae file that is in the examples folder without success. The Chrome javascript console isn't showing any errors, so I'm not quite sure where to look in my code. It all resembles functional examples, so I'm not sure why it's not functional. Is there something I'm unaware of that is relevant to collada loading?
RESOLVED: The item was rendering, but had no skin or texture associated with it. So it was rendering at the same colour as the background, which understandably appears to not be rendering at all. Discovered by adding a grid to the ground just to check.

Resources