checkTransparent.js 3.54 KB
import { Vector3 } from "three";
/**
 * 網格排序,根據網格與 camera 的距離,重新排序網格拓樸,讓與 camera 距離愈遠的網格拓樸排在陣列愈前面。
 * 拓樸在陣列前面代表會先畫,後畫代表網格會顯示在先畫的前面(不會被蓋住),與 camera 愈近的網格愈後畫。
 * 對物件本身的透明度顯示進行改善,改善透明顯示下三角網格破碎的情況
 * @param {*THREE.BufferGeometry} geometry
 * @param {*THREE.Matrix4} matrix           模型移動矩陣
 * @param {*THREE.Matrix4} viewMatrix       camera視角矩陣
 */
export const checkTransparent = (geometry, matrix, viewMatrix) => {
  //camera視角矩陣的 8 9 10 元素為z軸,z軸為 camera 與 camera.lookAt 的軸向
  let viewVec0 = viewMatrix.elements[8];
  let viewVec1 = viewMatrix.elements[9];
  let viewVec2 = viewMatrix.elements[10];

  let position = geometry.getAttribute("position");
  let vertexLength = position == undefined ? 0 : position.count;
  if (vertexLength == 0) return;
  let index = geometry.getIndex();
  let faceLength = index ? index.count / 3 : Math.round(vertexLength / 3);
  let TriZF = new Array(faceLength);
  let faceIndex = 0;
  while (faceIndex < faceLength) {
    let face = getFaceIndices(geometry, faceIndex);
    let vertexa = getVertexUsingIndex(geometry, face.a);
    let vertexb = getVertexUsingIndex(geometry, face.b);
    let vertexc = getVertexUsingIndex(geometry, face.c);

    vertexa = new Vector3(vertexa.x, vertexa.y, vertexa.z);
    vertexb = new Vector3(vertexb.x, vertexb.y, vertexb.z);
    vertexc = new Vector3(vertexc.x, vertexc.y, vertexc.z);

    if (vertexa == undefined || vertexb == undefined || vertexc == undefined) {
      faceIndex++;
      continue;
    }
    let va = vertexa.applyMatrix4(matrix);
    let vb = vertexb.applyMatrix4(matrix);
    let vc = vertexc.applyMatrix4(matrix);
    let pt = va.add(vb).add(vc).multiplyScalar(0.333);
    let Z = viewVec0 * pt.x + viewVec1 * pt.y + viewVec2 * pt.z;
    TriZF[faceIndex] = {
      Z: Z,
      index: faceIndex,
    };
    faceIndex++;
  }
  TriZF.sort(function (a, b) {
    // Z值有正負號,負值愈大代表距離離camera愈遠
    return a.Z - b.Z;
  });
  let indices = [];
  let i = 0;
  while (i < TriZF.length) {
    if (TriZF[i] == undefined) {
      continue;
    }
    let face = getFaceIndices(geometry, TriZF[i].index);
    indices.push(face.a, face.b, face.c);
    ++i;
  }
  geometry.setIndex(indices);
  TriZF = undefined;
  indices = undefined;
};

/**
 * 設定網格拓樸
 */
const setIndices = (geometry) => {
  let indices = geometry.getIndex();
  if (indices == null) {
    let position = geometry.getAttribute("position");
    let vertexLength = position == undefined ? 0 : position.count;
    let indices = [];
    for (let id = 0; id < vertexLength; id += 3) {
      indices.push(id, id + 1, id + 2);
    }
    if (indices.length > 0) {
      geometry.setIndex(indices);
    }
  }
};

/**
 * 取得 faceIndex 網格面的周圍頂點 index
 */
const getFaceIndices = (geometry, faceIndex) => {
  setIndices(geometry);
  let a, b, c;
  let indices = geometry.getIndex();
  a = indices.array[faceIndex * 3 + 0];
  b = indices.array[faceIndex * 3 + 1];
  c = indices.array[faceIndex * 3 + 2];
  return { a: a, b: b, c: c };
};

/**
 * 取得 index 頂點座標 x y z
 */
const getVertexUsingIndex = (geometry, index) => {
  let position = geometry.getAttribute("position");
  if (position == undefined) return new Vector3();
  return {
    x: position.getX(index),
    y: position.getY(index),
    z: position.getZ(index),
  };
};