11、OpenGL - 混合(颜色混合)
混合
OpenGL 渲染時會把顏色存在顏色緩沖區中,每個片段的深度值也是放在深度緩沖區。
當深度緩沖區被關閉時,新的顏色將簡單的覆蓋原來顏色緩沖區存在的顏色值。
當深度緩沖區再次打開時,新的顏色片段只是當他們比原來的值更接近臨近的裁剪屏幕才會替換原來的顏色片段
//開啟混合
?
1、顏色混合
目標顏色:已經存儲在顏色緩存區的顏色值(已經存在的顏色,舊顏色)
源顏色:作為當前渲染命令結果進入顏色緩沖區的顏色(新進來的顏色,新顏色)
(顏色混合可以這樣理解,好比做一個濾鏡效果。目標顏色就是我們當前原圖的顏色值,是我們要渲染的目標。源顏色就是濾鏡顏色。就好比是獲取 一個數據源,然后根據這個數據源上的顏色值去渲染我們實際的目標圖片,得到混合后的顏色)。
固定著色器 / 可編程著色器 -> 使用開關方式 -> 顏色混合(單純的2個圖層重疊進行混合)
可編程著色器 -> 片元著色器 -> 處理圖片原圖顏色 + 顏色(顏色值)-> 進行顏色混合方程式計算 -> 套用公式
當混合功能被開啟的時候,源顏色和目標顏色的組合方式是混合方程式控制的。在默認情況下,混合方程式如下所示:
Cf = (Cs * S) + (Cd * D);
- Cf:最終計算參數的顏色
- Cs:源顏色
- Cd:目標顏色
- S:源混合因子,源Alpha 混合因子
- D:目標混合因子,目標 Alpha 混合因子
?
2、設置混合因子
使用? glBlendFunc 函數
?
| GL_ZERO?? ??? ??? ??? ??? ??? ? | (0, 0, 0)?? ??? ??? ??? ? | 0 |
| GL_ONE?? ??? ??? ??? ??? ??? | (1, 1, 1)?? ??? ??? ??? ? | 1 |
| GL_SRC_COLOR?? ??? ??? ??? ? | (Rs, Gs, Bs)?? ??? ??? ? | As |
| GL_ONE_MINUS_SCR_COLOR?? ? | (1, 1, 1) - (Rd, Gd, Bs)?? ? | 1 - As |
| GL_DST_COLOR?? ??? ??? ??? ? | (Rd, Gd, Bd)?? ??? ??? ? | Ad |
| GL_ONE_MINUS_DST_COLOR?? ??? ? | (1, 1, 1) - (Rd, Gd, Bd)?? ? | 1 - Ad |
| GL_SRC_ALPHA?? ??? ??? ??? ? | (As, As, As)?? ??? ??? ? | As |
| GL_ONE_MINUS_SCR_ALPHA?? ??? ? | (1, 1, 1) - (As, As, As)?? ? | 1 - As |
| GL_DST_ALPHA?? ??? ??? ??? ? | (Ad, Ad, Ad)?? ??? ??? ? | Ad |
| GL_ONE_MINUS_DST_ALPHA?? ??? ? | (1, 1, 1) - (Ad, Ad, Ad)?? ? | 1 - Ad |
| GL_CONSTANT_COLOR?? ??? ??? ? | (Rc, Gc, Bc)?? ??? ??? ? | Ac |
| GL_ONE_MINUS_CONSTANT_ALPHA | (1, 1, 1) - (Rc, Gc, Bc)? | 1 - Ac |
| GL_CONSTANT_ALPHA?? ??? ??? ? | (Ac, Ac, Ac)?? ??? ??? ? | Ac |
| GL_ONE_MINUS_CONSTANT_ALPHA | (1, 1, 1) - (Ac, Ac, Ac)?? ? | 1 - Ac |
| GL_SRC_ALPHA_STURATE?? ??? | (f, f, f) *f = min(As, 1-Ad) | 1 |
表中R、G、B、A 分別代表 紅、綠、藍、alpha
表中下標S、D,分別代表源、?標
表中C 代表常量顏?(默認?色)
舉例:下面通過一個常用的混合函數組合來說明問題:
如果顏色緩存區已經有一種顏色紅色(1.0f, 0.0f, 0.0f, 0.0f),這個目標顏色Cd,如果在這上面用一種alpha 為0.6 的藍色(0.0f, 0.0f, 1.0f, 0.6f)
Cd(目標顏色) = (1.0f, 0.0f, 0.0f, 0.0f);
Cs(源顏色) = (0.0f, 0.0f, 1.0f, 0.6f);
S = 源alpha 值 = 0.6f;
D = 1 - 源 alpha 值 = 1-0.6f = 0.4f;
方程式
Cf = (Cs * S) + (Cd * D)
等價于
(Blue * 0.6f) + (Red * 0.4f)
顏色混合總結
剛剛的例子,最終顏色是以原先的紅色(目標顏色)與 后來的藍色(源顏色)進行組合。
源顏色的 alpha 值越高,添加的藍色顏色成分越高,目標顏色所保留的成分就會越少。
混合函數經常用于實現在其他一些不透明的物體前面繪制一個透明物體的效果。
?
3、混合方程式
修改顏色混合方程式。默認混合方程式
Cf = (Cs * S) + (Cd * D)
?
實際上不止一種顏色混合方程式,OpenGL有5個不同的方程式進行選擇。
//選擇混合方程式的函數
glbBendEquation(Glenum mode);| GL_FUNC_ADD | Cf = (Cs * S) + (Cd * D) |
| GL_FUNC_SUBTRACT? | Cf = (Cs * S) - (Cd * D) |
| GL_FUNC_REVERSE_SUBTRACT? | Cf = (Cd * D) - (Cs * S) |
| GL_MIN?? ??? ? | Cf = min(Cs, Cd) |
| GL_MAX? | Cf = max(Cs, Cd) |
常用混合顏色
默認初始化為黑色 (0.0f, 0.0f, 0.0f, 0.0f)。可以修改這個常量混合顏色
?
glBlendFuncSeparate函數
除了能使?OpenGL內置的混合因?,還可以有更靈活的選擇。
glBlendFuncSeparate 注意
glBlendeFunc 指定源和目標 RGBA 值的混合函數;但是 glBlendFuncSeparate 函數則允許為RGB 和 alpha 成分單獨指定混合函數
在混合因子表中
- GL_CONSTANT_COLOR,
- GL_ONE_MINUS_CONSTANT_COLOR
- GL_CONSTANT_ALPHA
- GL_ONE_MINUS_CONSTANT
值允許混合方程式引入一個常量混合顏色。
?
4、demo
詳細代碼參見Demo? 顏色混混 demo
Demo地址 -> OpenGLDemos -> 4.ColorMixing
畫四個固定的矩形,中間畫一個可以移動的矩形,設置矩形的透明度為0.5,移動中間的矩形與其他四個矩形重疊,看一下混合的效果
#include <stdio.h> //顏色組合 #include "GLTools.h" #include "GLShaderManager.h"#ifdef __APPLE__ #include <glut/glut.h> #else #define FREEGLUT_STATIC #include <GL/glut.h> #endif GLBatch squareBatch;//批次類 GLBatch greenBatch; GLBatch redBatch; GLBatch blueBatch; GLBatch blackBatch;GLShaderManager shaderManager;//著色器管理器GLfloat blockSize = 0.2f; GLfloat vVerts[] = {-blockSize, -blockSize, 0.0f,blockSize, -blockSize, 0.0f,blockSize, blockSize, 0.0f,-blockSize, blockSize, 0.0f, }; //main手動觸發 //設置窗口背景顏色 //初始化存儲著色器 //設置圖形頂點數據 //利用GLBatch 三角形批次類,將數據傳遞給著色器 void SetupRC() { // 設置窗口顏色glClearColor(1.0f, 1.0f, 1.0f, 1.0f); // 初始化著色器shaderManager.InitializeStockShaders();// 繪制1個移動的矩形squareBatch.Begin(GL_TRIANGLE_FAN, 4);squareBatch.CopyVertexData3f(vVerts);squareBatch.End();// 繪制4個固定矩形 // 第一個矩形GLfloat vBlock1[] = {0.25f, 0.25f, 0.0f,0.75f, 0.25f, 0.0f,0.75f, 0.75f, 0.0f,0.25f, 0.75f, 0.0f,};greenBatch.Begin(GL_TRIANGLE_FAN, 4);greenBatch.CopyVertexData3f(vBlock1);greenBatch.End();// 第二個矩形GLfloat vBlock2[] = {-0.75f, 0.25f, 0.0f,-0.25f, 0.25f, 0.0f,-0.25f, 0.75f, 0.0f,-0.75f, 0.75f, 0.0f,};redBatch.Begin(GL_TRIANGLE_FAN, 4);redBatch.CopyVertexData3f(vBlock2);redBatch.End();// 第三個矩形GLfloat vBlock3[] = {-0.75f, -0.75f, 0.0f,-0.25f, -0.75f, 0.0f,-0.25f, -0.25f, 0.0f,-0.75f, -0.25f, 0.0f,};blueBatch.Begin(GL_TRIANGLE_FAN, 4);blueBatch.CopyVertexData3f(vBlock3);blueBatch.End();// 第四個矩形GLfloat vBlock4[] = {0.25f, -0.75f, 0.0f,0.75f, -0.75f, 0.0f,0.75f, -0.25f, 0.0f,0.25f, -0.25f, 0.0f,};blackBatch.Begin(GL_TRIANGLE_FAN, 4);blackBatch.CopyVertexData3f(vBlock4);blackBatch.End(); } //上下左右鍵控制移動 void SpecialKeys(int key, int x, int y) {GLfloat stepSize = 0.025f;GLfloat blockX = vVerts[0];GLfloat blockY = vVerts[7];if (key == GLUT_KEY_UP)blockY += stepSize;if (key == GLUT_KEY_DOWN)blockY -= stepSize;if (key == GLUT_KEY_LEFT)blockX -= stepSize;if (key == GLUT_KEY_RIGHT)blockX += stepSize;if (blockX < -1.0f) blockX = -1.0f;if (blockX > (1.0f - blockSize * 2)) blockX = 1.0f - blockSize * 2;if (blockY < (-1.0f + blockSize * 2)) blockY = -1.0f + blockSize * 2;if (blockY > 1.0f) blockY = 1.0f;vVerts[0] = blockX;vVerts[1] = blockY - blockSize * 2;vVerts[3] = blockX + blockSize * 2;vVerts[4] = blockY - blockSize * 2;vVerts[6] = blockX + blockSize * 2;vVerts[7] = blockY;vVerts[9] = blockX;vVerts[10] = blockY;squareBatch.CopyVertexData3f(vVerts);glutPostRedisplay(); } void RenderScene(void) { // 清理緩沖區 (顏色、深度、模板緩沖區)glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);// 1、開啟混合glEnable(GL_BLEND); // 2、開啟組合函數 計算混合顏色因子glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);// 定義4種顏色GLfloat vRed[] = { 1.0f, 0.0f, 0.0f, 1.0f};GLfloat vRed1[] = { 1.0f, 0.0f, 0.0f, 0.5f};GLfloat vGreen[] = { 0.0f, 1.0f, 0.0f, 0.5f};GLfloat vBlue[] = { 0.0f, 0.0f, 1.0f, 0.5f};GLfloat vBlack[] = { 0.0f, 0.0f, 0.0f, 0.5f};// 3、使用著色器管理器 // 使用單位著色器 // 參數1:簡單的使用默認笛卡爾坐標系(-1,1),所有片段都應用一種顏色。GLT_SHADER_IDENTITY // 參數2:著色器顏色shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vRed);// 4、容器類開始繪制squareBatch.Draw();// 5、召喚場景的時候,將4個固定矩形繪制好 // 使用單位著色器 // 參數1:簡單的使用默認笛卡爾坐標系(-1,1),所有片段都應用一種顏色。GLT_SHADER_IDENTITY // 參數2:著色器顏色shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vGreen);greenBatch.Draw();shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vRed1);redBatch.Draw();shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vBlue);blueBatch.Draw();shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vBlack);blackBatch.Draw();// 5、關閉混合glDisable(GL_BLEND);// 同步繪制命令glutSwapBuffers(); } void ChangeSize(int w, int h) {glViewport(0, 0, w, h); } int main(int argc, char * argv[]) {gltSetWorkingDirectory(argv[0]);glutInit(&argc, argv);glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);glutInitWindowSize(800, 600);glutCreateWindow("移動矩形,觀察外觀");GLenum err = glewInit();if (GLEW_OK != err){fprintf(stderr, "Error: %s\n", glewGetErrorString(err));return 1;}glutReshapeFunc(ChangeSize);glutDisplayFunc(RenderScene);glutSpecialFunc(SpecialKeys);SetupRC();glutMainLoop();return 0; }?
總結
以上是生活随笔為你收集整理的11、OpenGL - 混合(颜色混合)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 干货丨小米自研主动降噪技术在Redmi
- 下一篇: 游戏用户隐私协议《贪吃鱼进化》