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
Related
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
I am making a 3d voxel game using threejs. I am coming across a problem where I have a geometry, as well as a material and I am trying to make an instanced mesh of about 1000 blocks (to increase game performance) and I want to give each of those blocks a different position. How do I do this? This is what I have so far so you can refer to it, thanks!
var geometry = new THREE.BoxBufferGeometry(1, 1, 1);
var blockMaterial = new THREE.MeshBasicMaterial({color : 0x00ff00});
Now that I have this, what should I continue to write if I want about 1000 blocks in an instancedMesh in certain positions that I want? Thanks again :)
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 am building quite a complex 3D environment in Three.js (FPS-a-like). For this purpose I wanted to structure the loading of textures and materials in an object oriƫnted way. For example; materials.wood.brownplank is a reusable material with a certain texture and other properties. Below is a simplified visualisation of the process where models uses materials and materials uses textures.
loadTextures();
loadMaterials();
loadModels();
//start doing stuff in the scene
I want to use that material on differently sized objects. However, in Three.js you can't (AFAIK) set a certain texture scale. You will have to set the repeat to scale it appropiate to your object. But I don't want to do that for every plane of every object I use.
Here is how it looks now
As you can see, the textures are not uniform in size.
Is there an easy way achieve this? So cloning the texture and/or material every time and setting the repeat according to the geometry won't do :)
I hope someone can help me.
Conclusion:
There is no real easy way to do this. I ended up changing my loading methods, where things like materials.wood.brownplank are now for example getMaterial('wood', 'brownplank') In the function new objects are instantiated
You should be able to do this by modifying your geometry UV coordinates according to the "real" dimensions of each face.
In Three.js, UV coordinates are relative to the face and texture (as in, 0.0 = one edge, 1.0 = other edge), no matter what the actual size of texture or face is. But by modifying the UVs in geometry (multiply them by some factor based on face physical size), you can use the same material and texture in different sizes (and orientations) per face.
You just need to figure out the mapping between UVs, geometry scale and your desired working units (eg. mm or m). Sorry I don't have, or know a ready algorithm to do it, but that's the approach you probably need to take. Should be quite doable with a bit of experimentation and google-fu.
I'm struggling with a visualization I'm working on that involves a stream of repeated images. I have it working with a single sprite with a ParticleSystem, but I can only apply a single material to the system. Since I want to choose between textures I tried creating a pool of Particle objects so that I could choose the materials individually, but I can't get an individual Particle to show up with the WebGL renderer.
This is my first foray into WebGL/Three.js, so I'm probably doing something bone-headed, but I thought it would be worth asking what the proper way to go about this is. I'm seeing three possibilities:
I'm using Particle wrong (initializing with a mapped material, adding to the scene, setting position) and I need to fix what I'm doing.
I need a ParticleSystem for each sprite I want to display.
What I'm doing doesn't fit into particles at all and I really should be using another object type.
All the examples I see using the canvas renderer use Particle directly, but I can't find an example using the WebGL renderer that doesn't use ParticleSystem. Any hints?
Ok, I am going from what I have read elsewhere on this github issues page. You should start by reading it. It seems that the Particle is simply for the Canvas Renderer, and it will become Sprite in a further edition of Three.JS. ParticleSystem, however is not going to fulfill your needs either it seems. I don't think these classes are going to help you accomplish this in WebGL in 3D. Depending on what you are doing you might be better off with the CanvasRenderer anyway. ParticleSystem will only allow you to apply a single material which will serve as the material for each particle in the system as you suggested.
Short answer:
You can render THREE.Particle using THREE.CanvasRenderer only.