How to resize collada models to a given size - three.js

I will resite a collada model to a user given size...
Maybe with patterns, maybe with scalling only.
My actual idea is to implement a bounding box with the given sizes. And then scale the collada until it hits one side of the bounding box.
But maybe there are better solutions?

You want to resize a model to a given size. The model may have child meshes.
One solution is to determine the model's bounding box.
var box = new THREE.Box3().setFromObject( model );
var boxCenter = box.center();
var boxSize = box.size();
Then, depending on your criteria, you can reset the model's scale and position:
model.position.set( x, y, z );
model.scale.set( s, s, s ); // same value for each component to prevent distortion
How you determine the new position and scale is up to you.
three.js r.71

Related

Get screen coordinates of a vertex in a THREE.js Points object using bufferGeometry

I want to have a DOM node track a particle in my THREE.js simulation. My simulation is built with the Points object, using a bufferGeometry. I'm setting the positions of each vertex in the render loop. Over the course of the simulation I'm moving / rotating both the camera and the Points object (through its parent Object3d).
I can't figure out how to get reliable screen coordinates for any of my particles. I've followed the instructions on other questions, like Three.JS: Get position of rotated object, and Converting World coordinates to Screen coordinates in Three.js using Projection, but none of them seem to work for me. At this point I can see that the calculated projections of the vertices are changing with my camera movements and object rotations, but not in a way that I can actually map to the screen. Also, sometimes two particles that neighbor each other on the screen will yield wildly different projected positions.
Here's my latest attempt:
const { x, y, z } = layout.getNodePosition(nodes[nodeHoverTarget].id)
var m = camera.matrixWorldInverse.clone()
var mw = points.matrixWorld.clone()
var p = camera.projectionMatrix.clone()
var modelViewMatrix = m.multiply(mw)
var position = new THREE.Vector3(x, y, z)
var projectedPosition = position.applyMatrix4(p.multiply(modelViewMatrix))
console.log(projectedPosition)
Essentially I've replicated the operations in my shader to derive gl_Position.
projectedPosition is where I'd like to store the screen coordinates.
I'm sorry if I've missed something obvious... I've tried a lot of things but so far nothing has worked :/
Thanks in advance for any help.
I figured it out...
var position = new THREE.Vector3(x, y, z)
var projectedPosition = position.applyMatrix4(points.matrixWorld).project(camera)

Three.js children to ignore scaling of parent object

I am trying to model a galaxy that displays some stars. The planets are children of the star mesh.
When you zoom, the star mesh gets bigger but I want at a certain zoom level, that the star remains the same size and only the planets increase in reference to the zoom scale.
This code is working just fine, but I am wondering if this is the best way and maybe there is another, better way to achieve this:
var scale = instance.controls.scale;
obj.scale.set(obj.scale.x*scale,obj.scale.y*scale,obj.scale.z*scale);
for (var c = 0; c < obj.children.length; c++) {
var child = obj.children[c];
child.scale.set(child.scale.x/scale,child.scale.y/scale,child.scale.z/scale);
}
The scale variable comes from the camera control that informs me how much zoom is applied. Zoom in will result in scale > 1 and scale out will result in scale < 1
In order to keep my star the same size if I zoom, I have to multiply it by the scale factor but because my planets are children of the star, I need to negate the scaling by doing the opposite.
Add an extra container between the parent object and the children, like so:
var container = new THREE.Group();
obj.add( container );
containter.add( child );
Then,
obj.scale.multiplyScalar( scale );
container.scale.divideScalar( scale );
three.js r.71

Make text always appear orthogonal to the plane when rotating a cube

