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 vVaryingTexCoord2)函数
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,可以逐个像素地控制哪个片段进行绘制,哪个片段不会。
云雾的纹理图:
- OpenGL蓝宝书源码学习(二十)第六章——Dissolve
- OpenGL蓝宝书源码学习(十四)第六章——ShadedTriangle.cpp
- OpenGL蓝宝书源码学习(十五)第六章——FlatShader.cpp
- OpenGL蓝宝书源码学习(十六)第六章——GLSL语言内建函数
- OpenGL蓝宝书源码学习(十七)第六章——DiffuseLight.cpp
- OpenGL蓝宝书源码学习(十八)第六章——ADS光照模型
- OpenGL蓝宝书源码学习(十九)第六章——LitTexture.cpp
- OpenGL蓝宝书源码学习(二)第二章——Move.cpp
- OpenGL蓝宝书源码学习(二十一)第七章——SphereWorld矩阵纹理
- OpenGL蓝宝书源码学习(二十二)第七章——Cubemap立方体贴图
- OpenGL蓝宝书源码学习(二十三)第七章——MultiTexture多重纹理
- OpenGL蓝宝书源码学习(十三)第六章——OpenGL着色器和着色语言
- OpenGL蓝宝书源码学习(一)第二章——Triangle.cpp
- OpenGL蓝宝书源码学习(五)第三章——Blending.cpp
- OpenGL蓝宝书源码学习(三)第三章——GeoTest.cpp
- OpenGL蓝宝书源码学习(四)第三章——Scissor.cpp
- OpenGL蓝宝书源码学习(六)第三章——Smoother.cpp
- OpenGL蓝宝书源码学习(七)第四章——ModelViewProjection.cpp
- C++最全string与char *的转换
- Android中View绘制过程(一) decorView绘制
- 方法和数组
- Java的代码块
- Matlab code for Gauss-Seidel and Successive over relaxation iterative methods
- OpenGL蓝宝书源码学习(二十)第六章——Dissolve
- unlink之64位下有保护措施的利用
- csdn如何转载别人的博客
- 模仿百度API接口搜索框
- C++ Primer 练习 12.19
- Android Loader的机制以及源码分析
- ubuntu 16.04 安装ROS时的依赖问题的解决
- 题解——Leetcode 16. 3Sum Closest 难度:Medium
- 让TextView的drawableLeft与文本一起居中