Three.js Hemisphere Light - three.js

I`m examining a different types of light with dat.GUI and three.js (r72) and get stucked on dinamically turning on/off the HemisphereLight.
I have a one instance of each light being added to the scene:
var pointLight = new THREE.PointLight(this._whiteColor);
pointLight.visible = false;
var hemisphereLight = new THREE.HemisphereLight(this._whiteColor, this._whiteColor);
hemisphereLight.visible = false;
ect...
and a buttons for turning on/off with simple handler. Like this:
me._sceneObjects.hemisphereLight.visible = value;
So, before rendering all lights are present in the scene, but not visible.
When executing a handler for Hemisphere light - it stay invisible. After excluding hemisphereLight.visible = false; works fine.
Currently I`m disabling this light after rendering a 1st frame:
function render() {
some code ...
if (!sentenceExecuted && firstCall > 0) {
hemisphereLight.light.visible = false;
sentenceExecuted = true;
} else {
firstCall++;
}
};
I will be grateful for any suggestions to fix this without workaround.
Sorry for possible mistakes in English.

WestLangley, thank you for the link to Wiki article.
After reading and trying the examples I have found my mistake.
Originally I wanted to add "invisible" (using Object3D.visible) for render lights into a scene and then turn them on/off dynamically.
Some lights (in my case HemisphereLight and SpotLight) do not work this way because of internal three.js rendering algorythm (buffers for geometries and materials were built without considering my lights).
To achieve dynamic lightning an author of the article suggest to:
Add light with intensity = 0 and then increase it (such light is taken into account by render)
Force material to be updated (material.needsUpdate = true) for affected scene objects after setting light visibility to true.

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);
});

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.

ILNumerics: Export part of a scene as image without affecting original scene

I have created a Scene with ILNumerics that consists of 3 PlotCubes and a Colorbar.
Screenshot of the ILPanel
I wanted to add a method that exports the scene as an image in two ways, the first being the screenshot you see above.
The second export is supposed to only show the centric cube.
I attempted to follow the guidelines of ILNumerics for scene management.
I wrote the following code:
public void ExportAsImage(int resolutionWidth, int resolutionHeight, string path, bool includeSubCubes)
{
using (ILScope.Enter())
{
ILGDIDriver backgroundDriver = new ILGDIDriver(resolutionWidth, resolutionHeight, ilPanel1.Scene);
if (includeSubCubes)
{
// code for standard export here
}
else
{
// setting left and top cube and color bar invisible and
// adjusting main cube size is affecting the ilPanel.Scene
backgroundDriver.Scene.First<ILColorbar>().Visible = false;
GetElementByTag<ILPlotCube>(backgroundDriver.Scene, _leftCubeTag).Visible = false;
GetElementByTag<ILPlotCube>(backgroundDriver.Scene, _topCubeTag).Visible = false;
GetElementByTag<ILPlotCube>(backgroundDriver.Scene, _mainCubeTag).ScreenRect = new RectangleF(0, 0, 1, 1);
GetElementByTag<ILPlotCube>(backgroundDriver.Scene, _mainCubeTag).DataScreenRect = new RectangleF.Empty;
backgroundDriver.Scene.Configure();
backgroundDriver.Render();
// save image
backgroundDriver.BackBuffer.Bitmap.Save(path,System.Drawing.Imaging.ImageFormat.Png);
// revert changes done to cubes and color bar
backgroundDriver.Scene.First<ILColorbar>().Visible = true;
GetElementByTag<ILPlotCube>(backgroundDriver.Scene, _leftCubeTag).Visible = true;
GetElementByTag<ILPlotCube>(backgroundDriver.Scene, _topCubeTag).Visible = true;
AdjustCubeSizes();
}
}
}
Note: "GetElementByTag" is an own implementation to retrieve objects in the ILNumerics Scene.
I first expected that the new driver basically creates a copy of the Scene I can work on, but like the code shows I have to revert all changed after the export or the displayed ilPanel only shows the scene the way I exported it.
Is it possible at all to do export to image without affecting the real Scene? Am I just missing some details?
Regards,
Florian S.
Florian, it does make a copy. But you need to add the interesting part to a new scene. The magic is happening in the Add() method:
var scene4render = new ILScene();
scene4render.Add(oldScene.First<ILPlotCube>(mytag));
// ... configure scene4render here, it will be detached from the original scene
// with the exception of shared buffers.
// ... proceed with rendering
In order to also include + render interactive state changes to the original plot cube (let's say rotations by the users mouse) you'd use something like that:
scene4render.Add(panel.SceneSyncRoot.First<ILPlotCube>(mytag));
Also, I wonder what GetElementByTag does better than ILGroup.First<T>(tag, predicate) or ILGroup.Find<T>(...)?
See also: http://ilnumerics.net/scene-management.html

Animations stretching geometry

I read that the latest threejs exporter added support for multiple animations so I created a quick experiment and exported a model with the latest plugin..after a bit of playing around with the code I managed to get each of the animations within the model playing, however the geometry is getting skewed horribly.
I'm pretty sure the issue is related to the following error: "gl.getProgramInfoLog() WARNING: Could not find vertex shader attribute 'position' to match BindAttributeLocation request." but not positive. Maybe I'm just not aware of something, such as a particular blender export flag configuration or something else that needs to be set within the code. Here's the important parts:
for (var i = 0; i < materials.length; i++) {
var mat = materials[i];
mat.skinning = true;
}
scene.add(mesh);
// add animation data to the animation handler
var animations = [];
for(var a in mesh.geometry.animations) {
THREE.AnimationHandler.add(mesh.geometry.animations[a]);
var animation = new THREE.Animation(mesh,mesh.geometry.animations[a].name);
animations.push(animation);
}
animations[0].play();
Any ideas guys? Here's a screenshot: https://drive.google.com/file/d/0B6zdGNflpdJLSVVHemszWWFTTHc/edit?usp=sharing

three.js object is black before texture loads - can I change this behavior?

I am very new to three.js. In my project you can move through a series of planes with cross section images of an object. The problem is that the material doesn't load right away and moving up and down too quickly causes some of the planes to display black. I need to change this behavior. Is there a way to either
change some property so the plane is transparent - but the image should still be opaque when loaded
or don't display/render the plane at all until the texture is loaded?
I'm not at all sure I am on the right track, and I am hoping someone more experienced can suggest a specific fix.
Thanks!
Not sure if you already cleared this up but I made a handy little function to take care of this by modifying the opacity setting, the basic of which are:
function loadTexture( path ){
var mat = new THREE.MeshBasicMaterial({
map: new THREE.ImageUtils.loadTexture( path, null, function() {
mat.opacity = 1;
} ),
opacity: 0
});
return mat;
}

Resources