绘制线框三角形
| def triangleWireframed(self, v0, v1, v2, color): |
| self.line(v0[0], v0[1], v1[0], v1[1], color) |
| self.line(v1[0], v1[1], v2[0], v2[1], color) |
| self.line(v2[0], v2[1], v0[0], v0[1], color) |
| |
绘制线框三角形 2(按顶点的 y 轴坐标排序,为扫描线算法做准备)
| def triangleWireframed2(self, v0, v1, v2): |
| vertices = [v0, v1, v2] |
| vertices.sort(key=lambda x: x[1]) |
| self.line( |
| vertices[0][0], |
| vertices[0][1], |
| vertices[1][0], |
| vertices[1][1], |
| [1.0, 0.0, 0.0], |
| ) |
| self.line( |
| vertices[1][0], |
| vertices[1][1], |
| vertices[2][0], |
| vertices[2][1], |
| [0.0, 1.0, 0.0], |
| ) |
| self.line( |
| vertices[2][0], |
| vertices[2][1], |
| vertices[0][0], |
| vertices[0][1], |
| [0.0, 0.0, 1.0], |
| ) |
| |
扫描线算法 / Line Sweeping Algorithm
| def triangle1(self, v0, v1, v2, color): |
| vertices = [v0, v1, v2] |
| vertices.sort(key=lambda x: x[1]) |
| |
| |
| self.triangleWireframed(v0, v1, v2, color) |
| |
| |
| slopeInv2 = (vertices[0][0] - vertices[2][0]) / ( |
| vertices[0][1] - vertices[2][1] |
| ) |
| |
| for i in range(2): |
| v0 = vertices[i] |
| v1 = vertices[i + 1] |
| v2 = vertices[(i + 2) % 3] |
| if v0[1] != v1[1]: |
| slopeInv1 = (v1[0] - v0[0]) / (v1[1] - v0[1]) |
| for y in Utils.fRange(v0[1] + 1, v1[1]): |
| self.line( |
| slopeInv1 * (y - v0[1]) + v0[0], |
| y, |
| slopeInv2 * (y - vertices[0][1]) + vertices[0][0], |
| y, |
| color, |
| ) |
| |
| |
| self.triangleWireframed(vertices[0], vertices[1], vertices[2], [1.0, 0.0, 0.0]) |
| |
基于包围盒 & 重心坐标(Barycentric Coordinates)
| def triangle2(self, v0, v1, v2, color): |
| |
| minX = min(v0[0], v1[0], v2[0]) |
| maxX = max(v0[0], v1[0], v2[0]) |
| minY = min(v0[1], v1[1], v2[1]) |
| maxY = max(v0[1], v1[1], v2[1]) |
| |
| |
| |
| def insideTriangle(x, y, v0, v1, v2): |
| vec1 = [v2[0] - v0[0], v2[0] - v1[0], v2[0] - x] |
| vec2 = [v2[1] - v0[1], v2[1] - v1[1], v2[1] - y] |
| res = [ |
| vec1[1] * vec2[2] - vec1[2] * vec2[1], |
| vec1[2] * vec2[0] - vec1[0] * vec2[2], |
| vec1[0] * vec2[1] - vec1[1] * vec2[0], |
| ] |
| u = res[0] / -res[2] |
| v = res[1] / -res[2] |
| return u > 0 and v > 0 and u + v < 1 |
| |
| for x in Utils.fRange(minX, maxX): |
| for y in Utils.fRange(minY, maxY): |
| if insideTriangle(x, y, v0, v1, v2): |
| self.setPixel(x, y, color) |
| |
| |
| self.triangleWireframed(v0, v1, v2, [1.0, 0.0, 0.0]) |
| |
测试

【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)