How to Change a Box's dimensions/size after creation? - javascript

One can easily create a THREE.BoxGeometry where you have to pass arguments when creating as three separated arguments for width, height, and depth.
I would like to create any and all THREE[types]() with no parameters and set the values after that.
Is there a way to set the dimensions/size of the box geometry after creation (possibly buried in a Mesh already too)? other then scaling etc.
I couldn't find this in the documentation if so, otherwise maybe a major feature request if not a bug there. Any thoughts on how to classify this? maybe just a documentation change.

If you want to scale a mesh, you have two choices: scale the mesh
mesh.scale.set( x, y, z );
or scale the mesh's geometry
mesh.geometry.scale( x, y, z );
The first method modifies the mesh's matrix transform.
The second method modifies the vertices of the geometry.
Look at the source code so you understand what each scale method is doing.
three.js r.73

When you instantiate a BoxGeometry object, or any other geometry for that matter, the vertices and such buffers are created on the spot using the parameters provided. As such, it is not possible to simply change a property of the geometry and have the vertices update; the entire object must be re-instantiated.
You will need to create your geometries as you have the parameters for them available. You can however create meshes without geometries, add them to a scene, and update the mesh's geometry property once you have enough information to instantiate the object. If not that, you could also set a default value at first and then scale to reach your target.

Technically, scaling only creates the illusion of an updated geometry and the question did say (other then scaling). So, I would say a better approach would be to reassign the geometry property of your mesh to a new geometry.
mesh.geometry = new THREE.BoxGeometry(newSize, newSize, newSize)
With this approach you can update any aspect of the geometry including width segments for example. This is especially useful when working with non box geometries like cylinders or spheres.
Here is a full working example using this approach:
let size = 10
let newSize = 20
// Create a blank geometry and make a mesh from it.
let geometry = new THREE.BoxGeometry()
let material = new THREE.MeshNormalMaterial()
let mesh = new THREE.Mesh(geometry, material)
// Adding this mesh to the scene won't display anything because ...
// the geometry has no parameters yet.
scene.add(mesh)
// Unless you intend to reuse your old geometry dispose of it...
// this will significantly reduce memory footprint.
mesh.geometry.dispose()
// Update the mesh geometry to a new geometry with whatever parameters you desire.
// You will now see these changes reflected in the scene.
mesh.geometry = new THREE.BoxGeometry(size, size, size)
// You can update the geometry as many times as you like.
// This can be done before or after adding the mesh to the scene.
mesh.geometry = new THREE.BoxGeometry(newSize, newSize, newSize)

Related

Can I skip the normal syntax and work with geometry buffers in three.js for faster performance?

I'm new to the area of geometry generation and manipulation and I'm planning on doing this on an intricate and large scale. I know the basic way of doing this is like it's shown in the answer to this question..
var geom = new THREE.Geometry();
var v1 = new THREE.Vector3(0,0,0);
var v2 = new THREE.Vector3(0,500,0);
var v3 = new THREE.Vector3(0,500,500);
geom.vertices.push(v1);
geom.vertices.push(v2);
geom.vertices.push(v3);
geom.faces.push( new THREE.Face3( 0, 1, 2 ) );
geom.computeFaceNormals();
var object = new THREE.Mesh( geom, new THREE.MeshNormalMaterial() );
object.position.z = -100;//move a bit back - size of 500 is a bit big
object.rotation.y = -Math.PI * .5;//triangle is pointing in depth, rotate it -90 degrees on Y
scene.add(object);
But I do have experience with doing image manipulation working directly with a typed array image buffer on the GPU which is essentially the same thing as manipulating 3D points, since colors are essentially 3D points on a 2D grid (in the case of a buffer, flattened out to a 1D typed array) and I know just how much faster that kind of large scale manipulation is when processed with shaders on the GPU.
So I'm wondering if I can access the geometry in three.js directly as a typed array buffer. If so, I can use gpu.js to manipulate it on the GPU rather than CPU and boost performance exponentially.
Basically I'm asking if there's something like canvas's getImageData method for three.js geometry.
As ThJim01 mentioned in the comment, THREE.BufferGeometry is the way to go, but if you insist on using THREE.Geometry to initialize your list of triangles, you can use the BufferGeometry.fromGeometry function to generate the BufferGeometry from the Geometry you originally made.
var geometry = new THREE.Geometry();
// ... initialize verts and faces ...
// Initialize the BufferGeometry
var buffGeom = new THREE.BufferGeometry();
buffGeom.fromGeometry(geometry);
// Print the typed array for the position of the vertices
console.log(buffGeom.getAttribute('position').array);
Note that the resultant geometry will not have an index array and just be a list of disjointed triangles (as it was represented as in the first place!)
Hope that helps!

How do I change the basic parameters of a Geometry in Three.js (for example, radius, number of vertices, etc.)

I create a tetrahedron of radius 3
// create a tetrahedron
var tetGeometry = new THREE.TetrahedronGeometry(3);
var tetMaterial = new THREE.MeshLambertMaterial(
{color: 0x20f020, transparent:true, opacity:0.6});
tet = new THREE.Mesh(tetGeometry, tetMaterial);
tet.name='tet';
tet.castShadow = true;
Later, I want the tetrahedron to grow:
// change hedron
scene.getObjectByName('tet').radius = control.hedronRadius;
That doesn't work.
// change vertices
scene.getObjectByName('tet').detail = control.hedronVertices;
That doesn't work either.
scene.getObjectByName('tet').verticesNeedUpdate;
And this doesn't help.
So how do I change the radius of a tetrahedron (or any Geometry) and how do I change the vertices.
In the documentation I see references to:
Geometry
.dynamic
.morph
.verticesNeedUpdate
.scale
And also references to bones and skeletons and skinned meshes used to animate geometries.
How do I change these aspects of Geometries in general?
What's the most reasonable, suggested way then to grow the radius of a Tetrahedron, or change the number of vertices show it becomes a different number polyhedron?
To change geometry you need to use:
morphTargets: true
I've prepared an example using a tetrahedron as you mention in jsfiddle.
Use sliders to change geometry.
To make some custom vertices and "fill" them by faces, you need to understand a lot of things from math, like; point, vector, etc.
I've done 2 simple flat objects, triangle and square in jsfiddle.
I hope that you'll easy understand how it works in general.

how to make a transition from one mesh to another?

I have mesh1 and Mesh2. Each has extrusion.
mesh1 ->100 vertices
mesh2 ->200 vertices
In my code I do the following:
mesh1.geometry.verticesNeedUpdate = true;
mesh1 = Mesh2;
mesh1.geometry.computeBoundingBox ();
and so I manage to update mesh1 (this works in my original code), but I do not want you to see any abrupt change. I want an animation while mesh1 becomes the geometry Mesh2.
I've always used the library tween.js. So for example:
new TWEEN.Tween (mesh1.scale) .to ({x: 1, and 1, z 1}, 1000) .start ();
but I don't know how to do animation in this case.
With transition or animation, you see the changes in real time of the vertices of mesh2 to mesh1. I do not want to display any abrupt change.
You can use morphTarget for it. You have sets of vertices with same length, but with different positions. Then you set the morphTargetInfluences to effect the transition from that set of vertices to another set of vertices.
This is from Threejs Geometry documentation
.morphTargets
Array of morph targets. Each morph target is a Javascript object:
{ name: "targetName", vertices: [ new THREE.Vector3(), ... ] } Morph vertices match number and order of primary vertices.
This is a good example. View it's source code for better understanding.

three js getting coordinates of mesh.lookAt(object);

