OpenGL蓝宝书源码学习(二十)第六章——Dissolve

来源:互联网 发布:六轴机械手臂编程 编辑:程序博客网 时间:2024/06/05 12:40

侵蚀着色器渲染图元,呈现腐蚀效果的源码示例。

// Dissolve.cpp// OpenGL SuperBible// Demonstrates discard fragment command// Program by Richard S. Wright Jr.#include // OpenGL toolkit#include #include #include #include #include #include #ifdef __APPLE__#include #else#define FREEGLUT_STATIC#include #endifGLFrame             viewFrame;GLFrustum           viewFrustum;GLTriangleBatch     torusBatch;GLMatrixStack       modelViewMatrix;GLMatrixStack       projectionMatrix;GLGeometryTransform transformPipeline;GLShaderManager     shaderManager;GLuintADSDissloveShader;// The dissolving light shaderGLintlocAmbient;// The location of the ambient colorGLint   locDiffuse;// The location of the diffuse colorGLint   locSpecular;// The location of the specular colorGLintlocLight;// The location of the Light in eye coordinatesGLintlocMVP;// The location of the ModelViewProjection matrix uniformGLintlocMV;// The location of the ModelView matrix uniformGLintlocNM;// The location of the Normal matrix uniformGLintlocTexture;// The location of the  texture uniformGLint   locDissolveFactor;  // The location of the dissolve factorGLuintcloudTexture;// The cloud texture texture object// Load a TGA as a 2D Texture. Completely initialize the statebool LoadTGATexture(const char *szFileName, GLenum minFilter, GLenum magFilter, GLenum wrapMode){GLbyte *pBits;int nWidth, nHeight, nComponents;GLenum eFormat;// Read the texture bitspBits = gltReadTGABits(szFileName, &nWidth, &nHeight, &nComponents, &eFormat);if(pBits == NULL) return false;glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapMode);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapMode);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter);    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);glTexImage2D(GL_TEXTURE_2D, 0, nComponents, nWidth, nHeight, 0, eFormat, GL_UNSIGNED_BYTE, pBits);    free(pBits);        if(minFilter == GL_LINEAR_MIPMAP_LINEAR ||        minFilter == GL_LINEAR_MIPMAP_NEAREST ||       minFilter == GL_NEAREST_MIPMAP_LINEAR ||       minFilter == GL_NEAREST_MIPMAP_NEAREST)        glGenerateMipmap(GL_TEXTURE_2D);    return true;}// This function does any needed initialization on the rendering// context. void SetupRC(void){// BackgroundglClearColor(0.0f, 0.0f, 0.0f, 1.0f );glEnable(GL_DEPTH_TEST);    shaderManager.InitializeStockShaders();    viewFrame.MoveForward(4.0f);    // Make the torus    gltMakeTorus(torusBatch, .80f, 0.25f, 52, 26);ADSDissloveShader = gltLoadShaderPairWithAttributes("Dissolve.vp", "Dissolve.fp", 3, GLT_ATTRIBUTE_VERTEX, "vVertex",GLT_ATTRIBUTE_NORMAL, "vNormal", GLT_ATTRIBUTE_TEXTURE0, "vTexCoords0");locAmbient = glGetUniformLocation(ADSDissloveShader, "ambientColor");locDiffuse = glGetUniformLocation(ADSDissloveShader, "diffuseColor");locSpecular = glGetUniformLocation(ADSDissloveShader, "specularColor");locLight = glGetUniformLocation(ADSDissloveShader, "vLightPosition");locMVP = glGetUniformLocation(ADSDissloveShader, "mvpMatrix");locMV  = glGetUniformLocation(ADSDissloveShader, "mvMatrix");locNM  = glGetUniformLocation(ADSDissloveShader, "normalMatrix");locTexture = glGetUniformLocation(ADSDissloveShader, "cloudTexture");locDissolveFactor = glGetUniformLocation(ADSDissloveShader, "dissolveFactor");glGenTextures(1, &cloudTexture);glBindTexture(GL_TEXTURE_1D, cloudTexture);LoadTGATexture("Clouds.tga", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_CLAMP_TO_EDGE);}// Cleanupvoid ShutdownRC(void){}// Called to draw scenevoid RenderScene(void){static CStopWatch rotTimer;// Clear the window and the depth bufferglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);    modelViewMatrix.PushMatrix(viewFrame);modelViewMatrix.Rotate(rotTimer.GetElapsedSeconds() * 10.0f, 0.0f, 1.0f, 0.0f);GLfloat vEyeLight[] = { -100.0f, 100.0f, 100.0f };GLfloat vAmbientColor[] = { 0.1f, 0.1f, 0.1f, 1.0f };GLfloat vDiffuseColor[] = { 0.1f, 1.0f, 0.1f, 1.0f };GLfloat vSpecularColor[] = { 1.0f, 1.0f, 1.0f, 1.0f };glUseProgram(ADSDissloveShader);glUniform4fv(locAmbient, 1, vAmbientColor);glUniform4fv(locDiffuse, 1, vDiffuseColor);glUniform4fv(locSpecular, 1, vSpecularColor);glUniform3fv(locLight, 1, vEyeLight);glUniformMatrix4fv(locMVP, 1, GL_FALSE, transformPipeline.GetModelViewProjectionMatrix());glUniformMatrix4fv(locMV, 1, GL_FALSE, transformPipeline.GetModelViewMatrix());glUniformMatrix3fv(locNM, 1, GL_FALSE, transformPipeline.GetNormalMatrix());glUniform1i(locTexture, 1);float fFactor = fmod(rotTimer.GetElapsedSeconds(), 10.0f);fFactor /= 10.0f;glUniform1f(locDissolveFactor, fFactor);    torusBatch.Draw();    modelViewMatrix.PopMatrix();    glutSwapBuffers();glutPostRedisplay();}void ChangeSize(int w, int h){// Prevent a divide by zeroif(h == 0)h = 1;// Set Viewport to window dimensions    glViewport(0, 0, w, h);    viewFrustum.SetPerspective(35.0f, float(w)/float(h), 1.0f, 100.0f);        projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());    transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);}///////////////////////////////////////////////////////////////////////////////// Main entry point for GLUT based programsint main(int argc, char* argv[])    {gltSetWorkingDirectory(argv[0]);glutInit(&argc, argv);glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);glutInitWindowSize(800, 600);glutCreateWindow("Help me, I'm melting!");    glutReshapeFunc(ChangeSize);    glutDisplayFunc(RenderScene);GLenum err = glewInit();if (GLEW_OK != err) {fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));return 1;    }SetupRC();    glutMainLoop();ShutdownRC();return 0;    }// ADS Point lighting Shader// Vertex Shader// Richard S. Wright Jr.// OpenGL SuperBible#version 130// Incoming per vertex... position and normalin vec4 vVertex;in vec3 vNormal;in vec2 vTexCoords0;uniform mat4   mvpMatrix;uniform mat4   mvMatrix;uniform mat3   normalMatrix;uniform vec3   vLightPosition;// Color to fragment programsmooth out vec3 vVaryingNormal;smooth out vec3 vVaryingLightDir;smooth out vec2 vVaryingTexCoord;void main(void)     {    // Pass on the texture coordinates     vVaryingTexCoord = vTexCoords0;    // Get surface normal in eye coordinates    vVaryingNormal = normalMatrix * vNormal;    // Get vertex position in eye coordinates    vec4 vPosition4 = mvMatrix * vVertex;    vec3 vPosition3 = vPosition4.xyz / vPosition4.w;    // Get vector to light source    vVaryingLightDir = normalize(vLightPosition - vPosition3);    // Don't forget to transform the geometry!    gl_Position = mvpMatrix * vVertex;    }// ADS Point lighting Shader// Fragment Shader// Richard S. Wright Jr.// OpenGL SuperBible#version 130out vec4 vFragColor;uniform vec4       ambientColor;uniform vec4       diffuseColor;   uniform vec4       specularColor;uniform sampler2D  cloudTexture;uniform float      dissolveFactor;smooth in vec3 vVaryingNormal;smooth in vec3 vVaryingLightDir;smooth in vec2 vVaryingTexCoord;void main(void)    {     vec4 vCloudSample = texture(cloudTexture, vVaryingTexCoord);    if(vCloudSample.r < dissolveFactor)        discard;       // Dot product gives us diffuse intensity    float diff = max(0.0, dot(normalize(vVaryingNormal), normalize(vVaryingLightDir)));    // Multiply intensity by diffuse color, force alpha to 1.0    vFragColor = diff * diffuseColor;    // Add in ambient light    vFragColor += ambientColor;    // Specular Light    vec3 vReflection = normalize(reflect(-normalize(vVaryingLightDir), normalize(vVaryingNormal)));    float spec = max(0.0, dot(normalize(vVaryingNormal), vReflection));    if(diff != 0) {        float fSpec = pow(spec, 128.0);        vFragColor.rgb += vec3(fSpec, fSpec, fSpec);        }    }    



