Browse Source

fix dot product

Gregg Tavares 6 years ago
parent
commit
4818245e14

+ 71 - 24
threejs/lessons/threejs-align-html-elements-to-3d.md

@@ -509,8 +509,9 @@ the math relatively easy.
 
 
 ```js
 ```js
 const tempV = new THREE.Vector3();
 const tempV = new THREE.Vector3();
++const cameraToPoint = new THREE.Vector3();
++const cameraPosition = new THREE.Vector3();
 +const normalMatrix = new THREE.Matrix3();
 +const normalMatrix = new THREE.Matrix3();
-+const positiveZ = new THREE.Vector3(0, 0, 1);
 
 
 function updateLabels() {
 function updateLabels() {
   // exit if we have not yet loaded the JSON file
   // exit if we have not yet loaded the JSON file
@@ -518,22 +519,33 @@ function updateLabels() {
     return;
     return;
   }
   }
 
 
-+  const visibleDot = Math.cos(THREE.Math.degToRad(75));
++  const minVisibleDot = 0.2;
 +  // get a matrix that represents a relative orientation of the camera
 +  // get a matrix that represents a relative orientation of the camera
 +  normalMatrix.getNormalMatrix(camera.matrixWorldInverse);
 +  normalMatrix.getNormalMatrix(camera.matrixWorldInverse);
++  // get the camera's position
++  camera.getWorldPosition(cameraPosition);
   for (const countryInfo of countryInfos) {
   for (const countryInfo of countryInfos) {
     const {position, elem} = countryInfo;
     const {position, elem} = countryInfo;
 
 
-+    // orient the position based on the camera's orientation
++    // Orient the position based on the camera's orientation.
++    // Since the sphere is at the origin and the sphere is a unit sphere
++    // this gives us a camera relative direction vector for the position.
 +    tempV.copy(position);
 +    tempV.copy(position);
 +    tempV.applyMatrix3(normalMatrix);
 +    tempV.applyMatrix3(normalMatrix);
 +
 +
-+    // get the dot product with positiveZ
-+    // -1 = facing directly away and +1 = facing directly toward us
-+    const dot = tempV.dot(positiveZ);
++    // compute the direction to this position from the camera
++    cameraToPoint.copy(position);
++    cameraToPoint.applyMatrix4(camera.matrixWorldInverse).normalize();
++
++    // get the dot product of camera relative direction to this position
++    // on the globe with the direction from the camera to that point.
++    // 1 = facing directly towards the camera
++    // 0 = exactly on tangent of the sphere from the camera
++    // < 0 = facing away
++    const dot = tempV.dot(cameraToPoint);
 +
 +
 +    // if the orientation is not facing us hide it.
 +    // if the orientation is not facing us hide it.
-+    if (dot < visibleDot) {
++    if (dot < minVisibleDot) {
 +      elem.style.display = 'none';
 +      elem.style.display = 'none';
 +      continue;
 +      continue;
 +    }
 +    }
@@ -557,11 +569,27 @@ function updateLabels() {
 }
 }
 ```
 ```
 
 
-Above we use the positions as a direction, get their direction relative 
-to the camera and take the *dot product* with a positive Z vector. This
-gives us a value from -1 to 1 where -1 means the label is directly on the
-other side of the sphere and +1 means the label is directly on our side
-of the sphere. We then use that value to show or hide the element.
+Above we use the positions as a direction and get that direction relative to the
+camera. Then we get the camera relative direction from the camera to that
+position on the globe and take the *dot product*. The dot product returns the cosine
+of the angle between the to vectors. This gives us a value from -1
+to +1 where -1 means the label is facing the camera, 0 means the label is directly
+on the edge of the sphere relative to the camera, and anything greater than zero is
+behind. We then use that value to show or hide the element.
+
+<div class="spread">
+  <div>
+    <div data-diagram="dotProduct" style="height: 400px"></div>
+  </div>
+</div>
+
+In the diagram above we can see the dot product of the direction the label is
+facing to direction from the camera to that position. If you rotate the
+direction you'll see the dot product is -1.0 when the direction is directly
+facing the camera, it's 0.0 when exactly on the tangent of the sphere relative
+to the camera or to put it another way it's 0 when the 2 vectors are
+perpendicular to each other, 90 degrees It's greater than zero with the label is
+behind the sphere.
 
 
 For issue #2, too many labels we need some way to decide which labels
 For issue #2, too many labels we need some way to decide which labels
 to show. One way would be to only show labels for large countries.
 to show. One way would be to only show labels for large countries.
@@ -605,9 +633,11 @@ or not
 
 
 ```js
 ```js
 +const large = 20 * 20;
 +const large = 20 * 20;
-const visibleDot = Math.cos(THREE.Math.degToRad(75));
+const maxVisibleDot = 0.2;
 // get a matrix that represents a relative orientation of the camera
 // get a matrix that represents a relative orientation of the camera
 normalMatrix.getNormalMatrix(camera.matrixWorldInverse);
 normalMatrix.getNormalMatrix(camera.matrixWorldInverse);
+// get the camera's position
+camera.getWorldPosition(cameraPosition);
 for (const countryInfo of countryInfos) {
 for (const countryInfo of countryInfos) {
 -  const {position, elem} = countryInfo;
 -  const {position, elem} = countryInfo;
 +  const {position, elem, area} = countryInfo;
 +  const {position, elem, area} = countryInfo;
@@ -633,11 +663,11 @@ add a GUI so we can play with them
 ```js
 ```js
 +const settings = {
 +const settings = {
 +  minArea: 20,
 +  minArea: 20,
-+  visibleAngleDeg: 75,
++  maxVisibleDot: -0.2,
 +};
 +};
 +const gui = new dat.GUI({width: 300});
 +const gui = new dat.GUI({width: 300});
 +gui.add(settings, 'minArea', 0, 50).onChange(requestRenderIfNotRequested);
 +gui.add(settings, 'minArea', 0, 50).onChange(requestRenderIfNotRequested);
-+gui.add(settings, 'visibleAngleDeg', 0, 180).onChange(requestRenderIfNotRequested);
++gui.add(settings, 'maxVisibleDot', -1, 1, 0.01).onChange(requestRenderIfNotRequested);
 
 
 function updateLabels() {
 function updateLabels() {
   if (!countryInfos) {
   if (!countryInfos) {
@@ -645,14 +675,22 @@ function updateLabels() {
   }
   }
 
 
 -  const large = 20 * 20;
 -  const large = 20 * 20;
--  const visibleDot = Math.cos(THREE.Math.degToRad(75));
+-  const maxVisibleDot = -0.2;
 +  const large = settings.minArea * settings.minArea;
 +  const large = settings.minArea * settings.minArea;
-+  const visibleDot = Math.cos(THREE.Math.degToRad(settings.visibleAngleDeg));
   // get a matrix that represents a relative orientation of the camera
   // get a matrix that represents a relative orientation of the camera
   normalMatrix.getNormalMatrix(camera.matrixWorldInverse);
   normalMatrix.getNormalMatrix(camera.matrixWorldInverse);
+  // get the camera's position
+  camera.getWorldPosition(cameraPosition);
   for (const countryInfo of countryInfos) {
   for (const countryInfo of countryInfos) {
 
 
     ...
     ...
+
+    // if the orientation is not facing us hide it.
+-    if (dot > maxVisibleDot) {
++    if (dot > settings.maxVisibleDot) {
+      elem.style.display = 'none';
+      continue;
+    }
 ```
 ```
 
 
 and here's the result
 and here's the result
@@ -660,18 +698,27 @@ and here's the result
 {{{example url="../threejs-align-html-elements-to-3d-globe.html" }}}
 {{{example url="../threejs-align-html-elements-to-3d-globe.html" }}}
 
 
 You can see as you rotate the earth labels that go behind disappear.
 You can see as you rotate the earth labels that go behind disappear.
-Adjust the `visibleAngleDeg` to see the cutoff change.
-
-You can also adjust  the `minArea` value to see larger or smaller countries
+Adjust the `minVisibleDot` to see the cutoff change.
+You can also adjust the `minArea` value to see larger or smaller countries
 appear.
 appear.
 
 
-I'll be honest, the more I worked on this the more I realized just how much
+The more I worked on this the more I realized just how much
 work is put into Google Maps. They have also have to decide which labels to
 work is put into Google Maps. They have also have to decide which labels to
 show. I'm pretty sure they use all kinds of criteria. For example your current
 show. I'm pretty sure they use all kinds of criteria. For example your current
 location, your default language setting, your account settings if you have an
 location, your default language setting, your account settings if you have an
-account.
+account, they probably use population or popularity, they might give priority
+to the countries in the center of the view, etc ... Lots to think about.
 
 
 In any case I hope these examples gave you some idea of how to align HTML
 In any case I hope these examples gave you some idea of how to align HTML
-elements with your 3D.
+elements with your 3D. A few things I might change.
+
+Next up let's make it so you can [pick and highlight a country](threejs-indexed-textures.html).
 
 
-Next up let's make it so you can [pick and highlight a country](threejs-indexed-textures.html).
+<style>
+div[data-diagram] canvas {
+  width: 100%;
+  height: 100%;
+  display: block;
+}
+</style>
+<script src="resources/threejs-align-html-elements-to-3d.js"></script>

+ 2 - 1
threejs/lessons/threejs-indexed-textures.md

@@ -222,9 +222,10 @@ function updateLabels() {
   }
   }
 
 
   const large = settings.minArea * settings.minArea;
   const large = settings.minArea * settings.minArea;
-  const visibleDot = Math.cos(THREE.Math.degToRad(settings.visibleAngleDeg));
   // get a matrix that represents a relative orientation of the camera
   // get a matrix that represents a relative orientation of the camera
   normalMatrix.getNormalMatrix(camera.matrixWorldInverse);
   normalMatrix.getNormalMatrix(camera.matrixWorldInverse);
+  // get the camera's position
+  camera.getWorldPosition(cameraPosition);
   for (const countryInfo of countryInfos) {
   for (const countryInfo of countryInfos) {
 -    const {position, elem, area} = countryInfo;
 -    const {position, elem, area} = countryInfo;
 -    // large enough?
 -    // large enough?

+ 20 - 9
threejs/threejs-align-html-elements-to-3d-globe.html

@@ -149,16 +149,17 @@ function main() {
   loadCountryData();
   loadCountryData();
 
 
   const tempV = new THREE.Vector3();
   const tempV = new THREE.Vector3();
+  const cameraToPoint = new THREE.Vector3();
+  const cameraPosition = new THREE.Vector3();
   const normalMatrix = new THREE.Matrix3();
   const normalMatrix = new THREE.Matrix3();
-  const positiveZ = new THREE.Vector3(0, 0, 1);
 
 
   const settings = {
   const settings = {
     minArea: 20,
     minArea: 20,
-    visibleAngleDeg: 75,
+    maxVisibleDot: -0.2,
   };
   };
   const gui = new dat.GUI({width: 300});
   const gui = new dat.GUI({width: 300});
   gui.add(settings, 'minArea', 0, 50).onChange(requestRenderIfNotRequested);
   gui.add(settings, 'minArea', 0, 50).onChange(requestRenderIfNotRequested);
-  gui.add(settings, 'visibleAngleDeg', 0, 180).onChange(requestRenderIfNotRequested);
+  gui.add(settings, 'maxVisibleDot', -1, 1, 0.01).onChange(requestRenderIfNotRequested);
 
 
   function updateLabels() {
   function updateLabels() {
     if (!countryInfos) {
     if (!countryInfos) {
@@ -166,9 +167,10 @@ function main() {
     }
     }
 
 
     const large = settings.minArea * settings.minArea;
     const large = settings.minArea * settings.minArea;
-    const visibleDot = Math.cos(THREE.Math.degToRad(settings.visibleAngleDeg));
     // get a matrix that represents a relative orientation of the camera
     // get a matrix that represents a relative orientation of the camera
     normalMatrix.getNormalMatrix(camera.matrixWorldInverse);
     normalMatrix.getNormalMatrix(camera.matrixWorldInverse);
+    // get the camera's position
+    camera.getWorldPosition(cameraPosition);
     for (const countryInfo of countryInfos) {
     for (const countryInfo of countryInfos) {
       const {position, elem, area} = countryInfo;
       const {position, elem, area} = countryInfo;
       // large enough?
       // large enough?
@@ -177,16 +179,25 @@ function main() {
         continue;
         continue;
       }
       }
 
 
-      // orient the position based on the camera's orientation
+      // Orient the position based on the camera's orientation.
+      // Since the sphere is at the origin and the sphere is a unit sphere
+      // this gives us a camera relative direction vector for the position.
       tempV.copy(position);
       tempV.copy(position);
       tempV.applyMatrix3(normalMatrix);
       tempV.applyMatrix3(normalMatrix);
 
 
-      // get the dot product with positiveZ
-      // -1 = facing directly away and +1 = facing directly toward us
-      const dot = tempV.dot(positiveZ);
+      // compute the direction to this position from the camera
+      cameraToPoint.copy(position);
+      cameraToPoint.applyMatrix4(camera.matrixWorldInverse).normalize();
+
+      // get the dot product of camera relative direction to this position
+      // on the globe with the direction from the camera to that point.
+      // -1 = facing directly towards the camera
+      // 0 = exactly on tangent of the sphere from the camera
+      // > 0 = facing away
+      const dot = tempV.dot(cameraToPoint);
 
 
       // if the orientation is not facing us hide it.
       // if the orientation is not facing us hide it.
-      if (dot < visibleDot) {
+      if (dot > settings.maxVisibleDot) {
         elem.style.display = 'none';
         elem.style.display = 'none';
         continue;
         continue;
       }
       }

+ 20 - 13
threejs/threejs-indexed-textures-picking-and-highlighting.html

@@ -59,11 +59,10 @@
 <script src="resources/threejs/r102/three.js"></script>
 <script src="resources/threejs/r102/three.js"></script>
 <script src="resources/threejs/r102/js/utils/BufferGeometryUtils.js"></script>
 <script src="resources/threejs/r102/js/utils/BufferGeometryUtils.js"></script>
 <script src="resources/threejs/r102/js/controls/OrbitControls.js"></script>
 <script src="resources/threejs/r102/js/controls/OrbitControls.js"></script>
-<script src="../3rdparty/dat.gui.min.js"></script>
 <script>
 <script>
 'use strict';
 'use strict';
 
 
-/* global THREE, dat */
+/* global THREE */
 
 
 function main() {
 function main() {
   const canvas = document.querySelector('#c');
   const canvas = document.querySelector('#c');
@@ -230,16 +229,14 @@ function main() {
   loadCountryData();
   loadCountryData();
 
 
   const tempV = new THREE.Vector3();
   const tempV = new THREE.Vector3();
+  const cameraToPoint = new THREE.Vector3();
+  const cameraPosition = new THREE.Vector3();
   const normalMatrix = new THREE.Matrix3();
   const normalMatrix = new THREE.Matrix3();
-  const positiveZ = new THREE.Vector3(0, 0, 1);
 
 
   const settings = {
   const settings = {
     minArea: 20,
     minArea: 20,
-    visibleAngleDeg: 75,
+    maxVisibleDot: -0.2,
   };
   };
-  const gui = new dat.GUI({width: 300});
-  gui.add(settings, 'minArea', 0, 50).onChange(requestRenderIfNotRequested);
-  gui.add(settings, 'visibleAngleDeg', 0, 180).onChange(requestRenderIfNotRequested);
 
 
   function updateLabels() {
   function updateLabels() {
     // exit if we have not loaded the data yet
     // exit if we have not loaded the data yet
@@ -248,9 +245,10 @@ function main() {
     }
     }
 
 
     const large = settings.minArea * settings.minArea;
     const large = settings.minArea * settings.minArea;
-    const visibleDot = Math.cos(THREE.Math.degToRad(settings.visibleAngleDeg));
     // get a matrix that represents a relative orientation of the camera
     // get a matrix that represents a relative orientation of the camera
     normalMatrix.getNormalMatrix(camera.matrixWorldInverse);
     normalMatrix.getNormalMatrix(camera.matrixWorldInverse);
+    // get the camera's position
+    camera.getWorldPosition(cameraPosition);
     for (const countryInfo of countryInfos) {
     for (const countryInfo of countryInfos) {
       const {position, elem, area, selected} = countryInfo;
       const {position, elem, area, selected} = countryInfo;
       const largeEnough = area >= large;
       const largeEnough = area >= large;
@@ -260,16 +258,25 @@ function main() {
         continue;
         continue;
       }
       }
 
 
-      // orient the position based on the camera's orientation
+      // Orient the position based on the camera's orientation.
+      // Since the sphere is at the origin and the sphere is a unit sphere
+      // this gives us a camera relative direction vector for the position.
       tempV.copy(position);
       tempV.copy(position);
       tempV.applyMatrix3(normalMatrix);
       tempV.applyMatrix3(normalMatrix);
 
 
-      // get the dot product with positiveZ
-      // -1 = facing directly away and +1 = facing directly toward us
-      const dot = tempV.dot(positiveZ);
+      // compute the direction to this position from the camera
+      cameraToPoint.copy(position);
+      cameraToPoint.applyMatrix4(camera.matrixWorldInverse).normalize();
+
+      // get the dot product of camera relative direction to this position
+      // on the globe with the direction from the camera to that point.
+      // -1 = facing directly towards the camera
+      // 0 = exactly on tangent of the sphere from the camera
+      // > 0 = facing away
+      const dot = tempV.dot(cameraToPoint);
 
 
       // if the orientation is not facing us hide it.
       // if the orientation is not facing us hide it.
-      if (dot < visibleDot) {
+      if (dot > settings.maxVisibleDot) {
         elem.style.display = 'none';
         elem.style.display = 'none';
         continue;
         continue;
       }
       }

+ 20 - 13
threejs/threejs-indexed-textures-picking-debounced.html

@@ -59,11 +59,10 @@
 <script src="resources/threejs/r102/three.js"></script>
 <script src="resources/threejs/r102/three.js"></script>
 <script src="resources/threejs/r102/js/utils/BufferGeometryUtils.js"></script>
 <script src="resources/threejs/r102/js/utils/BufferGeometryUtils.js"></script>
 <script src="resources/threejs/r102/js/controls/OrbitControls.js"></script>
 <script src="resources/threejs/r102/js/controls/OrbitControls.js"></script>
-<script src="../3rdparty/dat.gui.min.js"></script>
 <script>
 <script>
 'use strict';
 'use strict';
 
 
-/* global THREE, dat */
+/* global THREE */
 
 
 function main() {
 function main() {
   const canvas = document.querySelector('#c');
   const canvas = document.querySelector('#c');
@@ -230,16 +229,14 @@ function main() {
   loadCountryData();
   loadCountryData();
 
 
   const tempV = new THREE.Vector3();
   const tempV = new THREE.Vector3();
+  const cameraToPoint = new THREE.Vector3();
+  const cameraPosition = new THREE.Vector3();
   const normalMatrix = new THREE.Matrix3();
   const normalMatrix = new THREE.Matrix3();
-  const positiveZ = new THREE.Vector3(0, 0, 1);
 
 
   const settings = {
   const settings = {
     minArea: 20,
     minArea: 20,
-    visibleAngleDeg: 75,
+    maxVisibleDot: -0.2,
   };
   };
-  const gui = new dat.GUI({width: 300});
-  gui.add(settings, 'minArea', 0, 50).onChange(requestRenderIfNotRequested);
-  gui.add(settings, 'visibleAngleDeg', 0, 180).onChange(requestRenderIfNotRequested);
 
 
   function updateLabels() {
   function updateLabels() {
     // exit if we have not loaded the data yet
     // exit if we have not loaded the data yet
@@ -248,9 +245,10 @@ function main() {
     }
     }
 
 
     const large = settings.minArea * settings.minArea;
     const large = settings.minArea * settings.minArea;
-    const visibleDot = Math.cos(THREE.Math.degToRad(settings.visibleAngleDeg));
     // get a matrix that represents a relative orientation of the camera
     // get a matrix that represents a relative orientation of the camera
     normalMatrix.getNormalMatrix(camera.matrixWorldInverse);
     normalMatrix.getNormalMatrix(camera.matrixWorldInverse);
+    // get the camera's position
+    camera.getWorldPosition(cameraPosition);
     for (const countryInfo of countryInfos) {
     for (const countryInfo of countryInfos) {
       const {position, elem, area, selected} = countryInfo;
       const {position, elem, area, selected} = countryInfo;
       const largeEnough = area >= large;
       const largeEnough = area >= large;
@@ -260,16 +258,25 @@ function main() {
         continue;
         continue;
       }
       }
 
 
-      // orient the position based on the camera's orientation
+      // Orient the position based on the camera's orientation.
+      // Since the sphere is at the origin and the sphere is a unit sphere
+      // this gives us a camera relative direction vector for the position.
       tempV.copy(position);
       tempV.copy(position);
       tempV.applyMatrix3(normalMatrix);
       tempV.applyMatrix3(normalMatrix);
 
 
-      // get the dot product with positiveZ
-      // -1 = facing directly away and +1 = facing directly toward us
-      const dot = tempV.dot(positiveZ);
+      // compute the direction to this position from the camera
+      cameraToPoint.copy(position);
+      cameraToPoint.applyMatrix4(camera.matrixWorldInverse).normalize();
+
+      // get the dot product of camera relative direction to this position
+      // on the globe with the direction from the camera to that point.
+      // -1 = facing directly towards the camera
+      // 0 = exactly on tangent of the sphere from the camera
+      // > 0 = facing away
+      const dot = tempV.dot(cameraToPoint);
 
 
       // if the orientation is not facing us hide it.
       // if the orientation is not facing us hide it.
-      if (dot < visibleDot) {
+      if (dot > settings.maxVisibleDot) {
         elem.style.display = 'none';
         elem.style.display = 'none';
         continue;
         continue;
       }
       }

+ 20 - 13
threejs/threejs-indexed-textures-picking.html

@@ -59,11 +59,10 @@
 <script src="resources/threejs/r102/three.js"></script>
 <script src="resources/threejs/r102/three.js"></script>
 <script src="resources/threejs/r102/js/utils/BufferGeometryUtils.js"></script>
 <script src="resources/threejs/r102/js/utils/BufferGeometryUtils.js"></script>
 <script src="resources/threejs/r102/js/controls/OrbitControls.js"></script>
 <script src="resources/threejs/r102/js/controls/OrbitControls.js"></script>
-<script src="../3rdparty/dat.gui.min.js"></script>
 <script>
 <script>
 'use strict';
 'use strict';
 
 
-/* global THREE, dat */
+/* global THREE */
 
 
 function main() {
 function main() {
   const canvas = document.querySelector('#c');
   const canvas = document.querySelector('#c');
@@ -161,16 +160,14 @@ function main() {
   loadCountryData();
   loadCountryData();
 
 
   const tempV = new THREE.Vector3();
   const tempV = new THREE.Vector3();
+  const cameraToPoint = new THREE.Vector3();
+  const cameraPosition = new THREE.Vector3();
   const normalMatrix = new THREE.Matrix3();
   const normalMatrix = new THREE.Matrix3();
-  const positiveZ = new THREE.Vector3(0, 0, 1);
 
 
   const settings = {
   const settings = {
     minArea: 20,
     minArea: 20,
-    visibleAngleDeg: 75,
+    maxVisibleDot: -0.2,
   };
   };
-  const gui = new dat.GUI({width: 300});
-  gui.add(settings, 'minArea', 0, 50).onChange(requestRenderIfNotRequested);
-  gui.add(settings, 'visibleAngleDeg', 0, 180).onChange(requestRenderIfNotRequested);
 
 
   function updateLabels() {
   function updateLabels() {
     // exit if we have not loaded the data yet
     // exit if we have not loaded the data yet
@@ -179,9 +176,10 @@ function main() {
     }
     }
 
 
     const large = settings.minArea * settings.minArea;
     const large = settings.minArea * settings.minArea;
-    const visibleDot = Math.cos(THREE.Math.degToRad(settings.visibleAngleDeg));
     // get a matrix that represents a relative orientation of the camera
     // get a matrix that represents a relative orientation of the camera
     normalMatrix.getNormalMatrix(camera.matrixWorldInverse);
     normalMatrix.getNormalMatrix(camera.matrixWorldInverse);
+    // get the camera's position
+    camera.getWorldPosition(cameraPosition);
     for (const countryInfo of countryInfos) {
     for (const countryInfo of countryInfos) {
       const {position, elem, area, selected} = countryInfo;
       const {position, elem, area, selected} = countryInfo;
       const largeEnough = area >= large;
       const largeEnough = area >= large;
@@ -191,16 +189,25 @@ function main() {
         continue;
         continue;
       }
       }
 
 
-      // orient the position based on the camera's orientation
+      // Orient the position based on the camera's orientation.
+      // Since the sphere is at the origin and the sphere is a unit sphere
+      // this gives us a camera relative direction vector for the position.
       tempV.copy(position);
       tempV.copy(position);
       tempV.applyMatrix3(normalMatrix);
       tempV.applyMatrix3(normalMatrix);
 
 
-      // get the dot product with positiveZ
-      // -1 = facing directly away and +1 = facing directly toward us
-      const dot = tempV.dot(positiveZ);
+      // compute the direction to this position from the camera
+      cameraToPoint.copy(position);
+      cameraToPoint.applyMatrix4(camera.matrixWorldInverse).normalize();
+
+      // get the dot product of camera relative direction to this position
+      // on the globe with the direction from the camera to that point.
+      // 1 = facing directly towards the camera
+      // 0 = exactly on tangent of the sphere from the camera
+      // < 0 = facing away
+      const dot = tempV.dot(cameraToPoint);
 
 
       // if the orientation is not facing us hide it.
       // if the orientation is not facing us hide it.
-      if (dot < visibleDot) {
+      if (dot > settings.maxVisibleDot) {
         elem.style.display = 'none';
         elem.style.display = 'none';
         continue;
         continue;
       }
       }

+ 20 - 13
threejs/threejs-indexed-textures-random-colors.html

@@ -59,11 +59,10 @@
 <script src="resources/threejs/r102/three.js"></script>
 <script src="resources/threejs/r102/three.js"></script>
 <script src="resources/threejs/r102/js/utils/BufferGeometryUtils.js"></script>
 <script src="resources/threejs/r102/js/utils/BufferGeometryUtils.js"></script>
 <script src="resources/threejs/r102/js/controls/OrbitControls.js"></script>
 <script src="resources/threejs/r102/js/controls/OrbitControls.js"></script>
-<script src="../3rdparty/dat.gui.min.js"></script>
 <script>
 <script>
 'use strict';
 'use strict';
 
 
-/* global THREE, dat */
+/* global THREE */
 
 
 function main() {
 function main() {
   const canvas = document.querySelector('#c');
   const canvas = document.querySelector('#c');
@@ -210,16 +209,14 @@ function main() {
   loadCountryData();
   loadCountryData();
 
 
   const tempV = new THREE.Vector3();
   const tempV = new THREE.Vector3();
+  const cameraToPoint = new THREE.Vector3();
+  const cameraPosition = new THREE.Vector3();
   const normalMatrix = new THREE.Matrix3();
   const normalMatrix = new THREE.Matrix3();
-  const positiveZ = new THREE.Vector3(0, 0, 1);
 
 
   const settings = {
   const settings = {
     minArea: 20,
     minArea: 20,
-    visibleAngleDeg: 75,
+    maxVisibleDot: -0.2,
   };
   };
-  const gui = new dat.GUI({width: 300});
-  gui.add(settings, 'minArea', 0, 50).onChange(requestRenderIfNotRequested);
-  gui.add(settings, 'visibleAngleDeg', 0, 180).onChange(requestRenderIfNotRequested);
 
 
   function updateLabels() {
   function updateLabels() {
     // exit if we have not loaded the data yet
     // exit if we have not loaded the data yet
@@ -228,9 +225,10 @@ function main() {
     }
     }
 
 
     const large = settings.minArea * settings.minArea;
     const large = settings.minArea * settings.minArea;
-    const visibleDot = Math.cos(THREE.Math.degToRad(settings.visibleAngleDeg));
     // get a matrix that represents a relative orientation of the camera
     // get a matrix that represents a relative orientation of the camera
     normalMatrix.getNormalMatrix(camera.matrixWorldInverse);
     normalMatrix.getNormalMatrix(camera.matrixWorldInverse);
+    // get the camera's position
+    camera.getWorldPosition(cameraPosition);
     for (const countryInfo of countryInfos) {
     for (const countryInfo of countryInfos) {
       const {position, elem, area, selected} = countryInfo;
       const {position, elem, area, selected} = countryInfo;
       const largeEnough = area >= large;
       const largeEnough = area >= large;
@@ -240,16 +238,25 @@ function main() {
         continue;
         continue;
       }
       }
 
 
-      // orient the position based on the camera's orientation
+      // Orient the position based on the camera's orientation.
+      // Since the sphere is at the origin and the sphere is a unit sphere
+      // this gives us a camera relative direction vector for the position.
       tempV.copy(position);
       tempV.copy(position);
       tempV.applyMatrix3(normalMatrix);
       tempV.applyMatrix3(normalMatrix);
 
 
-      // get the dot product with positiveZ
-      // -1 = facing directly away and +1 = facing directly toward us
-      const dot = tempV.dot(positiveZ);
+      // compute the direction to this position from the camera
+      cameraToPoint.copy(position);
+      cameraToPoint.applyMatrix4(camera.matrixWorldInverse).normalize();
+
+      // get the dot product of camera relative direction to this position
+      // on the globe with the direction from the camera to that point.
+      // -1 = facing directly towards the camera
+      // 0 = exactly on tangent of the sphere from the camera
+      // > 0 = facing away
+      const dot = tempV.dot(cameraToPoint);
 
 
       // if the orientation is not facing us hide it.
       // if the orientation is not facing us hide it.
-      if (dot < visibleDot) {
+      if (dot > settings.maxVisibleDot) {
         elem.style.display = 'none';
         elem.style.display = 'none';
         continue;
         continue;
       }
       }