LeonYuanYao 5 years ago
parent
commit
e3ce14818c
2 changed files with 211 additions and 143 deletions
  1. 194 140
      examples/jsm/utils/GeometryPackingUtils.js
  2. 17 3
      examples/webgl_materials_packed_geometry.html

+ 194 - 140
examples/jsm/utils/GeometryPackingUtils.js

@@ -36,164 +36,94 @@ var GeometryPackingUtils = {
 
 
                 let encoded;
                 let encoded;
 
 
-                encoded = uInt16Encode(array[idx], array[idx + 1], array[idx + 2]);
+                encoded = GeometryEncodingUtils.uInt16Encode(array[idx], array[idx + 1], array[idx + 2]);
 
 
                 result[idx / 3 * 2 + 0] = encoded[0];
                 result[idx / 3 * 2 + 0] = encoded[0];
                 result[idx / 3 * 2 + 1] = encoded[1];
                 result[idx / 3 * 2 + 1] = encoded[1];
 
 
             }
             }
 
 
+            mesh.geometry.setAttribute('normal', new THREE.BufferAttribute(result, 2, true));
+
         } else if (encodeMethod == "OCT") {
         } else if (encodeMethod == "OCT") {
 
 
             result = new Int8Array(count * 2);
             result = new Int8Array(count * 2);
 
 
-            var oct, dec, best, currentCos, bestCos;
-
             for (let idx = 0; idx < array.length; idx += 3) {
             for (let idx = 0; idx < array.length; idx += 3) {
 
 
                 let encoded;
                 let encoded;
 
 
-                encoded = octEncodeBest(array[idx], array[idx + 1], array[idx + 2]);
+                encoded = GeometryEncodingUtils.octEncodeBest(array[idx], array[idx + 1], array[idx + 2]);
+
+                let x = encoded[0] / (encoded[0] < 0 ? 128 : 127)
+                let y = encoded[1] / (encoded[1] < 0 ? 128 : 127)
+
+                if ( Math.abs(array[idx + 2]) == 0 ){
+                    console.log([ array[idx], array[idx + 1], array[idx + 2] ], encoded, 
+                        x, 
+                        y,
+                        1-Math.abs(x)-Math.abs(y), 
+                        (1-Math.abs(x)-Math.abs(y))*127, 
+                    )
+                }
 
 
                 result[idx / 3 * 2 + 0] = encoded[0];
                 result[idx / 3 * 2 + 0] = encoded[0];
                 result[idx / 3 * 2 + 1] = encoded[1];
                 result[idx / 3 * 2 + 1] = encoded[1];
 
 
             }
             }
 
 
-        } else {
-
-            console.error("Unrecognized encoding method, should be `BASIC` or `OCT`. ");
-
-        }
+            mesh.geometry.setAttribute('normal', new THREE.BufferAttribute(result, 2, true));
 
 
+        } else if (encodeMethod == "DEFAULT") {
 
 
-        mesh.geometry.setAttribute('normal', new THREE.BufferAttribute(result, 2, true));
+            result = new Uint8Array(count * 3);
 
 
-        mesh.geometry.attributes.normal.needsUpdate = true;
-        mesh.geometry.attributes.normal.isPacked = true;
-        mesh.geometry.attributes.normal.packingMethod = encodeMethod;
-
-        // modify material
-        if (!(mesh.material instanceof PackedPhongMaterial)) {
-            mesh.material = new PackedPhongMaterial().copy(mesh.material);
-        }
-
-        if (encodeMethod == "BASIC") {
-            mesh.material.defines.USE_PACKED_NORMAL = 0;
-        }
-        if (encodeMethod == "OCT") {
-            mesh.material.defines.USE_PACKED_NORMAL = 1;
-        }
+            for (let idx = 0; idx < array.length; idx += 3) {
 
 
+                let encoded;
 
 
-        /**
-         * 
-         * Encoding functions: Basic, OCT
-         * 
-         */
+                encoded = GeometryEncodingUtils.defaultEncode(array[idx], array[idx + 1], array[idx + 2]);
 
 
-        // for `Basic` encoding
-        function uInt16Encode(x, y, z) {
-            let normal0 = parseInt(0.5 * (1.0 + Math.atan2(y, x) / Math.PI) * 65535);
-            let normal1 = parseInt(0.5 * (1.0 + z) * 65535);
-            return new Uint16Array([normal0, normal1]);
-        }
+                let decoded = GeometryEncodingUtils.defaultDecode(encoded);
 
 
-        // for `OCT` encoding
-        function octEncodeBest(x, y, z) {
-            // Test various combinations of ceil and floor
-            // to minimize rounding errors
-            best = oct = octEncodeVec3(x, y, z, "floor", "floor");
-            dec = octDecodeVec2(oct);
-            currentCos = bestCos = dot(x, y, z, dec);
-
-            oct = octEncodeVec3(x, y, z, "ceil", "floor");
-            dec = octDecodeVec2(oct);
-            currentCos = dot(x, y, z, dec);
-
-            if (currentCos > bestCos) {
-                best = oct;
-                bestCos = currentCos;
-            }
+                let angle = Math.acos(Math.min(array[idx] * decoded[0] + array[idx + 1]  * decoded[1] + array[idx + 2] * decoded[2], 1.0)) * 180 / Math.PI;
 
 
-            oct = octEncodeVec3(x, y, z, "floor", "ceil");
-            dec = octDecodeVec2(oct);
-            currentCos = dot(x, y, z, dec);
+                Math.abs(array[idx + 2]) < 0.05 && console.log([array[idx], array[idx + 1], array[idx + 2]], encoded, decoded, angle)
 
 
-            if (currentCos > bestCos) {
-                best = oct;
-                bestCos = currentCos;
-            }
 
 
-            oct = octEncodeVec3(x, y, z, "ceil", "ceil");
-            dec = octDecodeVec2(oct);
-            currentCos = dot(x, y, z, dec);
+                result[idx + 0] = encoded[0];
+                result[idx + 1] = encoded[1];
+                result[idx + 2] = encoded[2];
 
 
-            if (currentCos > bestCos) {
-                best = oct;
-                bestCos = currentCos;
             }
             }
 
 
-            var angle = Math.acos(bestCos) * 180 / Math.PI;
+            mesh.geometry.setAttribute('normal', new THREE.BufferAttribute(result, 3, true));
 
 
-            if (angle > 10){
-                console.log(angle)
-                oct = octEncodeVec3(x, y, z, "floor", "floor"); dec = octDecodeVec2(oct);
-                console.log([x, y, z], octDecodeVec2(octEncodeVec3(x, y, z, "floor", "floor")))
-                console.log([x, y, z], octDecodeVec2(octEncodeVec3(x, y, z, "ceil", "floor")))
-                console.log([x, y, z], octDecodeVec2(octEncodeVec3(x, y, z, "floor", "ceil")))
-                console.log([x, y, z], octDecodeVec2(octEncodeVec3(x, y, z, "ceil", "ceil")))
+        } else {
 
 
-            }
+            console.error("Unrecognized encoding method, should be `BASIC` or `OCT`. ");
 
 
-            return best;
         }
         }
 
 