一、丢弃片段

片段着色器设有取消处理而不写入任何片段颜色(或者是深度、魔板等)值的选项。声明discard只会使片段程序停止运行,这个声明的一个常规用途就是执行alpha测试。普通的混合操作需要从颜色缓冲区进行一次读取、两次乘法(至少)、对颜色进行一次求和,然后将得到的值写回颜色缓冲区。如果alpha为0,或者非常接近0,那么片段实际上是不可见的。使用discard声明,我们可以逐个像素地控制哪个片段会进行绘制,哪个片段不会。

本次示例的目标是让对象(一个绿色花托)在10秒范围内“消散”。通过对云纹理进行采样,并将一个颜色分量与倒计时变量进行比较,当颜色值大于阈值时则完全丢弃片段。

二、源码解析

1、Client程序部分源码解析

1)变量

GLintlocTexture;// 返回获取到的片段着色器的采样器,代表采样的纹理所绑定的纹理单元。
GLint   locDissolveFactor;  // 返回获取到的片段着色器的腐蚀系数,与片段着色器对纹理进行采样的值进行比较,比较后丢弃片段

GLuintcloudTexture;// 返回获取到的纹理单元对象

注意:以上的声明的变量,都与着色器中统一值(uinform)相对应。

2)函数解析

1.void SetupRC(void)

