mrdoob / three.js

JavaScript 3D Library.
https://threejs.org/
MIT License
102.77k stars 35.38k forks source link

BufferGeometry: Replacement for MeshFaceMaterial #5268

Closed rawphl closed 10 years ago

rawphl commented 10 years ago

I already asked a related question on stackoverflow (http://stackoverflow.com/questions/25609031/buffergeometry-meshfacematerial-implementation-r68) and luckily mrdoob answered quickly, but I'm still stuck on this issue. I was not able to find any further information or examples on the web.

In another stackoverflow answer by mrdoob, I saw the statement that BufferGeometry does not support MeshFaceMaterial, but the reasons are unclear to me. We have a pretty large application that displays various models that heavily rely on MeshFaceMaterial for all the different kinds of maps. We are also trying to reduce memory usage and BufferGeometry would be a great start.

So my main questions are:

mrdoob commented 10 years ago

The way MeshFaceMaterial works when using WebGLRenderer is by internally creating a geometry per material. So, at the end of the day is like having a BufferGeometry per material.

Maybe the best way to deal with this would be by updating JSONLoader to generate BufferGeometry instead and "emulate" the MeshFaceMaterial at load time.

rawphl commented 10 years ago

So if I understand you correctly, BufferGeometry should still work with multiple materials if you create multiple geometries?

In the example on stackoverflow I created only one geometry but multiple meshes. The problem is I also tried copying the geometry for each mesh and I got the same results. I guess I will put together an example in the next few days that shows the problem.

rawphl commented 10 years ago

Ok so I was busy but now I found some time to dig into this, but before I start I still have a question: In order to make this work, I have to know which faces need which material. So far so good.

Now my first approach would be to create a separate geometry of all the faces for each material, meaning a BufferGeometry with index, position, normal and uv attributes, then create a mesh for each geometry and material pair and add it to an Object3D. As far as I understood, this should work and is basically the way Geometry with MeshFaceMaterial works now.

Now I have seen that BufferGeometry can also have offsets for drawing different faces, this makes sense and seems to be much easier than the approach mentioned above, but how would I assign materials to specific offset ranges?

WestLangley commented 10 years ago

As far as I understood, this should work and is basically the way Geometry with MeshFaceMaterial works now.

Correct.

how would I assign materials to specific offset ranges?

You can't. Try the first approach, and please post on stackoverlfow if you need additional help.

rawphl commented 10 years ago

Ok thanks. I understand that I should rather use stackoverflow for help, but please leave this issue open for now. I will do a PR with an example as soon as I'm done so other people who struggle with this will have a starting point.

mrdoob commented 10 years ago

Now I have seen that BufferGeometry can also have offsets for drawing different faces, this makes sense and seems to be much easier than the approach mentioned above, but how would I assign materials to specific offset ranges?

Haven't been able to implement/solve that yet.

rawphl commented 10 years ago

So the rendering of an indexed BufferGeometry with offsets happens here https://github.com/mrdoob/three.js/blob/master/src/renderers/WebGLRenderer.js#L2617 as far as I can tell.

All the necessary shader variables get set via setupVertexAttributes. That means what we would need is somekind of map from an offset range to a material index so we can pass the corresponding material to setupVertexAttributes.

This seems doable, but maybe you could elaborate on the problems you have faced.

At our company, we render models of appartments and we use all kinds of maps and materials. So naturally, with the old Geometry class, rendering performance is not really optimal if you have lots of objects and large geometries.

In the process of improving our rendering performance I have also studied the three.js blender exporter and I have planned to write a buffergeometry exporter. I saw that the JSON Format 4 is based on BufferGeometry but I have not seen an exporter implementation for it.

So my basic idea is to write a BufferGeometry exporter that also supports multiple materials and the whole geometry splitting( or offset-material mapping) would happen while exporting and not on the client. Writing the exporter seems like a pretty straight forward task, but I'm unsure how easy it will be to intergrate it into WebGLRenderer or If anyone else is already working on something similar.

If you can give me some insight on what you're planning with BufferGeometry I would love to invest my time into improving this. I will do this anyway cause we have to improve the performance of our app, but I see no point in keeping this to myself instead of making it a part of three.js.

WestLangley commented 10 years ago

If you want to do something that will work without altering WebGLRenderer, then you can do what you suggested: export a hierarchy of meshes, each with one material. Those meshes can use either indexed, or non-indexed BufferGeometry. I would expect non-indexed is sufficient.

mrdoob commented 10 years ago

So my basic idea is to write a BufferGeometry exporter that also supports multiple materials and the whole geometry splitting( or offset-material mapping) would happen while exporting and not on the client.

Yes yes yes! We definitely need a new Blender exporter that producers JSON Format 4 and slowly implement the missing features (skinning, ...). If you could start this would be amazing!

We can definitely help/discuss how to handle the material per offset part.

satori99 commented 10 years ago

I have already made a start on this. I have a working blender addon that exports indexed BufferGeometry and version 4.3 mesh objects. It can automatically split meshes by material. Though it doesn't use index offsets. It just makes seperate meshes)

At the moment it only supports static geometry (no skinning or animations), but I am hoping to get some time this weekend to figure that part out.

Python is new to me, so I probably have not written the most elegant code, but it is functional.

It also has the bonus of not modifying the blender scene at all. (The current official exporter re-uses mesh names for tmp meshes and causes the scene mesh data instances to be re-named on each export)

I will post it later today or tommorrow.

mrdoob commented 10 years ago

At the moment it only supports static geometry (no skinning or animations), but I am hoping to get some time this weekend to figure that part out.

That's not in the format "spec" yet. So I wouldn't worry about it by now.

Feel free to share what you have so far! ^^

rawphl commented 10 years ago

@satori99 sounds great!

Python is new to me, so I probably have not written the most elegant code, but it is functional.

I can help with a code clean up and documentation as soon as the functionality is there ;) I've spent the last few weeks learning the blender api and studying the WebGLRenderer and various blender exporter codes, all of which don't really have much documentation, so I think it's important to comment and document what we do, it will make it a lot easier for contributors in the future.

satori99 commented 10 years ago

I finally got some time for fun-coding (as opposed to boring coding that pays bills) and made my blender export script into an add-on.

https://github.com/satori99/threejs-blender-export

This is an example of a blender suzzane mesh with 6 materials exported as a Three.js object

Example of exported multimaterial mesh

You can view the example here (Orbit controls, use Shift to control light), and see the example JSON here

I use this script add-on to take advantage of multi-material meshes that use BufferGeometry with no need for MeshFaceMaterial.

rawphl commented 10 years ago

I read through #5417 and took a look at repsac's exporter. It seems to be very nice and already quite advanced, although it doesn't support exporting indexed geometries like satori99' exporter.

Anyway, both solutions provide a way to use multiple materials with a buffergeometry, so I'll close this issue and follow the development in #5417.