-        function octEncodeVec3(x, y, z, xfunc, yfunc) {
-            var x = x / (Math.abs(x) + Math.abs(y) + Math.abs(z));
-            var y = y / (Math.abs(x) + Math.abs(y) + Math.abs(z));
-
-            if (z < 0) {
-                var tempx = x;
-                var tempy = y;
-                tempx = (1 - Math.abs(y)) * (x >= 0 ? 1 : -1);
-                tempy = (1 - Math.abs(x)) * (y >= 0 ? 1 : -1);
-                x = tempx;
-                y = tempy;
-            }
+        mesh.geometry.attributes.normal.needsUpdate = true;
+        mesh.geometry.attributes.normal.isPacked = true;
+        mesh.geometry.attributes.normal.packingMethod = encodeMethod;
 
 
-            return new Int8Array([
-                Math[xfunc](x * 127.5 + (x < 0 ? 1 : 0)),
-                Math[yfunc](y * 127.5 + (y < 0 ? 1 : 0))
-            ]);
+        // modify material
+        if (!(mesh.material instanceof PackedPhongMaterial)) {
+            mesh.material = new PackedPhongMaterial().copy(mesh.material);
         }
         }
 
 
-        function octDecodeVec2(oct) {
-            var x = oct[0];
-            var y = oct[1];
-            x /= x < 0 ? 127 : 128;
-            y /= y < 0 ? 127 : 128;
-
-            var z = 1 - Math.abs(x) - Math.abs(y);
-
-            if (z < 0) {
-                var tmpx = x;
-                x = (1 - Math.abs(y)) * (x >= 0 ? 1 : -1);
-                y = (1 - Math.abs(tmpx)) * (y >= 0 ? 1 : -1);
-            }
-
-            var length = Math.sqrt(x * x + y * y + z * z);
-
-            return [
-                x / length,
-                y / length,
-                z / length
-            ];
+        if (encodeMethod == "BASIC") {
+            mesh.material.defines.USE_PACKED_NORMAL = 0;
         }
         }
