I am using THREE and I am trying to intersect a box mesh with a custom geometry I am creating and converting it to geometry using :
const g = new THREE.Geometry().fromBufferGeometry(shape3d)
I aim to add faces to the custom geometry, that is why I do that. So I expect to get back from the intersection my custom geometry + polygons that the box has.
I get that indeed, though I get also some holes as you can see in the below image :
I used many csg versions that are out there, the manthrax one, the ThreeCSG etc but no luck!
thank you
I suggest you set bevelEnabled:false to your mesh extrusion, because I am psychic and I can see your code in my head. :D
Related
Coded using:
Using ThreeJS v0.130.1
Framework: Angular 12, but that's not relevant to the issue.
Testing on Chrome browser.
I am building an application that gets more than 100K points. I use these points to render a THREE.Points object on the screen.
I found that default THREE.PointsMaterial does not support lighting (the points are visible with or without adding lights to the scene).
So I tried to implement a custom ShaderMaterial. But I could not find a way to add lighting to the rendered object.
Here is a sample of what my code is doing:
Sample App on StackBlitz showing my current attempt
In this code, I am using sample values for point cloud data, normals and color but everything else is similar to my actual application. I can see the 3D object, but need more proper lighting using normals.
I need help or guidance to implement the following:
Add lighting to custom shader material. I have Googled and tried many things, no success so far.
Using normals, show the effects of lighting (In this sample code, the normals are fixed to Y-axis direction, but I am calculating them based on some vector logic in actual application). So calculating normals is already done, but I want to use them to show light shine/shading effect in the custom shader material.
And in this sample, color attribute is set to fixed red color, but in actual application I am able to apply colors using UV range from a texture to color attribute.
Please advise how/if I can get lighting based on normals for Point Cloud. Thanks.
Note: I looked at this Stackoveflow question but it only deals with changing the alpha/transparency of points and not lighting.
Adding lighting to a custom material is a very complex process. Especially since you could use Phong, Lambert, or Physical lighting methods, and there's a lot of calculations that need to pass from the vertex to the fragment shader. For instance, this segment of shader code is just a small part of what you'd need.
Instead of trying to re-create lighting from scratch, I recommend you create a PlaneGeometry with the material you'd like (Phong, Lambert, Physical, etc...) and use an InstancedMesh to create thousands of instances, just like in this example.
Based on that example, the pseudo-code of how you could achieve a similar effect is something like this:
const count = 100000;
const geometry = new PlaneGeometry();
const material = new THREE.MeshPhongMaterial();
mesh = new THREE.InstancedMesh( geometry, material, count );
mesh.instanceMatrix.setUsage( THREE.DynamicDrawUsage ); // will be updated every frame
scene.add( mesh );
const dummy = new THREE.Object3D();
update() {
// Sets the rotation so it's always perpendicular to camera
dummy.lookAt(camera);
// Updates positions of each plane
for (let i = 0; i < count; i++){
dummy.position.set( x, y, z );
dummy.updateMatrix();
mesh.setMatrixAt( i ++, dummy.matrix );
}
}
The for() loop would be the most expensive part of each frame, so if you need to update it on each frame, you might want to calculate this in the vertex shader, but that's another question altogether.
I am creating a scene with several thousand cubes, each of which can be translated, scaled and rotated.
Initially, I tried creating a cube geometry, applying the transformations, creating a mesh with my material and adding it to the scene. That worked but was very slow because of all the draw calls.
So now, for all the cubes, I create a THREE.BoxGeometry(1,1,1), and merge it with a single THREE.Geometry() each time before finally creating a material and a single mesh and adding it to my scene.
The performance is drastically improved but I don't know how to apply a translation (XYZ), scale (XYZ) and rotation (quaternion) to each box before merging it. Can someone point me at the right syntax?
Secondly, if I merge my geometry like this, is there still a way to pick out a single box with a raycaster? Typically I've used the object name on the mesh but that's not relevant anymore.
Thank you.
I have a problem with mapping a texture in THREE.js which is possibly related to creating custom UV-Coordinates as extensive search indicates.
The following picture shows a geometry which was created from THREE.BoxGeometry by manipulating the lower vertices of the box. The texture on the side looks stretched (although this is correct I guess).
picture1
Is there a way of "projecting" the texture onto the side, e.g. by creating custom uv-coordinates to look like in the second (photoshopped) picture?
picture2
Thanks for you help!
You will need to remap your vertices manually to perform what is called a "box mapping" or a "triplanar mapping".
Here is an example I threw together: https://codesandbox.io/s/qxk8xvnrvj
It creates a cube with some subdivisions.. perturbs those vertices if they are on top... and then does the iterations through the faces uvs and vertices to remap each faces UVs with a box mapping, by finding the dominant axis the face normal points along... and then using the other 2 axis' as the U and V axis for unwrapping.
I'm trying to make a Plane to always face the camera or another moving object but I want the Plane to only rotate on 1 axis. How can I use the lookAt function to make it only rotate side ways without tilting to look up or down at the moving object?
thanks, I managed to solve it easily by just keeping the y position of the rotating object constant.
if(planex){
var yaw_control = controls.getYawObject();
pos = new THREE.Vector3( yaw_control.position.x, planex.position.y, yaw_control.position.z );
planex.lookAt(pos);
}
http://www.lighthouse3d.com/opengl/billboarding/index.php?billCyl
maybe this article of any help for you. You are looking for those cylindrical billboards i think but read up from the first page ;) You can modify the specific mesh matrix yourself, although i am not sure if this is the most efficient way. I also did this myself once.
Get the camera look vec:
three.js set and read camera look vector
Then get the camera upVec and afterwards get the cross prodcut of those = rightVec according to the article above.
using those vectors, you can fill in a new Three.Matrix4() like explained in the article and then replace the meshes matrix with the newly created one. As I said, i am not quite into the matrix stuff in three.js but this works but it is probably not that efficient.
For this to work you will have to deactive the meshes auto matrix update with
mesh.matrixAutoUpdate = false;
I've recently started playing with three.js. Noticed that even with a few thousand simple cubes, the performance starts to drop.
So this brings my main question: is there any way to instance using three.js? I'm pretty sure this drop in performance is related to the drawcalls, therefore if instancing is possible with three.js somehow, it can help support the performance.
I'm aware of buffers but at this point it's impossible for me to create a geometry buffer that will give me the power to modify individual objects during runtime. If there is a library to handle all this, this also counts as a solution.
Shortly, I'm looking for an equivalent of object instancing in three.js. Any suggestions are appreciated.
I've understood that instancing can be emulated / reimplemented with a shader. Am not sure and have not tried though.
This old demo has 150k individually animated cubes on the GPU btw, but the source is minified so was hard to see what's going on. Perhaps not a proper instancing solution that would work for any mesh, am not sure, might even be. http://alteredqualia.com/three/examples/webgl_cubes.html
Will keep an eye open for this as we'd need it too I think.. (have added trees to vizicities in a demo now)
I have only thought up a solution and have not tried it yet. I want to instance very complex meshes and have them animated using a skeleton. It seems the JSON loader only loads as Geometry G. I want to convert to BufferGeometry BG1, than make another BufferGeometry BG2. Then assign references of vertex attributes, etc from BG2 to BG1
//load mesh
...
var mesh = loadMesh();
//convert to buffer geometry
var BG1 = new BufferGeometry();
BG1.fromGeometry(mesh);
var BG2 = new BufferGeometry();
BG2.addAttribute('position', G1.attributes['position']);
BG2.addAttribute('normal', G1.attributes['normal']);
BG2.addAttribute('uv', G1.attributes['uv']);
BG2.addAttribute('color', G1.attributes['color']);
BG2.drawcalls = BG1.drawcalls;
BG2.boundingBox = BG1.boundingBox;
BG2.boundingSphere = BG1.boundingSphere;
Its my understanding that webgl will share these buffers and not duplicate the memory used in VRAM. Any comments are welcome.
I had the same experience when trying to draw a couple of thousands of Spheres.
After some research I achieved a better performance (up to a million of items) using the PointCloud Object. Basically you create the PointCloud object from a geometry (it can be created from raw in this example or use one of the existing in Three.js) and the PointCloudMaterial, where you can modify the properties of each item.
An example could be as follows (adding 10 points)
var geo = new THREE.Geometry();
var mat = new THREE.PointCloudMaterial({size: 1, color:0xff0000});
//assign different positions to the points
for (var i=0 ; i<10 ; i++){
var point = new THREE.Vector3(3*i,0,0);
geo.vertices.push(point);
}
system = new THREE.PointCloud(geo, mat);
scene.add(system);
To modify the appearance, you can play with the PointCloudMaterial properties, or load a texture so that each point gets a desired shape (cube-like in your case).
If you share more details (why do you need cubes, for example) or some code, maybe I can be more helpful
Most of the answers here are extremely outdated.
THREE.js now supports instancing via InstancedMesh
https://threejs.org/docs/?q=instancedmesh#api/en/objects/InstancedMesh
See example here:
https://threejs.org/examples/webgl_buffergeometry_instancing.html