I'm creating text labels that appear on a 3D cube using the following pattern:
canvas = createTextCanvas(text, color, font, size);
texture = new THREE.Texture(canvas);
geom = new THREE.PlaneBufferGeometry(canvas.width, canvas.height, segW, segH);
material = new THREE.MeshBasicMaterial({map: texture, transparent: true});
mesh = new THREE.Mesh(geom, material);
mesh.position.x = x;
mesh.position.y = y;
mesh.position.z = z;
texture.needsUpdate = true;
The labels and their positions get set within a for loop for each edge of the cube. This results in labels appearing similar to this:
But then when I rotate the cube (using OrbitControls), you'll see that the label no longer appears vertically like above:
So using the Cost label as an example, I would want the text to remain vertically oriented whenever the cube is rotated. Basically, I'm trying to mimic the behavior of axis labeling in VTK.
So I believe the solution here is to set the up vector of the label to a vector that's always orthogonal to the plane. But I'm not sure how to implement this. Any suggestions or examples would be greatly appreciated.
If it helps, I'm constructing the cube using a BoxGeometry and MeshNormalMaterial.
Do you mean the label keeps moving with the cube or not?
If not, there is a example: http://stemkoski.github.io/Three.js/Sprite-Text-Labels.html. The label keeps facing to you but may not vertical.
Else ,you may need a canvas texture,the label is a object just like the cube and you can set its position to keep it vertical.But it doesn't look good sometime.the example:http://stemkoski.github.io/Three.js/Texture-From-Canvas.html.
I think you just want the label always facing to you when you change your sight.

Setting the projectionMatrix of a Perspective Camera in Three.js

I'm trying to set the ProjectionMatrix of a Three.js Perspective Camera to match a projection Matrix I calculated with a different program.
So I set the camera's position and rotation like this:
self.camera.position.x = 0;
self.camera.position.y = 0;
self.camera.position.z = 142 ;
self.camera.rotation.x = 0.0;// -0.032
self.camera.rotation.y = 0.0;
self.camera.rotation.z = 0;
Next I created a 4x4 Matrix (called Matrix4 in Three.js) like this:
var projectionMatrix = new THREE.Matrix4(-1426.149, -145.7176, -523.0170, 225.07519, -42.40711, -1463.2367, -23.6839, 524.3322, -0.0174, -0.11928, -0.99270, 0.43826, 0, 0, 0, 1);
and changed the camera's projection Matrix entries like this:
for ( var i = 0; i < 16; i++) {
self.camera.projectionMatrix.elements[i] = projectionMatrix.elements[i];
}
when I now render the scene I just get a black screen and can't see any of the objects I inserted. Turning the angle of the Camera doesn't help either. I still can't see any objects.
If I insert a
self.camera.updateProjectionMatrix();
after setting the camera's projection Matrix to the values of my projectionMatrix the camera is set back to the original Position (x=0,y=0,z=142 and looking at the origin where I created some objects) and the values I set in the camera's matrix seem to have been overwritten. I checked that by printing the cameras projection Matrix to the console. If I do not call the updateProjectionMatrix() function the values stay as I set them.
Does somebody have an idea how to solve this problem?
If I do not call the updateProjectionMatrix() function the values stay as I set them.
Correct, updateProjectionMatrix() calculates those 16 numbers you pasted in your projection matrix based on a bunch of parameters. Those parameters are, the position and rotation you set above, plus the parameters you passed (or default) for the camera. (these actually make the matrixWorld and its inverse.
In case of a perspective camera, you don't have much - near, far, fov and aspect. Left,right,top,bottom are derived from these, with an orthographic camera you set them directly. These are then used to compose the projection matrix.
Scratch a pixel has a REALLY good tutorial on this subject. The next lesson on the openGL projection matrix is actually more relevant to WebGL. left right top and bottom are made from your FOV and your aspect ratio. Add near and far and you've got yourself a projection matrix.
Now, in order for this thing to work, you either have to know what you're doing, or get really lucky. Pasting these numbers from somewhere else and getting it to work is short of winning the lottery. Best case scenario, you can have your scale all wrong and clipping your scene. Worst case, you've mixed a completely different matrix, different XYZ convention, and there's no way you'll get it to work, or at least make sense.
Out of curiosity, what are you trying to do? Are you trying to match your camera to a camera from somewhere else?

Manual frustum culling with three.js

I'm working on a voxel game with three.js. For this, I need to generate as many chunk as required to fill the screen. Currently, I'm loading a circle of radius 20 around the player.
What is the simplest way to compute the exact range of chunks required to fill the camera frustrum and avoid computing invisible chunks ?
Every chunk has the exact same size (let's say we have a vector size with the correct value), and are at Y=0 (X and Z varying).
var frustum = new THREE.Frustum();
frustum.setFromMatrix( new THREE.Matrix4().multiply( camera.projectionMatrix, camera.matrixWorldInverse ) );
for (var i=0; i<objects.length; i++) {
objects[i].visible = frustum.intersectsObject( objects[i] );
}
only objects that are within camera frustum will be rendered
documented here
hope this helps you?

Resources