-
-        function dot(x, y, z, vec3) {
-            return x * vec3[0] + y * vec3[1] + z * vec3[2];
+        if (encodeMethod == "OCT") {
+            mesh.material.defines.USE_PACKED_NORMAL = 1;
+        }
+        if (encodeMethod == "DEFAULT") {
+            mesh.material.defines.USE_PACKED_NORMAL = 2;
         }
         }
+
     },
     },
 
 
 
 
@@ -279,42 +209,154 @@ var GeometryPackingUtils = {
         mesh.material.uniforms.quantizeMat.value = decodeMat4;
         mesh.material.uniforms.quantizeMat.value = decodeMat4;
         mesh.material.uniforms.quantizeMat.needsUpdate = true;
         mesh.material.uniforms.quantizeMat.needsUpdate = true;
 
 
+    }
+
+};
+
+
+/**
+ * 
+ * Encoding functions: Default, Basic, OCT
+ * 
+ */
+var GeometryEncodingUtils = {
+
+    defaultEncode: function (x, y, z) {
+        let tmpx = parseInt((x + 1) * 0.5 * 255);
+        let tmpy = parseInt((y + 1) * 0.5 * 255);
+        let tmpz = parseInt((z + 1) * 0.5 * 255);
+        return new Uint8Array([tmpx, tmpy, tmpz]);
     },
     },
 
 
