Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Any chance of Merge geometries? #6

Closed
VanderSP opened this issue Apr 1, 2020 · 21 comments
Closed

Any chance of Merge geometries? #6

VanderSP opened this issue Apr 1, 2020 · 21 comments

Comments

@VanderSP
Copy link

VanderSP commented Apr 1, 2020

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
Copy link
Author

VanderSP commented Apr 1, 2020

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
Copy link
Author

VanderSP commented Apr 1, 2020

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
Copy link
Author

VanderSP commented Apr 2, 2020 via email

@shawn0326
Copy link
Owner

@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
Copy link
Author

VanderSP commented Apr 2, 2020

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:

<title>Clouds</title> <style type="text/css">
		body {
			background-color: #326696;
			margin: 0px;
			overflow: hidden;
			font-family:Monospace;
			font-size:13px;
			text-align:center;
			font-weight: bold;
			text-align:center;
		}

		a {
			color:#0078ff;
		}

	</style>
</head>
<body>

	<script type="text/javascript">
	  var _gaq = _gaq || [];
	  _gaq.push(['_setAccount', 'UA-86951-7']);
	  _gaq.push(['_trackPageview']);

	  (function() {
	    var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
	    ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
	    (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(ga);
	  })();
	</script>

	<script type="text/javascript" src="js/three.min.js"></script>
	<script type="text/javascript" src="js/Detector.js"></script>

	<script id="vs" type="x-shader/x-vertex">

		varying vec2 vUv;

		void main() {

			vUv = uv;
			gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );

		}

	</script>

	<script id="fs" type="x-shader/x-fragment">

		uniform sampler2D map;

		uniform vec3 fogColor;
		uniform float fogNear;
		uniform float fogFar;

		varying vec2 vUv;

		void main() {

			float depth = gl_FragCoord.z / gl_FragCoord.w;
			float fogFactor = smoothstep( fogNear, fogFar, depth );

			gl_FragColor = texture2D( map, vUv );
			gl_FragColor.w *= pow( gl_FragCoord.z, 20.0 );
			gl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );

		}

	</script>

	<script type="text/javascript">

		if ( ! Detector.webgl ) Detector.addGetWebGLMessage();

		var container;
		var camera, scene, renderer;
		var mesh, geometry, material;

		var mouseX = 0, mouseY = 0;
		var start_time = Date.now();

		var windowHalfX = window.innerWidth / 2;
		var windowHalfY = window.innerHeight / 2;

		init();

		function init() {

			container = document.createElement( 'div' );
			document.body.appendChild( container );

			// Bg gradient

			var canvas = document.createElement( 'canvas' );
			canvas.width = 32;
			canvas.height = window.innerHeight;

			var context = canvas.getContext( '2d' );

			var gradient = context.createLinearGradient( 0, 0, 0, canvas.height );
			gradient.addColorStop(0, "#1e4877");
			gradient.addColorStop(0.5, "#4584b4");

			context.fillStyle = gradient;
			context.fillRect(0, 0, canvas.width, canvas.height);

			container.style.background = 'url(' + canvas.toDataURL('image/png') + ')';
			container.style.backgroundSize = '32px 100%';

			//

			camera = new THREE.PerspectiveCamera( 30, window.innerWidth / window.innerHeight, 1, 3000 );
			camera.position.z = 6000;

			scene = new THREE.Scene();

			geometry = new THREE.Geometry();

			var texture = THREE.ImageUtils.loadTexture( 'cloud10.png', null, animate );
			texture.magFilter = THREE.LinearMipMapLinearFilter;
			texture.minFilter = THREE.LinearMipMapLinearFilter;

			var fog = new THREE.Fog( 0x4584b4, - 100, 3000 );

			material = new THREE.ShaderMaterial( {

				uniforms: {

					"map": { type: "t", value: texture },
					"fogColor" : { type: "c", value: fog.color },
					"fogNear" : { type: "f", value: fog.near },
					"fogFar" : { type: "f", value: fog.far },

				},
				vertexShader: document.getElementById( 'vs' ).textContent,
				fragmentShader: document.getElementById( 'fs' ).textContent,
				depthWrite: false,
				depthTest: false,
				transparent: true

			} );

			var plane = new THREE.Mesh( new THREE.PlaneGeometry( 64, 64 ) );

			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;

				THREE.GeometryUtils.merge( geometry, plane );

			}

			mesh = new THREE.Mesh( geometry, material );
			scene.add( mesh );

			mesh = new THREE.Mesh( geometry, material );
			mesh.position.z = - 8000;
			scene.add( mesh );

			renderer = new THREE.WebGLRenderer( { antialias: false } );
			renderer.setSize( window.innerWidth, window.innerHeight );
			container.appendChild( renderer.domElement );

			document.addEventListener( 'mousemove', onDocumentMouseMove, false );
			window.addEventListener( 'resize', onWindowResize, false );

		}

		function onDocumentMouseMove( event ) {

			mouseX = ( event.clientX - windowHalfX ) * 0.25;
			mouseY = ( event.clientY - windowHalfY ) * 0.15;

		}

		function onWindowResize( event ) {

			camera.aspect = window.innerWidth / window.innerHeight;
			camera.updateProjectionMatrix();

			renderer.setSize( window.innerWidth, window.innerHeight );

		}

		function animate() {

			requestAnimationFrame( animate );

			position = ( ( Date.now() - start_time ) * 0.03 ) % 8000;

			camera.position.x += ( mouseX - camera.position.x ) * 0.01;
			camera.position.y += ( - mouseY - camera.position.y ) * 0.01;
			camera.position.z = - position + 8000;

			renderer.render( scene, camera );

		}

	</script>
</body>

@VanderSP
Copy link
Author

VanderSP commented Apr 2, 2020

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
Copy link
Author

VanderSP commented Apr 2, 2020

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
Copy link
Owner

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
Copy link
Author

VanderSP commented Apr 2, 2020

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
Copy link
Author

VanderSP commented Apr 2, 2020

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
Copy link
Author

VanderSP commented Apr 2, 2020

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
Copy link
Owner

Done!

mergeGeometries: function(geometries, useGroups) {

var geometry = zen3d.GeometryUtils.mergeGeometries(planeGeometries);

@VanderSP
Copy link
Author

VanderSP commented Apr 2, 2020

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
Copy link
Owner

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
Copy link
Author

VanderSP commented Apr 2, 2020

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
Copy link
Author

VanderSP commented Apr 2, 2020

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
Copy link
Owner

shawn0326 commented Apr 2, 2020

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
Copy link
Author

VanderSP commented Apr 2, 2020

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

@shawn0326
Copy link
Owner

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

@VanderSP
Copy link
Author

VanderSP commented Apr 3, 2020

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?

@VanderSP VanderSP closed this as completed Apr 4, 2020
@shawn0326
Copy link
Owner

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants