shawn0326 / zen-3d

JavaScript 3D library.
MIT License
196 stars 24 forks source link

Any chance of Merge geometries? #6

Closed VanderSP closed 4 years ago

VanderSP commented 4 years ago

it´s very usefull for performance reasons... im trying to merge in threejs then gltfexporting to zen, but seems like geometries not generated... and i´ve already did this trick to use extrudebuffergeometry from three to zen, as another geometries that zen-3d don´t have yet... and it worked... but this time with merged, i dunno if it´s possible...

Sincerely, your project is very important to me... many thanks at moment!!!

VanderSP commented 4 years ago

For the moment i solved using BufferGeometryUtils, instead geometry.merge, it worked via gltfexporter!

edit: i thought that i solved but positions are not preserved with this method... any help would be very appreciated!

VanderSP commented 4 years ago

I tried to build zen-3d with a merge function implemented from threejs geometry...

i needed to initialize some arrays... and import matrix3

i needed to put getNormalMatrix on matrix3

no errors.. but no geometry

lol :D

VanderSP commented 4 years ago

Im just trying to merge plane buffers, like mr doob did in a old cloud experiment…

So a cloud made of bunch of clouds merged is much more performant…

Sent from Mailhttps://go.microsoft.com/fwlink/?LinkId=550986 for Windows 10

