Просмотр исходного кода

feat: 添加 alpha 颜色混合

nicetry12138 1 год назад
Родитель
Сommit
1ab1d68bbc

BIN
OpenGL/Image/021.png


BIN
OpenGL/Image/022.png


BIN
OpenGL/Image/023.png


+ 47 - 0
OpenGL/README.md

@@ -958,7 +958,54 @@ stbi_image_free(bits);
 | --- | --- | --- | 
 | ![](Image/019.jpg) | ![](Image/018.png) | ![](Image/020.png) |
 
+### alpha 测试绘制
 
+`A` 通道是一个 `0~255` 的值,表示 `alpha` 的值,表示像素的透明值
+
+- 如果 `alpha` 为 0,表示该像素不应该被显示
+- 如果 `alpha` 为 255, 表示该像素正常显示
+- 如果 `alpha` 为 125, 表示该像素 RGB 颜色显示程度
+
+![](Image/021.png)
+
+最简单粗暴解决方案就是设置设置一个 limit 值,当像素的 alpha 通道大于指定值时才能够进行绘制
+
+```cpp
+void Canvas::setAlphaLimit(byte inLimit) {
+    m_alphaLimit = inLimit;
+}
+
+void Canvas::drawImage(int inX, int inY, GT::Image* inImage)
+{
+    for (int u = 0; u < inImage->GetWidth(); ++u) {
+        for (int v = 0; v < inImage->GetHeight(); ++v) {
+            RGBA color = inImage->GetColor(u, v);
+            if (color.m_a > m_alphaLimit) {
+                drawPoint(Point(inX + u, inY + v, color));
+            }
+        }
+    }
+}
+```
+
+通过上面粗暴的设置绘制或者不绘制,能够等到一个还可以的效果
+
+![](Image/022.png)
+
+但是观察任务边缘可以发现,边缘过度极其僵硬,这是因为是直接设置像素的显隐性。一般来说为了过度平滑,没有这么明显的毛刺,会设置边缘像素的透明度,让其平滑过渡
+
+这里就涉及到 **带 alpha 颜色混合**
+
+```cpp
+RGBA srcColor = inImage->GetColor(u, v);
+RGBA dstColor = getColor(inX + u, inY + v);
+RGBA finalColor = colorLerp(dstColor, srcColor, srcColor.m_a / 255.0f);
+drawPoint(Point(inX + u, inY + v, finalColor));
+```
+
+| 未开启 alpha 混合 | 开启了 alpha 混合 |
+| --- | --- |
+| ![](Image/022.png) | ![](Image/023.png) |
 
 ## 图形学状态机接口封装
 

+ 24 - 2
OpenGL/src/WindowsProjectTest/WindowsProjectTest/Canvas.cpp

@@ -168,6 +168,21 @@ namespace GT {
 		return;
 	}
 
+	RGBA Canvas::getColor(int inX, int inY)
+	{
+		if (inX < 0 || inX >= m_Width || inY < 0 || inY >= m_Height)
+		{
+			return RGBA(0, 0, 0, 0);
+		}
+
+		return m_Buffer[inY * m_Width + inX];
+	}
+
+	void Canvas::setBlend(bool inUseBlend)
+	{
+		m_UseBlend = inUseBlend;
+	}
+
 	void Canvas::drawTriangleFlat(const Point& pt1, const Point& pt2, const Point& pt)
 	{
 		float k1 = 0.0f;
@@ -286,8 +301,15 @@ namespace GT {
 	{
 		for (int u = 0; u < inImage->GetWidth(); ++u) {
 			for (int v = 0; v < inImage->GetHeight(); ++v) {
-				RGBA color = inImage->GetColor(u, v);
-				drawPoint(Point(inX + u, inY + v, color));
+				RGBA srcColor = inImage->GetColor(u, v);
+				if (!m_UseBlend) {
+					drawPoint(Point(inX + u, inY + v, srcColor));
+				}
+				else {
+					RGBA dstColor = getColor(inX + u, inY + v);
+					RGBA finalColor = colorLerp(dstColor, srcColor, srcColor.m_a / 255.0f);
+					drawPoint(Point(inX + u, inY + v, finalColor));
+				}
 			}
 		}
 	}

+ 10 - 0
OpenGL/src/WindowsProjectTest/WindowsProjectTest/Canvas.h

@@ -14,6 +14,8 @@ namespace GT {
 		int m_Height{ -1 };
 		RGBA* m_Buffer{ nullptr };
 
+		byte m_alphaLimit{ 0 }; // 大于此值的像素才可以进行绘制
+		bool m_UseBlend = true; // 是否进行颜色混合
 
 	public: 
 		Canvas(int _width, int _height, void* _buffer) {
@@ -52,6 +54,14 @@ namespace GT {
 			}
 		}
 
+		void setAlphaLimit(byte inLimit) {
+			m_alphaLimit = inLimit;
+		}
+
+		RGBA getColor(int inX, int inY);
+
+		void setBlend(bool inUseBlend);
+
 	protected:
 		// 平底平顶三角形绘制 pt1 和 pt2 是平底或平顶的两点,pt 是单独的一个顶点
 		void drawTriangleFlat(const Point& pt1, const Point& pt2, const Point& pt);

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

@@ -112,7 +112,8 @@ int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
 	/*===========创建绘图用的位图========*/
 
 	_canvas = new GT::Canvas(wWidth, wHeight, buffer);
-	_image = GT::Image::readFromFile("res/sun.jpg");
+    _canvas->setAlphaLimit(0);
+	_image = GT::Image::readFromFile("res/carma.png");
 	//_zoomImage = GT::Image::zoomImage(_image, 3, 3);
 	//_zoomImageSimple = GT::Image::zoomImageSimple(_image, 3, 3);
 	//// _image->setAlpha(0.5);