📜  计算机图形学领域细分算法(1)

📅  最后修改于: 2023-12-03 14:57:32.040000             🧑  作者: Mango

计算机图形学领域细分算法

计算机图形学涉及到许多领域,其中一个比较重要的领域就是细分算法。细分算法可以将一个形状或者一个曲线划分成更小的片段以便于进行处理和渲染。

细分算法的类型
线性细分

线性细分算法是将一个曲线或者形状分成多个线段或者面片,这些线段或者面片之间没有连续性,是独立的。线性细分算法可以通过计算所需的顶点数量,来控制细分后的形状的精度。

曲线细分

曲线细分算法是将一个曲线分成多个曲线,这些曲线之间是连续的,并且曲线的参数是按照一定的规律变化的。曲线细分算法通常用于生成放置曲面的控制点。

曲面细分

曲面细分算法是将一个曲面分成多个曲面片,这些曲面片之间是连续的,并且曲面的参数也是按照一定的规律变化的。曲面细分算法通常用于生成更高精度的曲面。

细分算法的实现方法
Catmull-Clark细分算法

Catmull-Clark细分算法是一种曲面细分算法,它通过对曲面进行顶点平均和面片分割来实现。该算法的优点是可以处理具有任意拓扑形态的曲面,并且细分后的曲面仍然具有相同的拓扑形态。该算法的缺点是对于面数较大的曲面,计算量较大。

// 示例代码
function catmullClark (mesh) {
  // 对每个面进行细分
  for (let face of mesh.faces) {
    // 计算面的中心点
    let center = new Vector3(0, 0, 0)
    for (let v of face.vertices) {
      center.add(v.position)
    }
    center.divide(face.vertices.length)
    
    // 将面分成多个四边形
    let vertices = face.vertices
    let n = vertices.length
    let faces = []
    for (let i = 0; i < n; i++) {
      let a = vertices[i]
      let b = vertices[(i + 1) % n]
      let c = center
      let d = vertices[(i + n - 1) % n].clone()
      let newVertices = [a, b, c, d]
      let newFace = new Face(newVertices)
      faces.push(newFace)
    }
    
    // 更新原来的面和其相邻的面
    for (let f of face.adjacentFaces) {
      if (f !== face) {
        f.vertices.push(center)
      }
      // TODO: 更新新的四边形面的位置和法线
    }
  }
  
  // 对每个顶点进行细分
  for (let vertex of mesh.vertices) {
    // 计算相邻面的中心点和相邻顶点的中心点,即更新顶点坐标
    let center1 = new Vector3(0, 0, 0)
    let center2 = new Vector3(0, 0, 0)
    for (let face of vertex.adjacentFaces) {
      center1.add(face.centroid)
      for (let v of face.vertices) {
        if (v !== vertex) {
          center2.add(v.position)
        }
      }
    }
    center1.divide(vertex.adjacentFaces.length)
    center2.divide(vertex.adjacentVertices.length)
    let newPos = center1.clone().multiplyScalar(0.75).add(center2.clone().multiplyScalar(0.25)).add(vertex.position.clone().multiplyScalar(0.5))
    vertex.position = newPos
    // TODO: 更新顶点法线
  }
  
  // 更新曲面的拓扑结构和属性
  // TODO: ...
}
Loop细分算法

Loop细分算法也是一种曲面细分算法,它通过对曲面进行顶点平均和面片分割来实现。该算法相对于Catmull-Clark细分算法来说计算量更小,但是对于非平面的曲面可能会存在一些问题。

// 示例代码
function loop (mesh) {
  // 对每个面进行细分
  for (let face of mesh.faces) {
    // 将面分成多个三角形
    let vertices = face.vertices
    let n = vertices.length
    let faces = []
    for (let i = 0; i < n; i++) {
      let a = vertices[i]
      let b = vertices[(i + 1) % n]
      let c = vertices[(i + 2) % n]
      let newVertices = [a, b, c]
      let newFace = new Face(newVertices)
      faces.push(newFace)
    }

    // 更新原来的面和其相邻的面
    for (let f of face.adjacentFaces) {
      if (f !== face) {
        let e = f.getEdge(face)
        e.subdivisionEdge.updatePosition()
      }
      // TODO: 更新新的三角形面的位置和法线
    }
  }

  // 对每个顶点进行细分
  for (let vertex of mesh.vertices) {
    // 计算顶点的权重,即计算相邻面的数量、相邻顶点的数量和相邻边的数量
    let nF = vertex.adjacentFaces.length
    let nV = vertex.adjacentVertices.length
    let nE = vertex.adjacentEdges.length
    let beta = 0
    if (nF === 3) {
      beta = 3 / 16
    } else {
      beta = 3 / (8 * nF)
    }
    let gamma = 1 / nV
    let delta = 3 / (8 * nE)

    // 计算相邻顶点的中心点和相邻边的中心点
    let center1 = new Vector3(0, 0, 0)
    let center2 = new Vector3(0, 0, 0)
    for (let v of vertex.adjacentVertices) {
      center1.add(v.position)
    }
    center1.divide(nV)
    for (let e of vertex.adjacentEdges) {
      center2.add(e.subdivisionEdge.position)
    }
    center2.divide(nE)

    // 更新顶点坐标
    let newPos = vertex.position.clone().multiplyScalar(1 - nF * beta - nV * gamma - nE * delta).add(center1.clone().multiplyScalar(gamma)).add(center2.clone().multiplyScalar(delta))
    vertex.position = newPos
    // TODO: 更新顶点法线
  }

  // 更新曲面的拓扑结构和属性
  // TODO: ...
}
参考文献