From: Shawn Xiemailto:notifications@github.com Sent: Wednesday, April 1, 2020 10:47 PM To: shawn0326/zen-3dmailto:zen-3d@noreply.github.com Cc: VanderSPmailto:Xtronoid@live.com; Authormailto:author@noreply.github.com Subject: Re: [shawn0326/zen-3d] Any chance of Merge geometries? (#6)

Can you send me some examples to reproduce the problem? I will implement a geometry merge method later, but I'm not sure if this will solve your problem. In addition, I checked the BufferGeometryUtils.mergeBufferGeometries method of three.js and it seems that if the atrributes of geometries do not match, the method will be skipped. Determine if the merged geometries will render properly in three.js?

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHubhttps://github.com/shawn0326/zen-3d/issues/6#issuecomment-607574319, or unsubscribehttps://github.com/notifications/unsubscribe-auth/ANQVCXMYPNKXOV5BVLKNXYLRKPVBDANCNFSM4LY5WUZA.

shawn0326 commented 4 years ago

@VanderSP Can you send me some examples to reproduce the problem? I will implement a geometry merge method later, but I'm not sure if this will solve your problem. In addition, I checked the BufferGeometryUtils.mergeBufferGeometries method of three.js and it seems that if the atrributes of geometries do not match, the method will be skipped. Check if the merged geometries will render properly in three.js?

VanderSP commented 4 years ago

https://mrdoob.com/lab/javascript/webgl/clouds/

in this fashion style of coding calling .merge to join geometries in a faster one

the source of this demo:

<!DOCTYPE HTML>

Clouds
VanderSP commented 4 years ago

the shader is simple i converted already to zen3d,

note that this example is OLD, so that utils is now on geometry.merge (and must call updateMatrix just before each merge)

VanderSP commented 4 years ago

when i said about exporting and reimporting... was a way to try to avoid you creating the merge.... but gltf didnt liked merged...

so i keep gltf just for simple geometry that we dont have on zen..so i can stuff from three to zen...

and later i talked about my failed attempt to stuff a .merge on your geometry.js lol

shawn0326 commented 4 years ago

I modified the example to use THREE.BufferGeometry & THREE.BufferGeometryUtils.mergeBufferGeometries, and it works.

            // ...

            var plane = new THREE.Mesh( new THREE.PlaneBufferGeometry( 64, 64 ) );
            var planeGeometries = [];

            for ( var i = 0; i < 8000; i++ ) {

                plane.position.x = Math.random() * 1000 - 500;
                plane.position.y = - Math.random() * Math.random() * 200 - 15;
                plane.position.z = i;
                plane.rotation.z = Math.random() * Math.PI;
                plane.scale.x = plane.scale.y = Math.random() * Math.random() * 1.5 + 0.5;
                plane.updateMatrix();

                // clone geometry, because mergeBufferGeometries receives a Geoemtry array
                // clone cost more cache --!
                planeGeometries.push( plane.geometry.clone().applyMatrix4( plane.matrix ) ); 

            }

            // merge
            geometry = THREE.BufferGeometryUtils.mergeBufferGeometries( planeGeometries );

            // ...

And I will implement the mergeBufferGeometries method in zen3d later and try this example.

VanderSP commented 4 years ago

when i tried mergebuffergeometries (then exported it to zen3d via gltfexporter) it dont keep the positions of geometries... just stacked the clouds...

when i used geometry.merge and exported to zen3d it got no geometry at all

but wait, you are on THREE, im on zen3d, how do you merge in zen?

VanderSP commented 4 years ago

i use this to convert between

import { GLTFLoader } from 'zen-3d/examples/jsm/loaders/GLTFLoader'
import { GLTFExporter } from 'three/examples/jsm/exporters/GLTFExporter'

SDResourceManager.exporter = new GLTFExporter()
SDResourceManager.importer = new GLTFLoader()

static async three2Zen(mesh, material = null) {
        let exported = await new Promise(resolve => {
            SDResourceManager.exporter.parse(mesh, resolve, null)
        }).then(exported => {
            return exported
        })

        let imported = await new Promise(resolve => {
            SDResourceManager.importer.parse(JSON.stringify(exported, null, 2), '.', resolve, null)
        }).then(imported => {
            return imported
        })

        let importedMesh = imported.scene.children[0]

        if (material) {
            importedMesh.material = material
        }
        return importedMesh
    }
VanderSP commented 4 years ago

Yeah your trick to recover position worked, i did with three things and exported gltf to zen, now position mantains!! at least is a solution! thanks Shawn!

shawn0326 commented 4 years ago

Done!

https://github.com/shawn0326/zen-3d/blob/388c9b5e29f133f32bae0dc43f88fc851ac82338/examples/js/GeometryUtils.js#L152

https://github.com/shawn0326/zen-3d/blob/388c9b5e29f133f32bae0dc43f88fc851ac82338/examples/lab_clouds.html#L170

VanderSP commented 4 years ago

I will test it now... but just for curiosity, i tried the lab_clouds example via raw.githack... why it´s totally slow? do you think that the merging not really happened in performance level?

shawn0326 commented 4 years ago

I will test it now... but just for curiosity, i tried the lab_clouds example via raw.githack... why it´s totally slow? do you think that the merging not really happened in performance level?

Testing performance on my computer is normal. Also, weirdly, testing on mobile devices https://mrdoob.com/lab/javascript/webgl/clouds/ This page has very low performance, but my example is normal ... I can be sure that there are only two geometry in the scene. However, here are some reasons that can cause performance differences on different devices:

  1. new zen3d.Renderer (canvas, {antialias: true, alpha: true, stencil: true}) The settings of the antialias and stencil properties.
  2. texture.anisotropy = 16; enable texture anisotropy
VanderSP commented 4 years ago

i tried on laptop i7 chrome browser windows 10 gt630m using your html on raw githack

misteriously veeery slow

https://rawcdn.githack.com/shawn0326/zen-3d/388c9b5e29f133f32bae0dc43f88fc851ac82338/examples/lab_clouds.html

VanderSP commented 4 years ago

This code is for not stacking same positions.... it should be done in a .merge of the class in the future?

var vector3 = new zen3d.Vector3();

            function transformPositionAttribute(attribute, matrix) {
                var array = attribute.array;
                var count = attribute.count;
                for (var i = 0; i < count; i++) {
                    vector3.fromArray(array, i * 3);
                    vector3.applyMatrix4(matrix);
                    vector3.toArray(array, i * 3);
                }
            }

            function transformNormalAttribute(attribute, matrix) {
                var array = attribute.array;
                var count = attribute.count;
                for (var i = 0; i < count; i++) {
                    vector3.fromArray(array, i * 3);
                    vector3.applyMatrix4(matrix);
                    vector3.toArray(array, i * 3);
                }
            }
shawn0326 commented 4 years ago

This code is for not stacking same positions.... it should be done in a .merge of the class in the future?

Yes, I will refactor this method later, maybe I should implement the geometry.applyMatrix4 method

BTW. i just found a bug, normal vector should apply normalMatrix in transformNormalAttribute method

VanderSP commented 4 years ago

Nice! the material must be both on the plane as in the final mesh?

shawn0326 commented 4 years ago

In this case, plane's material is not necessary.

VanderSP commented 4 years ago

Oh yeah i forgot about zen defaulting antialias to true.... and there´s no such advantage on this billboard transparent case... after setting it to false, i earn a lot of fps... even in my gt630m, when clouds got near the camera it dropped to 6... after antialias false ~30fps...

so that bottleneck was this (lol, not even metering the merge difference so... i will make more tests)

about stencil true or false, i dont really understand how can affect in this case... but i guess that im fine with the default that´s false, right?

shawn0326 commented 4 years ago

about stencil true or false, i dont really understand how can affect in this case... but i guess that im fine with the default that´s false, right?

I'm not sure, just in case, in general there is no difference.