+    defaultDecode: function (array) {
+        return [
+            ((array[0] / 255) * 2.0) - 1.0,
+            ((array[1] / 255) * 2.0) - 1.0,
+            ((array[2] / 255) * 2.0) - 1.0,
+        ]
+    },
 
 
-    changeShaderChunk: function () {
+    // for `Basic` encoding
+    uInt16Encode: function (x, y, z) {
+        let normal0 = parseInt(0.5 * (1.0 + Math.atan2(y, x) / Math.PI) * 65535);
+        let normal1 = parseInt(0.5 * (1.0 + z) * 65535);
+        return new Uint16Array([normal0, normal1]);
+    },
 
 
-        THREE.ShaderChunk.beginnormal_vertex = `
+    // for `OCT` encoding
+    octEncodeBest: function (x, y, z) {
+        var oct, dec, best, currentCos, bestCos;
 
 
-        vec3 objectNormal = vec3( normal );
-        #ifdef USE_TANGENT
-            vec3 objectTangent = vec3( tangent.xyz );
-        #endif
+        // Test various combinations of ceil and floor
+        // to minimize rounding errors
+        best = oct = octEncodeVec3(x, y, z, "floor", "floor");
+        dec = octDecodeVec2(oct);
+        currentCos = bestCos = dot(x, y, z, dec);
 
 
-        #ifdef USE_PACKED_NORMAL
-            #ifdef USE_PACKED_NORMAL == 0  // basicEncode
-                float x = objectNormal.x * 2.0 - 1.0;
-                float y = objectNormal.y * 2.0 - 1.0;
-                vec2 scth = vec2(sin(x * PI), cos(x * PI));
-                vec2 scphi = vec2(sqrt(1.0 - y * y), y); 
-                objectNormal = normalize( vec3(scth.y * scphi.x, scth.x * scphi.x, scphi.y) );
-            #endif
+        oct = octEncodeVec3(x, y, z, "ceil", "floor");
+        dec = octDecodeVec2(oct);
+        currentCos = dot(x, y, z, dec);
 
 
-            #ifdef USE_PACKED_NORMAL == 1  // octEncode
-                vec3 v = vec3(objectNormal.xy, 1.0 - abs(objectNormal.x) - abs(objectNormal.y));
-                if (v.z < 0.0) 
-                {
-                    v.xy = (1.0 - abs(v.yx)) * vec2((v.x >= 0.0) ? +1.0 : -1.0, (v.y >= 0.0) ? +1.0 : -1.0);
+        if (currentCos > bestCos) {
+            best = oct;
+            bestCos = currentCos;
+        }
+
+        oct = octEncodeVec3(x, y, z, "floor", "ceil");
+        dec = octDecodeVec2(oct);
+        currentCos = dot(x, y, z, dec);
+
+        if (currentCos > bestCos) {
+            best = oct;
+            bestCos = currentCos;
+        }
+
+        oct = octEncodeVec3(x, y, z, "ceil", "ceil");
+        dec = octDecodeVec2(oct);
+        currentCos = dot(x, y, z, dec);
+
+        if (currentCos > bestCos) {
+            best = oct;
+            bestCos = currentCos;
+        }
+
+        var angle = Math.acos(bestCos) * 180 / Math.PI;
+
+        // if (Math.abs(z) < 0.05) {
+        //     console.log(angle)
+        //     console.log([x, y, z], octDecodeVec2(octEncodeVec3(x, y, z, "floor", "floor")))
+        //     console.log([x, y, z], octDecodeVec2(octEncodeVec3(x, y, z, "ceil", "floor")))
+        //     console.log([x, y, z], octDecodeVec2(octEncodeVec3(x, y, z, "floor", "ceil")))
+        //     console.log([x, y, z], octDecodeVec2(octEncodeVec3(x, y, z, "ceil", "ceil")))
+        // }
+
+        return best;
+
+        function octEncodeVec3(x, y, z, xfunc, yfunc) {
+            var x = x / (Math.abs(x) + Math.abs(y) + Math.abs(z));
+            var y = y / (Math.abs(x) + Math.abs(y) + Math.abs(z));
+
+            if (z < 0) {
+                var tempx = x;
+                var tempy = y;
+                tempx = (1 - Math.abs(y)) * (x >= 0 ? 1 : -1);
+                tempy = (1 - Math.abs(x)) * (y >= 0 ? 1 : -1);
+                x = tempx;
+                y = tempy;
+
+                var diff = 1-Math.abs(x)-Math.abs(y);
+                if (diff > 0){
+                    diff += 0.001
+                    x += x > 0 ? diff / 2 : -diff / 2;
+                    y += y > 0 ? diff / 2 : -diff / 2;
                 }
                 }
-                objectNormal = normalize(v);
-            #endif
-        #endif
-        
-        `;
+
+                console.log("z < 0", `z:${z}`, 1-Math.abs(x)-Math.abs(y))
+            }
+
+            return new Int8Array([
+                Math[xfunc](x * 127.5 + (x < 0 ? 1 : 0)),
+                Math[yfunc](y * 127.5 + (y < 0 ? 1 : 0))
+            ]);
+
+            // return new Int8Array([
+            //     parseInt(x * 127.5 + (x < 0 ? 1 : 0)),
+            //     parseInt(y * 127.5 + (y < 0 ? 1 : 0))
+            // ]);
+        }
+
+        function octDecodeVec2(oct) {
+            var x = oct[0];
+            var y = oct[1];
+            x /= x < 0 ? 127 : 128;
+            y /= y < 0 ? 127 : 128;
+
+            var z = 1 - Math.abs(x) - Math.abs(y);
+
+            if (z < 0) {
+                var tmpx = x;
+                x = (1 - Math.abs(y)) * (x >= 0 ? 1 : -1);
+                y = (1 - Math.abs(tmpx)) * (y >= 0 ? 1 : -1);
+            }
+
+            var length = Math.sqrt(x * x + y * y + z * z);
+
+            return [
+                x / length,
+                y / length,
+                z / length
+            ];
+        }
+
+        function dot(x, y, z, vec3) {
+            return x * vec3[0] + y * vec3[1] + z * vec3[2];
+        }
     }
     }
 
 
 };
 };
 
 
