How to change the normal of a PlaneGeometry in three.js? - javascript

I'm using Three.js to display planes, however I can't seem to find a way to change the normal of it. There's a Plane class that has a normal property so is there any way to use this instead of the PlaneGeometry one?

PlaneGeometry offers no means to change its normal, which is effectively always (0,0,1).
To make the plane geometry face in a different direction, you need to transform its vertices. This
is done by converting a Plane object to a transformation matrix and applying that
matrix to the PlaneGeometry. Here is code that generates a transformation matrix:
// Assumes that "plane" is the source THREE.Plane object.
// Normalize the plane
var normPlane=new THREE.Plane().copy(plane).normalize();
// Rotate from (0,0,1) to the plane's normal
var quaternion=new THREE.Quaternion()
.setFromUnitVectors(new THREE.Vector3(0,0,1),normPlane.normal);
// Calculate the translation
var position=new THREE.Vector3(
-normPlane.constant*normPlane.normal.x,
-normPlane.constant*normPlane.normal.y,
-normPlane.constant*normPlane.normal.z);
// Create the matrix
var matrix=new THREE.Matrix4()
.compose(position,quaternion,new THREE.Vector3(1,1,1));
// Transform the geometry (assumes that "geometry"
// is a THREE.PlaneGeometry or indeed any
// THREE.Geometry)
geometry.applyMatrix(matrix);

There is another option that perhaps can suit you. You can use lookAt method from the Mesh class. This method is inherited from Object3D class. You just need to specify the point where the plane will look. This way you can reuse your PlaneGeometry for other Mesh instances.
var geometry = new THREE.PlaneGeometry( 12, 12 );
var material = new THREE.MeshBasicMaterial( { color: 0x005E99 } );
var plane = new THREE.Mesh( geometry, material );
plane.lookAt(new THREE.Vector3(0.7, 0.7, 0.7));

Related

Three.js - how to create custom shapes

I´m using Three.js and trying to create some custom shapes, similar to one that appears in a project from one of agencies using threejs:
three.js featured project esample
How did they generated these boxes with holes inside? (on that examples
boxes basically have only borders around and are empty inside).
As I saw in the code (I was trying to figure out myself) they use BoxGeometry but I have no idea how to accomplish that. Does anyone know or can give me any directions? It would be really helpfull as i´m stuck with this and have no idea on how to create them.
So in THREE.js Meshes represent any kind of 3D object. They combine Geometries and Shaders. Generally to create a mesh you call
var mesh = new THREE.Mesh( geometry, shader );
If you use any of the builtin shaders (also known as Materials [ MeshBasicMaterial, MeshLambertMaterial, etc]) they have a wireFrame boolean attribute that allows this functionality.
var geometry = new THREE.BoxGeometry( x, y, z ),
material = new THREE.MeshBasicMaterial( {
wireFrame: true, // This makes the object appear wireframe
color: 0xffffff // You can alter other properties
});
var box = new THREE.Mesh( geometry, material );
// You can also change it later
box.material.wireFrame = false;

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

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)

CSG operations on bufferGeometry

I am currently using the three.js geometry class for creating a shape and then performing multiple CSG operations on that shape. Thus continuously redrawing the shape.
This process of performing multiple csg operations is slow, as I am using ray-casting to get the shape on click and perform CSG of the selected shape and a pre-defined shape (any shape or geometry).
So my questions are :
Will using buffer geometry speed up my CSG, but that said is there any library to perform CSG operations on THREE.BufferGeometry instances?
Is there a way I can speed up the process by using any other methods ?
This is my code-flow :
var objects = [];
init();
render();
function init(){
//scene and camera setup ... etc
var sphere = new THREE.SphereGeometry(200, 32, 32);
objects.push(sphere);
// raycasting config
// bind mouse click and move event
}
function onMouseDown() {
var intersects = raycaster.intersectObjects(objects);
.....
// get intersected shape ..
// perfrom csg with predifend shape .
// Also contains steps to convert
geometry to *CSG libaray geometry*
and back to Three.js geometry)..
// replace the shape with existing
.....
render();
}
I am using this library for CSG operations and overall flow is similar to this example in three.js examples.
I don't have element for performance comparison, but you can find a buffergeometry library in develop branch of ThreeCSG ThreeCSG develop from Wilt
It support buffergeometry (from examples):
var nonIndexedBoxMesh = new THREE.Mesh( nonIndexedBufferGeometry, material );
var bsp1 = new ThreeBSP( nonIndexedBoxMesh );
var indexedBoxMesh = new THREE.Mesh( indexedBufferGeometry, material );
var bsp2 = new ThreeBSP( indexedBoxMesh );
var geometry = bsp1.subtract( bsp2 ).toBufferGeometry();
var mesh = new THREE.Mesh( geometry, material );
It works with r75

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.

How to access the each element individually in Three.js

I have created mesh and rendered " 10 " 3d objects using three.js?
how to access each object to perform scaling , rotation & all stuffs so there is a
need to get the div object individually?
help me to solve this issue ?
thanks !
You do not seem to be asking a real question. But rather asking for someone to teach you something. In the 'startup code' a SphereGeometry object is combined with a MeshBasicMaterial object in order to create the Mesh object which is your 3d object that you can then use to access/set the objects position, rotation, etc. Here are the lines of code I am referring to:
var geometry = new THREE.SphereGeometry( 75, 20, 10 );
var material = new THREE.MeshBasicMaterial( { color: 0xffffff, wireframe: true } );
var mesh = new THREE.Mesh( geometry, material );
Once you create mesh objects you need to add them to the scene with a call to scene.add(mesh). At this point you can set or get the rotation or position as such
mesh.position.x = 50;
mesh.rotation.z = Math.PI / 2 // rotations are in radians

Categories

Resources