I have scene,meshes and target object.
When i set up
mesh.lookAt(object)
mesh correctly facing of object.
How can i repeat this rotation of mesh on another mesh, to force another mesh facing the same direction (not the same object, but the same orientation as a first mesh have)?
How can i get rotation coordinates of first mesh?
How can i get this coordinates without need of creating mesh and order mesh.lookAt(object). That mean only to calculate this coordinates without need to use it on some object?
UPDATE:
Only possible solution is to create new THREE.Object3D() and use object.lookAt(target). Then repeat rotation for all later loaded object like: new_object.rotation.set(object.rotation.x,object.rotation.y,object.rotation.z)
You will create only one Object, not a lot of unuseful Vector3-s.
Do not use new_object.rotation = object.rotation it is functional solution, but a variables stay connected. Change of object rotation, will update new_object.rotation too (renderer is updating all values each frame).
You can set the local rotation of the other meshes to the local rotation of the mech facing in the correct direction.
anyOtherMesh.rotation = mesh.rotation;
what about a
lookAt( new THREE.Vector3( target.position.x, target.position.y, target.position.z )
?

Three.js outlines

Is it possible to have an black outline on my 3d models with three.js?
I would have graphics which looks like Borderlands 2. (toon shading + black outlines)
I'm sure I came in late. Let's hope this would solve someone's question later.
Here's the deal, you don't need to render everything twice, the overhead actually is not substantial, all you need to do is duplicate the mesh and set the duplicate mesh's material side to "backside". No double passes. You will be rendering two meshes instead, with most of the outline's geometry culled by WebGL's "backface culling".
Here's an example:
var scene = new THREE.Scene();
//Create main object
var mesh_geo = new THREE.BoxGeometry(1, 1, 1);
var mesh_mat = new THREE.MeshBasicMaterial({color : 0xff0000});
var mesh = new THREE.Mesh(mesh_geo, mesh_mat);
scene.add(mesh);
//Create outline object
var outline_geo = new THREE.BoxGeometry(1, 1, 1);
//Notice the second parameter of the material
var outline_mat = new THREE.MeshBasicMaterial({color : 0x00ff00, side: THREE.BackSide});
var outline = new THREE.Mesh(outline_geo, outline_mat);
//Scale the object up to have an outline (as discussed in previous answer)
outline.scale.multiplyScalar(1.5);
scene.add(outline);
For more details on backface culling, check out: http://en.wikipedia.org/wiki/Back-face_culling
The above approach works well if you want to add an outline to objects, without adding a toon shader, and thus losing "realism".
Toon shading by itself supports edge detection. They've developed the 'cel' shader in Borderlands to achieve this effect.
In cel shading devs can either use the object duplication method (done at the [low] pipeline level), or can use image processing filters for edge detection. This is the point at which performance tradeoff is compared between the two techniques.
More info on cel: http://en.wikipedia.org/wiki/Cel_shading
Cheers!
Yes it is possible but not in a simple out-of-the-box way. For toon shading there are even shaders included in /examples/js/ShaderToon.js
For the outlines I think the most commonly suggested method is to render in two passes. First pass renders the models in black, and slightly larger scale. Second pass is normal scale and with the toon shaders. This way you'll see the larger black models as an outline. It's not perfect but I don't think there's an easy way out. You might have more success searching for "three.js hidden line rendering", as, while different look, somewhat similar method is used to achieve that.
Its a old question but here is what i did.
I created a Outlined Cel-shader for my CG course. Unfortunately it takes 3 rendering passes. Im currently trying to figure out how to remove one pass.
Here's the idea:
1) Render NormalDepth image to texture.
In vertex shader you do what you normally do, position to screen space and normal to screen space.
In fragment shader you calculate the depth of the pixel and then create the normal color with the depth as the alpha value
float ndcDepth = (2.0 * gl_FragCoord.z - gl_DepthRange.near - gl_DepthRange.far) / (gl_DepthRange.far - gl_DepthRange.near);
float clipDepth = ndcDepth / gl_FragCoord.w;
2) Render the scene on to a texture with cel-shading. I changed the scene override material.
3)Make quad and render both textures on the quad and have a orto camera look at it. Cel-shaded texture is just renderd on quad but the normaldepth shaded on that you use some edge detection and then with that you know when the pixel needs to be black(edge).

Categories

Resources