+
+
 /**
 /**
  * PackedPhongMaterial inherited from THREE.MeshPhongMaterial
  * PackedPhongMaterial inherited from THREE.MeshPhongMaterial
  * 
  * 
@@ -376,13 +418,21 @@ var PackedPhongShader = {
 
 
             vec3 octDecode(vec3 packedNormal)
             vec3 octDecode(vec3 packedNormal)
             { 
             { 
+                // packedNormal = packedNormal / 127.0;
+
                 vec3 v = vec3(packedNormal.xy, 1.0 - abs(packedNormal.x) - abs(packedNormal.y));
                 vec3 v = vec3(packedNormal.xy, 1.0 - abs(packedNormal.x) - abs(packedNormal.y));
                 if (v.z < 0.0) 
                 if (v.z < 0.0) 
                 {
                 {
                     v.xy = (1.0 - abs(v.yx)) * vec2((v.x >= 0.0) ? +1.0 : -1.0, (v.y >= 0.0) ? +1.0 : -1.0);
                     v.xy = (1.0 - abs(v.yx)) * vec2((v.x >= 0.0) ? +1.0 : -1.0, (v.y >= 0.0) ? +1.0 : -1.0);
                 }
                 }
                 return normalize(v);
                 return normalize(v);
-            } 
+            }
+
+            vec3 defaultDecode(vec3 packedNormal)
+            {
+                vec3 v = (packedNormal * 2.0) - 1.0;
+                return normalize(v);
+            }
         #endif`,
         #endif`,
 
 
         `#ifdef USE_PACKED_POSITION
         `#ifdef USE_PACKED_POSITION
@@ -406,6 +456,10 @@ var PackedPhongShader = {
             #if USE_PACKED_NORMAL == 1
             #if USE_PACKED_NORMAL == 1
                 objectNormal = octDecode(objectNormal);
                 objectNormal = octDecode(objectNormal);
             #endif
             #endif
+
+            #if USE_PACKED_NORMAL == 2
+                objectNormal = defaultDecode(objectNormal);
+            #endif
         #endif
         #endif
 
 
         #ifdef USE_TANGENT
         #ifdef USE_TANGENT

+ 17 - 3
examples/webgl_materials_packed_geometry.html

@@ -31,8 +31,10 @@
 
 
 		var data = {
 		var data = {
 			flatShading: false,
 			flatShading: false,
+			wireframe: false, 
 			basicEncode: false,
 			basicEncode: false,
 			octEncode: false, 
 			octEncode: false, 
+			defaultEncode: false, 
 			quantizePosition: false
 			quantizePosition: false
 		};
 		};
 
 
@@ -72,16 +74,19 @@
 			lights[2] = new THREE.PointLight(0xffffff, 1, 0);
 			lights[2] = new THREE.PointLight(0xffffff, 1, 0);
 
 
 			lights[0].position.set(0, 2 * radius, 0);
 			lights[0].position.set(0, 2 * radius, 0);
-			lights[1].position.set(radius, 2 * radius, radius);
-			lights[2].position.set(- radius, - 2 * radius, - radius);
+			lights[1].position.set(2 * radius, - 2 * radius, 2 * radius);
+			lights[2].position.set(- 2 * radius, - 2 * radius, - 2 * radius);
 
 
 			scene.add(lights[0]);
 			scene.add(lights[0]);
 			scene.add(lights[1]);
 			scene.add(lights[1]);
 			scene.add(lights[2]);
 			scene.add(lights[2]);
 
 
 			//
 			//
+			scene.add(new THREE.AxesHelper(radius * 5));
 
 
-			var lineMaterial = new THREE.LineBasicMaterial({ color: 0xffffff, transparent: true, opacity: 0.5 });
+			//
+
+			var lineMaterial = new THREE.LineBasicMaterial({ color: 0x999999, transparent: true, opacity: 0.5 });
 			var meshMaterial = new THREE.MeshPhongMaterial({ color: 0x156289, emissive: 0x072534, flatShading: data.flatShading });
 			var meshMaterial = new THREE.MeshPhongMaterial({ color: 0x156289, emissive: 0x072534, flatShading: data.flatShading });
 
 
 			var texture = new THREE.TextureLoader().load("textures/disturb.jpg");
 			var texture = new THREE.TextureLoader().load("textures/disturb.jpg");
@@ -98,6 +103,7 @@
 
 
 			var ballMesh = new THREE.Mesh(ballGeom, meshMaterial);
 			var ballMesh = new THREE.Mesh(ballGeom, meshMaterial);
 			var ballLineSegments = new THREE.LineSegments(ballGeom, lineMaterial);
 			var ballLineSegments = new THREE.LineSegments(ballGeom, lineMaterial);
+			ballLineSegments.visible = data.wireframe;
 
 
 			scene.add(ballLineSegments);
 			scene.add(ballLineSegments);
 			scene.add(ballMesh);
 			scene.add(ballMesh);
@@ -116,11 +122,17 @@
 				ballMesh.material = new THREE.MeshPhongMaterial({ color: 0x156289, emissive: 0x072534, flatShading: data.flatShading });
 				ballMesh.material = new THREE.MeshPhongMaterial({ color: 0x156289, emissive: 0x072534, flatShading: data.flatShading });
 			}
 			}
 
 
+			function updateLineSegments(){
+				ballLineSegments.visible = data.wireframe;
+			}
+
 			var folder = gui.addFolder('THREE.IcosahedronBufferGeometry');
 			var folder = gui.addFolder('THREE.IcosahedronBufferGeometry');
 			folder.open();
 			folder.open();
 			folder.add(data, 'flatShading', false).onChange(updateMaterial);
 			folder.add(data, 'flatShading', false).onChange(updateMaterial);
+			folder.add(data, 'wireframe', false).onChange(updateLineSegments);
 			folder.add(data, 'basicEncode', false).onChange(generateGeometry);
 			folder.add(data, 'basicEncode', false).onChange(generateGeometry);
 			folder.add(data, 'octEncode', false).onChange(generateGeometry);
 			folder.add(data, 'octEncode', false).onChange(generateGeometry);
+			folder.add(data, 'defaultEncode', false).onChange(generateGeometry);
 			folder.add(data, 'quantizePosition', false).onChange(generateGeometry);
 			folder.add(data, 'quantizePosition', false).onChange(generateGeometry);
 
 
 			scene.add(ballMesh);
 			scene.add(ballMesh);
@@ -188,6 +200,8 @@
 				method = "BASIC";
 				method = "BASIC";
 			} else if (data.octEncode) {
 			} else if (data.octEncode) {
 				method = "OCT";
 				method = "OCT";
+			} else if (data.defaultEncode) {
+				method = "DEFAULT";
 			}
 			}
 
 
 			if (method != "") {
 			if (method != "") {