فهرست منبع

feat: 提交平底平顶三角形绘制说明

nicetry12138 1 سال پیش
والد
کامیت
3e7af0445b

+ 50 - 0
OpenGL/README.md

@@ -599,8 +599,58 @@ bool InPolygon(Point P)
 - **并行或共线**(Collinear):向量 A 和 B 指向完全相同或相反的方向,即一个向量可以通过乘以一个标量来表达另一个向量。例如,如果 A = 2B 或 A = -B。
 - **零向量**:如果其中一个或两个向量是零向量(即其大小为0),那么它们的叉乘结果也将为0
 
+扫描线算法简单实现
+
+```cpp
+void Canvas::drawTriangle(const Point& pt1, const Point& pt2, const Point& pt3)
+{
+    // 获取包围盒
+    int left = MIN(pt3.m_x, MIN(pt2.m_x, pt1.m_x));
+    int bottom = MIN(pt3.m_y, MIN(pt2.m_y, pt1.m_y));
+    int right = MAX(pt3.m_x, MAX(pt2.m_x, pt1.m_x));
+    int top = MAX(pt3.m_y, MAX(pt2.m_y, pt1.m_y));
+    
+    // 剪裁屏幕
+    left = MAX(left, 0);
+    bottom = MAX(bottom, 0);
+    right = MIN(right, m_Width);
+    top = MIN(top, m_Height);
+
+    std::vector<Point> points = { pt1, pt2, pt3 };
+
+    for (int x = left; x <= right; ++x) {
+        for (int y = bottom; y <= top; ++y) {
+            if (judgeInTriangle(GT::Point(x, y), points)) {
+                drawPoint(Point(x, y, RGBA(255, 0, 0)));
+            }
+        }
+    }
+}
+```
+
 ### 三角形效率绘制-平底平顶三角形绘制
 
+如果一个三角形既不是平底也不是平顶,它可以被分割成一个平底和一个平顶三角形
+
+- 平底三角形:三角形的底部两个顶点在同一水平线上
+- 平顶三角形:三角形的顶部两个顶点在同一水平线上
+
+对于绘制这两种三角形,我们可以使用**线性插值**的方法来高效地计算每一水平线(scanline)上的交点,并填充这些像素。具体步骤如下:
+
+1. 排序顶点:根据 y 坐标对三角形的三个顶点进行排序,确定三角形是平顶还是平底。如果不是这两种类型,则需要分割
+2. 计算斜率:对于平底或平顶三角形,计算两侧边的斜率(dx/dy),以确定每增加一行 y,x 应该增加多少
+3. 扫描填充:
+    - 对于平底三角形,从顶点向下扫描到底边
+    - 对于平顶三角形,从底边向上扫描到顶点
+    - 在每个 y 级别,根据斜率更新 x 的位置,填充从左到右的像素
+
+对于一般的三角形,可以按照 y 值排序顶点后,找到中间点,将三角形分为一个平底和一个平顶三角形,然后分别使用上述方法渲染
+
+这种方法的优势在于它简化了扫描过程,减少了计算量,使得三角形的填充效率更高
+
+```cpp
+
+```
 
 ### 三角形效率绘制-绘制任意三角形
 

+ 8 - 1
OpenGL/src/WindowsProjectTest/WindowsProjectTest/Canvas.cpp

@@ -76,7 +76,14 @@ namespace GT {
 			}
 		}
 	}
-	void Canvas::drawTriangle(const Point& pt1, const Point& pt2, const Point& pt3)
+
+	void Canvas::drawTriangleFlat(const Point& pt1, const Point& pt2, const Point& pt3)
+	{
+
+	}
+
+	// 扫描线算法绘制三角形
+	void Canvas::drawTriangle_scan(const Point& pt1, const Point& pt2, const Point& pt3)
 	{
 		// 获取包围盒
 		int left = MIN(pt3.m_x, MIN(pt2.m_x, pt1.m_x));

+ 5 - 1
OpenGL/src/WindowsProjectTest/WindowsProjectTest/Canvas.h

@@ -31,7 +31,11 @@ namespace GT {
 		// 画线
 		void drawLine(const Point &pt1, const Point &pt2);
 
-		void drawTriangle(const Point &pt1, const Point &pt2, const Point &pt3);
+		// 平底平顶三角形绘制
+		void drawTriangleFlat(const Point& pt1, const Point& pt2, const Point& pt3);
+
+		// 扫描线算法实现三角形绘制
+		void drawTriangle_scan(const Point &pt1, const Point &pt2, const Point &pt3);
 
 		bool judgeInTriangle(const Point& pt, const std::vector<Point> &_ptArray);
 

+ 1 - 1
OpenGL/src/WindowsProjectTest/WindowsProjectTest/WindowsProjectTest.cpp

@@ -49,7 +49,7 @@ void Render() {
     //}
 
     // 测试三角形
-    _canvas->drawTriangle(GT::Point(10, 10, GT::RGBA(255, 0, 0, 0)), GT::Point(wWidth / 2, wHeight, GT::RGBA(255, 0, 0, 0)), GT::Point(wWidth, 10, GT::RGBA(255, 0, 0, 0)));
+    _canvas->drawTriangle_scan(GT::Point(10, 10, GT::RGBA(255, 0, 0, 0)), GT::Point(wWidth / 2, wHeight, GT::RGBA(255, 0, 0, 0)), GT::Point(wWidth, 10, GT::RGBA(255, 0, 0, 0)));
 
 	// 将 hMem 的数据一次写入到 hDC 中
 	BitBlt(hDC, 0, 0, wWidth, wHeight, hMem, 0, 0, SRCCOPY);