...........

//加载着色器。设置顶点和片段着色器程序,和在顶点着色器中需要的3个属性,即顶点、法向量和纹理。

ADSDissloveShader = gltLoadShaderPairWithAttributes("Dissolve.vp", "Dissolve.fp", 3, GLT_ATTRIBUTE_VERTEX, "vVertex",
GLT_ATTRIBUTE_NORMAL, "vNormal", GLT_ATTRIBUTE_TEXTURE0, "vTexCoords0");

...............

//获取着色器中的cloudTexture统一值

locTexture = glGetUniformLocation(ADSDissloveShader, "cloudTexture");

//获取着色器中的dissolveFactor统一值
locDissolveFactor = glGetUniformLocation(ADSDissloveShader, "dissolveFactor");

//生成纹理单元

glGenTextures(1, &cloudTexture);

//绑定纹理单元
glBindTexture(GL_TEXTURE_1D, cloudTexture);

//选择载入纹理贴图。设置扩展和收缩的方式为线性,设置边缘环绕模式。
LoadTGATexture("Clouds.tga", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_CLAMP_TO_EDGE);


2.void RenderScene(void)

//定义一个使用时间的对象

static CStopWatch rotTimer;

...........

glUniform1i(locTexture, 0);  //设置着色器中的纹理单元统一值,使用默认标识符绑定的纹理单元。注意此示例只绑定一个纹理单元,第二参数任意整数

//fmod函数对浮点类型数据进行取模运算,即“参数1”%10。

float fFactor = fmod(rotTimer.GetElapsedSeconds(), 10.0f);
fFactor /= 10.0f;
glUniform1f(locDissolveFactor, fFactor); //设置着色器中的侵蚀系数
    torusBatch.Draw();    //渲染图元

.................

2、Server程序源码解析

Dissolve.vp

1)变量

//三个输入属性,顶点位置、法线和纹理坐标。

in vec4 vVertex;       
in vec3 vNormal;
in vec2 vTexCoords0;

