姓名:卜凡

学号:2020211066

指导老师:符强

日期:2022-04-12 ~ 27

[#] 作业内容

  1. 使用附件中的 Catmull-Clark 四边形网格细分算法例程,修改并移植到自己的工程中;
  2. 场景中构造两个正方体网格,其中一个正方体位置固定,另一个正方体环绕着固定的正方体运动;
  3. 运动一圈后两个正方体进行网格细分,然后进行下一圈运动,即随着圈数增加,两个网格的形状会从正方体逐步细分到球体;
  4. 在 3 到 4 圈后停止运动(否则可能会由于过度细分造成程序卡死);
  5. 报告中给出运动控制流程,结果截图(包含多次细分的结果)等内容。

[1] 定义坐标点类和网格模型类

1.1 定义坐标点类

如下代码定义了表示三维坐标中的坐标点的 Point 类。它主要由 xyz 三个坐标构成。

技术要点:

# 表示三维坐标中的点。
class Point(object):
    
    def __init__(self, *args):

        # [0 参数] 默认构造方法:x 与 y 默认值均为 0
        if (len(args) == 0):
            self.x = self.y = self.z = 0.0

        # [1 参数] 复制构造方法
        elif (len(args) == 1 and isinstance(args[0], Point)):
            other = args[0];
            self.x = other.x
            self.y = other.y
            self.z = other.z

        # [1 参数] 构造方法,三参数均为同一值
        elif (len(args) == 1 and isinstance(args[0], (int, float))):
            value = args[0]
            self.x = self.y = self.z = value

        # [3 参数] 构造方法
        elif (len(args) == 3 and isinstance(args[0], (int, float))
                             and isinstance(args[1], (int, float))
                             and isinstance(args[2], (int, float))):
            self.x = args[0]
            self.y = args[1]
            self.z = args[2]
				
				# [其他参数] 抛出异常,表示参数不合法。
        else:
            raise ValueError("invalid args", args)

    # 重载 + 运算符:Point 之间的加法
    def __add__(self, other) -> object:
        return Point(self.x + other.x, self.y + other.y, self.z + other.z)
    # 重载 - 运算符:Point 之间的减法
    def __sub__(self, other) -> object:
        return Point(self.x - other.x, self.y - other.y, self.z - other.z)

    # 重载 * 运算符:Point 和实数之间的减法
    def __mul__(self, num:float) -> object:
        return Point(self.x * num, self.y * num, self.z * num)
    # 定义反 * 运算符:同上
    def __rmul__(self, num:float) -> object:
        return self.__mul__(num)

    # 定义字符串化方法
    def __str__(self) -> str:
        return "P(%.3f, %.3f, %.3f)" % (self.x, self.y, self.z)

    def toTuple(self) -> T.Tuple[float, float, float]:
        return (self.x, self.y, self.z)

    # 定义求两 Point 之间距离的方法
    def dist(self, other) -> float:
        return math.sqrt((self.x - other.x) ** 2
                         + (self.y - other.y) ** 2
                         + (self.z - other.z) ** 2)
    # 重载 / 运算符:同上
    def __truediv__(self, other) -> float:
        return self.dist(other)

1.2 定义网格模型类

下面部分的代码定义了表示三维坐标中的一个多边形网格的 Mesh 类。它主要由顶点坐标序列(下称 ptList )和表示各面具有哪些顶点的下标矩阵(下称 idMatrix )构成。

如下图是一个标准立方体的例子,其 ptListidMatrix 如下代码块:

Untitled

ptList = [Point(1,1,-1), Point(1,-1,-1), Point(-1,-1,-1), Point(-1,1,-1), 
          Point(1,1,1), Point(1,-1,1), Point(-1,-1,1), Point(-1,1,1)]
idMatrix = [[0,1,2,3], [3,2,6,7], [4,0,3,7], [4,5,1,0], [7,6,5,4], [1,5,6,2]]

技术要点:

# 表示多边形网格模型。注意采用的方法是 Point 列表和表示如何成面的 id 矩阵。
class Mesh(object):

    # Mesh - Part.1 定义对象工作的部分
   
    def __init__(self, *args):

        # [0 参数] 默认空构造方法
        if (len(args) == 0):
            self.ptList = list()
            self.idMatrix = list()

        # [1 参数] 复制构造方法
        elif (len(args) == 1 and isinstance(args[0], Mesh)):
            other = args[0]
            # 做深拷贝
            self.ptList = [pt for pt in other.ptList]
            self.idMatrix = [[index for index in faceids] for faceids in other.idMatrix]

        # [2 参数] 传入点列表和 id 矩阵的构造方法
        elif (len(args) == 2) and isinstance(args[0], list) \\
                              and (isinstance(args[0][0], Point)) \\
                              and (isinstance(args[1], list)) \\
                              and (isinstance(args[1][0], list)) \\
                              and (isinstance(args[1][0][0], int)):
            ptList = args[0]
            idMatrix = args[1]
            # 做深拷贝
            self.ptList = [pt for pt in ptList]
            self.idMatrix = [[index for index in faceids] for faceids in idMatrix]

        else:
            raise ValueError("invalid args", args)

    # 重载 + 运算符:ptList 中每个 Point 都对给定点做加法
    def __add__(self, other:Point) -> object:
        for i in range(len(self.ptList)):
            self.ptList[i] = self.ptList[i] + other;
    # 重载 - 运算符:ptList 中每个 Point 都对给定点做减法
    def __sub__(self, other:Point) -> object:
        for i in range(len(self.ptList)):
            self.ptList[i] = self.ptList[i] - other;

    # 定义字符串化方法
    def __str__(self) -> str:
        # join 是字符串化序列最高效的方法
        return "M{[" + ", ".join([pt.__str__() for pt in self.ptList]) + "], [" \\
            + ", ".join("["
                + [", ".join([index for index in faceids]) for faceids in self.idMatrix]
            + "]") + "]}"

    # 定义绘制方法
    def render(self) -> None:
        for faceids in self.idMatrix:
            glBegin(GL_LINE_LOOP)  # 绘制线环
            for index in faceids:
                glVertex3f(self.ptList[index].x, self.ptList[index].y, self.ptList[index].z)
            glEnd()

		# Mesh - Part.2 定义算法工作的部分(见下)