i've been tinkering around with three.js and i have a canvas i'd like to use as kind of a GUI. for that i have to check if an object is in the camera frustum.
my current code:
camera.updateMatrix();
camera.updateMatrixWorld();
var frustum = new THREE.Frustum();
var projScreenMatrix = new THREE.Matrix4();
projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );
frustum.setFromProjectionMatrix( camera.projectionMatrix );
if(frustum.containsPoint( mesh.position )){
//stuff happens...
};
frustum.containsPoint()keeps returning false. what am i doing wrong here?
Your code is using
frustum.setFromMatrix( camera.projectionMatrix );
But that isn't the matrix you want. Instead use:
frustum.setFromMatrix( new THREE.Matrix4().multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ) );
as answered in How to determine if plane is in Three.js camera Frustum
Three.js is doing view frustum Culling internally and only rendering when in camera frustum. Assuming that your Boundig Volumes are calculated correct, you can track weather a renderable Object3D is inside the camera view frustum when Object3D.onBeforeRender callback is called in your current frame
Related
I have a camera drone animation model that I attach two objects to. The camera drone is just a black sphere with a texture. I attach a red sphere to the camera drone where the lens appears on its textureis, to make it look like a security camera lens. Works great. When I move the model, the red sphere moves with the camera drone perfectly as it moves and rotates.
However, I also attach a spotlight at the exact same place on the camera drone object. My desire is to have the spotlight beam come out of the camera drone lens so that it appears to emanate from the lens. However, when the camera drone moves, the spotlight stays in place and gets left behind, despite the fact I attach the spotlight the exact same way and in the exact same place as I attach the red sphere. In other words, when the camera drone moves away, I see the spotlight hanging in space where it was first created instead of it traveling in lock step with the camera drone.
Below is the code I use to create and attach the red sphere and spotlight. The code executes when the GLB loader callback executes.
Note: self.CAC.modelInstance is where the ThreeJS object for the camera drone animation model is stored. Also, AnimatedLight is the object I created to build a spotlight and animate it. Finally, initModelArgs is an object that contains some size, position, and other settings that are loaded from a file earlier.
Can someone tell me what I am doing wrong and how to fix this problem? Also, can you tell me what it is about the way that I think how the spotlight should work that is also wrong?
// PARAMETERS: url, onLoad, onProgress, onError
self.CAC.modelLoader.load(
// url
urlToModel,
// onLoad
(glb) => {
// Size.
glb.scene.scale.x = initModelArgs.theScale;
glb.scene.scale.y = initModelArgs.theScale;
glb.scene.scale.z = initModelArgs.theScale;
self.CAC.setModelInstance(glb.scene);
// Set the initial position.
self.CAC.modelInstance.position.x = initModelArgs.initialPos_X;
self.CAC.modelInstance.position.y = initModelArgs.initialPos_Y;
self.CAC.modelInstance.position.z = initModelArgs.initialPos_Z;
// Create an animation mixer for this model.
self.CAC.modelAnimationMixer = new THREE.AnimationMixer(self.CAC.modelInstance);
// Speed
self.CAC.modelAnimationMixer.timeScale = initModelArgs.theTimeScale;
// Add the model to the scene.
g_ThreeJsScene.add(self.CAC.modelInstance);
// Initialize the model completely. The camera drone has no
// animations because we animate it manually, so we pass
// NULL to let the initializeModelCompletely() function
// know that.
self.CAC.initializeModelCompletely(null);
// NOTE: Camera drone has no animations/actions. We animate it
// manually.
// -------------------- BEGIN: SUB-OBJECTS ------------
// Call updateCenterOfModel so our bounding box and center properties
// are correct.
self.CAC.updateCenterOfModel();
// Create the sub-objects necessary for emulating a light
// projector on the camera drone.
// .................... BEGIN: SUB-OBJECT - Camera Lens ............
const radius = 3;
const cameraLensObj =
new THREE.Mesh(
new THREE.SphereBufferGeometry( radius, 20, 20 ),
new THREE.MeshPhongMaterial( { color: 0xFF0000 } ));
cameraLensObj.position.set(0, 0, 15);
// Add it to the top level animation model.
self.CAC.modelInstance.add(cameraLensObj);
// .................... END : SUB-OBJECT - Camera Lens ............
// .................... BEGIN: SUB-OBJECT - Light Beam ............
const spotLightAsLightBeam_anim_obj =
new AnimatedLight(
`${self.CAC.modelName}-lens-light-beam`,
modelDeclJsonObj,
'SpotLight',
// Tell the animated light to augment our mini-menu
// instead of creating its own.
self);
// Call initialize model on the spotlight or we will not have
// the model instance filled in.
spotLightAsLightBeam_anim_obj.initializeModel(self.CAC.parentAnimManagerObj, initModelArgs);
const spotLightModelInstanceObj = spotLightAsLightBeam_anim_obj.CAC.modelInstance;
// Position the spotlight that acts as the camera drone's light
// beam right on top of the small sphere we use to emulate
// a projector's lens.
spotLightModelInstanceObj.position.set(0, 0, 15);
// Add it to the top level animation model.
self.CAC.modelInstance.add(spotLightAsLightBeam_anim_obj.CAC.modelInstance);
// .................... END : SUB-OBJECT - Light Beam ............
I have to rotate the camera during initial loading of object in three js.
So can anyone help me in which way i have to do that.Can i use Perspective Camera for this ?
for reference
https://theyearofgreta.com/
It is possible to tween the camera movement on the initial load of the object.
new TWEEN.Tween(currentPosition)
.to(targetPosition, 2000)
.onUpdate(function () {
camera.position.set(...currentPosition);
camera.lookAt(new THREE.Vector3(0, 0, 0));
});
I made a simple example to showcase the movement:
https://codepen.io/cdeep/pen/ZEygVNy
Basics of using tween for three.js animations:
http://learningthreejs.com/blog/2011/08/17/tweenjs-for-smooth-animation/
I cannot get post-processing to work with EffectComposer and BloomPass
I've looked at the past stack overflow posts including making sure that there is a renderpass, bloompass, and then a copyshader, with rendertoscreen set to true on the last pass, but nothing seems to work.
Here is my code:
(I render a simple cylinder earlier)
var renderModel = new THREE.RenderPass( scene, camera );
var effectCopy = new THREE.ShaderPass(THREE.CopyShader);
var effectBloom = new THREE.BloomPass ( 1, 25, 5);
effectCopy.renderToScreen = true;
renderer.autoClear = false;
var composer = new THREE.EffectComposer( renderer );
composer.setSize( width,height );
composer.addPass( renderModel );
composer.addPass( effectBloom );
composer.addPass(effectCopy);
and then I render the scene with
composer.render( 0.05 );
instead of
renderer.render( scene, camera );
Expected result is just a cylinder rendered in the scene(when I comment out adding the bloom and copy pass to the effect composer)
Cannot post images because this is my first question, but it renders a light blue cylinder with a black background.
But instead I just get a black screen when I add the passes.
I have tried doing different combinations such as just the rendermodel and bloom effect but it still doesn't work.
I am using webgl2 if that has any significance.
In case anyone is having trouble and this solution works:
It ended up being some problem with the three.js I was importing from a cdn.
(https://cdnjs.cloudflare.com/ajax/libs/three.js/97/three.js)
I changed to a minified version of three.js I had downloaded earlier and post-processing started to work again.
Hopefully, this helps anyone with similar problems.
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.
Following method of adding light helper works ok:
var light = new THREE.SpotLight( 0xFFFFFF );
light.position.set(100,100,100);
scene.add(light);
var helper = new THREE.SpotLightHelper( light );
scene.add(helper);
but following will cause helper to be off position:
var wrapper = new THREE.Object3D();
wrapper.position.set(100,100,100);
var light = new THREE.SpotLight( 0xFFFFFF );
wrapper.add(light);
var helper = new THREE.SpotLightHelper( light );
wrapper.add(helper);
scene.add(wrapper);
It seems like helper position is taken from absolute light position to scene, but is then applied from it's wrapper, that means it is actually applied twice a thus doesn't match actual position of the light. In this example, helper would appear on (200,200,200). Same applies for PointLight and probably other light types.
Is it possible to put helpers into wrapper together with light and avoid position problem?
see it demonstrated here: http://jsfiddle.net/wfpxdw37/24/
Light Helpers are just that -- helpers.
They must be added as a child of the scene.
Consider that requirement a feature. :-)
three.js r.69