//统一值的声明,模型视图投影矩阵、模型视图矩阵、法向量矩阵和光源位置坐标

uniform mat4   mvpMatrix;
uniform mat4   mvMatrix;
uniform mat3   normalMatrix;
uniform vec3   vLightPosition;

//输出给片段着色器的属性值

smooth out vec3 vVaryingNormal; //视坐标的各个顶点的法向量
smooth out vec3 vVaryingLightDir;//光源的方向
smooth out vec2 vVaryingTexCoord;//纹理坐标

2)函数

void main(void) 

//用顶点着色器的纹理坐标设置得到纹理坐标

vVaryingTexCoord = vTexCoords0;

//用法向量矩阵乘以法线(输入属性)得到视坐标的各个顶点的法向量

vVaryingNormal = normalMatrix * vNormal;

//得到视坐标系中顶点的位置坐标。用模型视图矩阵乘以顶点坐标再除以w分量。

vec4 vPosition4 = mvMatrix * vVertex;
    vec3 vPosition3 = vPosition4.xyz / vPosition4.w;

//得到的光源的方向向量。用光源的位置坐标减去顶点的坐标,在进行归一化。

vVaryingLightDir = normalize(vLightPosition - vPosition3);

//几何渲染设置

gl_Position = mvpMatrix * vVertex;

Dissolve.fp

1)变量

out vec4 vFragColor; //将要光栅化的颜色输出

uniform vec4       ambientColor; //环境光颜色统一值
uniform vec4       diffuseColor;   //漫射光颜色统一值
uniform vec4       specularColor;//镜面光颜色统一值
uniform sampler2D  cloudTexture; //采样器统一值
uniform float      dissolveFactor; //腐蚀系数统一值

//三个输入属性。从顶点着色器传递过来

smooth in vec3 vVaryingNormal;
smooth in vec3 vVaryingLightDir;
smooth in vec2 vVaryingTexCoord

2)函数

void main(void)

//使用纹理坐标(参数2)对纹理单元进行采样(参数1)得到颜色值(返回值)

vec4 vCloudSample = texture(cloudTexture, vVaryingTexCoord);

//判断如果纹理的alpha值小鱼腐蚀系数,则丢弃片段。

if(vCloudSample.r < dissolveFactor)
        discard;

//求光源照射在图元上的漫射光强度。法向量和光源方向向量的点乘积与0.0的最大值

float diff = max(0.0, dot(normalize(vVaryingNormal), normalize(vVaryingLightDir)));

//片段着色器输出颜色值为漫射光强度乘以漫射光颜色(漫射光颜色在RenderScene函数进行设置)

vFragColor = diff * diffuseColor;

//片段着色器输出颜色值加等环境光颜色值

vFragColor += ambientColor;

//先求反射光向量,根据射向光源方向的向量为入射向量和法向量求反射向量。再根据光源方向向量和反射向量的点乘积求镜面光强度,判断如果漫射光强度不是0,再进行128次幂。最后着色器输出颜色值加等镜面光强度颜色。

vec3 vReflection = normalize(reflect(-normalize(vVaryingLightDir), normalize(vVaryingNormal)));
    float spec = max(0.0, dot(normalize(vVaryingNormal), vReflection)); 
    if(diff != 0) {
        float fSpec = pow(spec, 128.0);
        vFragColor.rgb += vec3(fSpec, fSpec, fSpec);
        }
    }

三、小结

此示例通过一个寝室的效果,简单学习了一下着色器中的丢弃片段的应用。通过加载一个云雾的纹理贴图获取其alpha值,在Client程序中设置一个腐蚀系数与纹理贴图的alpha值进行比较,当alpha的值小于腐蚀系数时,完全丢弃片段(discard)。腐蚀系数是在Client程序中随系统时间进行设置的,所以在着色器的丢弃片段时,采样得到的纹理颜色的alpha值与变化的腐蚀系数进行比较,逐个像素地控制绘制效果,会出现图形被侵蚀的效果。声明discard,可以逐个像素地控制哪个片段进行绘制,哪个片段不会。

云雾的纹理图:




阅读全文
0 0