1
votes

I am using recasting to cast a ray from each face midpoint of a mesh to the mesh itself to find local thickness. Interestingly, because of the mesh arrangement, sometimes the ray passes between the triangles and do not show correct thickness. Someone mentioned to me as a problem with float precision. I was wondering if anyone know how to improve my code. Thank You.

var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 100000);
camera.position.setScalar(500);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

var controls = new THREE.OrbitControls(camera, renderer.domElement);

var loader = new THREE.STLLoader();
loader.load('https://sos-ch-dk-2.exo.io/stl-upload-test/uploads/stl/5bd15fae89ff9a1cb7816af9/stl/hexagon.STL', function(geometry) {
  var material = new THREE.MeshBasicMaterial({ side: THREE.DoubleSide, vertexColors: THREE.VertexColors});
  var mesh = new THREE.Mesh(geometry, material);
  scene.add(mesh);
  colorMesh(mesh);
});

function colorMesh(mesh) {

  //var minDist = 0.6;
	var colorArray = [];
  var raycaster = new THREE.Raycaster();
  var intersects = [];

  var pos = mesh.geometry.attributes.position;

  var ori = new THREE.Vector3();
  var dir = new THREE.Vector3();
  var trc = new THREE.Vector3();
  var a = new THREE.Vector3(),
    b = new THREE.Vector3(),
    c = new THREE.Vector3(),
    midPoint = new THREE.Vector3(),
    tri = new THREE.Triangle();
  var closest = new THREE.Vector3();

  var faces = pos.count / 3;
  for (let i = 0; i < faces; i++) {
    a.fromBufferAttribute(pos, i * 3 + 0);
    b.fromBufferAttribute(pos, i * 3 + 1);
    c.fromBufferAttribute(pos, i * 3 + 2);
    tri.set(a, b, c);
    tri.getMidpoint(ori);
    tri.getNormal(dir)
    raycaster.set(ori, dir.negate());
    intersects = raycaster.intersectObject(mesh);
		//minDist = Math.min(minDist, intersects[intersects.length > 1 ? 1 : 0].distance);
    minDist = intersects[intersects.length > 1 ? 1 : 0].distance;
    console.log(minDist);
    
    var col =  new THREE.Vector3(Math.floor((10/minDist)*255),Math.floor(0.01*minDist*255),0);	
    //var col =  new THREE.Vector3(0,0,0);	
    
    for (var j = 0;j<3;j++) {
      colorArray.push(col.x);
      colorArray.push(col.y);
      colorArray.push(col.z);
    }
    console.log(col);
  }
  var colors = new Uint8Array( colorArray );

  mesh.geometry.addAttribute( 'color', new THREE.BufferAttribute( colors, 3,true ) );

	//helper = new THREE.VertexNormalsHelper( objects[0], 2, 0x00ff00, 1 );
				// scene.add(helper);
  //return minDist >= 0.6;
}


renderer.setAnimationLoop(() => {
  renderer.render(scene, camera)
});
body {
  overflow: hidden;
  margin: 0;
}
<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
<script src="https://threejs.org/examples/js/loaders/STLLoader.js"></script>

sample image

1
You'll have to show us your code to get any kind of meaningful answer. - mypetlion
Sure, how can I add my code, it is bit long, and JSFiddle link could not be added! - Hesamoy
Edit your answer. Don't post all of it, just post the relevant parts. Copy paste the code into your answer, don't post a screenshot of the code (pictures of text are useless for trying to help you). - mypetlion
You can add a snippet - gman

1 Answers

2
votes

The problem is that Ray.js does not consider all possible cases. In fact, it returns either the point of intersection, or null which is not enough to handle your problem with edges.

The problem: When ray intersects the mesh, there are many special cases possible:

  1. ray goes exactly through one single vertex of a mesh --> in current implementation this will be reported as zero or one or two or up to N intersections (depends on how floating point accuracy acts on each of N faces based on this vertex)

  2. ray goes exactly along the one of faces,

  3. ray goes along the face and meets the vertex in the end,

... and many more similar situations, but you get the point.


There's a way to significantly mitigate the risk of getting into these situations: don't use face midpoint, take a random point on the face instead.

For example:

// tri.getMidpoint(ori);

// get some random point on face
let r0 = 0.33 * Math.random();
let r1 = 0.33 * Math.random();
let r2 = 1.0 - r0 - r1;

let ori = new THREE.Vector3(
    r0*a.x + r1*b.x + r2*c.x,
    r0*a.y + r1*b.y + r2*c.y,
    r0*a.z + r1*b.z + r2*c.z
);