OpenGL蓝宝书源码学习(十九)第六章——LitTexture.cpp

访问纹理加载到着色器渲染小球图元,并使用光照模型照亮图形的源码示例。

// LitTexture.cpp
// OpenGL SuperBible
// Demonstrates combining lighting and texture
// Program by Richard S. Wright Jr.

#include 
   
   
    
    	// OpenGL toolkit
#include 
    
    
     
     
#include 
     
     
      
      
#include 
      
      
       
       
#include 
       
       
         #include 
        
          #include 
         
           #ifdef __APPLE__ #include 
          
            #else #define FREEGLUT_STATIC #include 
           
             #endif GLFrame viewFrame; GLFrustum viewFrustum; GLTriangleBatch sphereBatch; GLMatrixStack modelViewMatrix; GLMatrixStack projectionMatrix; GLGeometryTransform transformPipeline; GLShaderManager shaderManager; GLuint ADSTextureShader; // The textured diffuse light shader GLint locAmbient; // The location of the ambient color GLint locDiffuse; // The location of the diffuse color GLint locSpecular; // The location of the specular color GLint locLight; // The location of the Light in eye coordinates GLint locMVP; // The location of the ModelViewProjection matrix uniform GLint locMV; // The location of the ModelView matrix uniform GLint locNM; // The location of the Normal matrix uniform GLint locTexture; GLuint texture; // Load a TGA as a 2D Texture. Completely initialize the state bool LoadTGATexture(const char *szFileName, GLenum minFilter, GLenum magFilter, GLenum wrapMode) { GLbyte *pBits; int nWidth, nHeight, nComponents; GLenum eFormat; // Read the texture bits pBits = 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) { // Background glClearColor(0.0f, 0.0f, 0.0f, 1.0f ); glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); shaderManager.InitializeStockShaders(); viewFrame.MoveForward(4.0f); // Make the sphere gltMakeSphere(sphereBatch, 1.0f, 26, 13); ADSTextureShader = gltLoadShaderPairWithAttributes("ADSTexture.vp", "ADSTexture.fp", 3, GLT_ATTRIBUTE_VERTEX, "vVertex", GLT_ATTRIBUTE_NORMAL, "vNormal", GLT_ATTRIBUTE_TEXTURE0, "vTexture0"); locAmbient = glGetUniformLocation(ADSTextureShader, "ambientColor"); locDiffuse = glGetUniformLocation(ADSTextureShader, "diffuseColor"); locSpecular = glGetUniformLocation(ADSTextureShader, "specularColor"); locLight = glGetUniformLocation(ADSTextureShader, "vLightPosition"); locMVP = glGetUniformLocation(ADSTextureShader, "mvpMatrix"); locMV = glGetUniformLocation(ADSTextureShader, "mvMatrix"); locNM = glGetUniformLocation(ADSTextureShader, "normalMatrix"); locTexture = glGetUniformLocation(ADSTextureShader, "colorMap"); glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); LoadTGATexture("CoolTexture.tga", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_CLAMP_TO_EDGE); } // Cleanup void ShutdownRC(void) { glDeleteTextures(1, &texture); } // Called to draw scene void RenderScene(void) { static CStopWatch rotTimer; // Clear the window and the depth buffer glClear(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.2f, 0.2f, 0.2f, 1.0f }; GLfloat vDiffuseColor[] = { 1.0f, 1.0f, 1.0f, 1.0f}; GLfloat vSpecularColor[] = { 1.0f, 1.0f, 1.0f, 1.0f }; glBindTexture(GL_TEXTURE_2D, texture); glUseProgram(ADSTextureShader); 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, 0); sphereBatch.Draw(); modelViewMatrix.PopMatrix(); glutSwapBuffers(); glutPostRedisplay(); } void ChangeSize(int w, int h) { // Prevent a divide by zero if(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 programs int main(int argc, char* argv[]) { gltSetWorkingDirectory(argv[0]); glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL); glutInitWindowSize(800, 600); glutCreateWindow("Lit Texture"); 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 normal in vec4 vVertex; in vec3 vNormal; in vec4 vTexture0; uniform mat4 mvpMatrix; uniform mat4 mvMatrix; uniform mat3 normalMatrix; uniform vec3 vLightPosition; // Color to fragment program smooth out vec3 vVaryingNormal; smooth out vec3 vVaryingLightDir; smooth out vec2 vTexCoords; void main(void) { // 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); // Pass along the texture coordinates vTexCoords = vTexture0.st; // Don't forget to transform the geometry! gl_Position = mvpMatrix * vVertex; } // ADS Point lighting Shader // Fragment Shader // Richard S. Wright Jr. // OpenGL SuperBible #version 130 out vec4 vFragColor; uniform vec4 ambientColor; uniform vec4 diffuseColor; uniform vec4 specularColor; uniform sampler2D colorMap; smooth in vec3 vVaryingNormal; smooth in vec3 vVaryingLightDir; smooth in vec2 vTexCoords; void main(void) { // 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; // Modulate in the texture vFragColor *= texture(colorMap, vTexCoords); // 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); } } 
            
           
          
         
       
      
      
     
     
    
    
   
   

示例是在ADSPhong着色器中添加了一个纹理,再渲染到图元上。

一、基础知识

纹理坐标将作为属性传递到顶点着色器。在片段着色器中,这些属性通常是在顶点之间进行平滑插值的。片段着色器使用这些插值纹理坐标来对纹理进行采样(sample)。当前绑定的纹理对象已经针对Mip贴图/非Mip贴图、过滤模式和环绕模式等进行了设置。经过采样和过滤的纹理颜色将作为RGBA颜色值返回,可以直接将他写入片段,或者也可以与其他颜色计算相结合。

二、源码解析

1、Client部分源码解析

注:这里解析的是新的源码。

GLint   locTexture;  //返回片段着色器中的采样器
GLuint  texture; //纹理标识(ID)

1)void SetupRC(void)

//加载着色器程序。参数3:在顶点着色器中有3个属性值,即后面的带引号的参数,顶点、法线和纹理贴图

ADSTextureShader = gltLoadShaderPairWithAttributes("ADSTexture.vp", "ADSTexture.fp", 3, GLT_ATTRIBUTE_VERTEX, "vVertex",
GLT_ATTRIBUTE_NORMAL, "vNormal", GLT_ATTRIBUTE_TEXTURE0, "vTexture0");

........

locTexture = glGetUniformLocation(ADSTextureShader, "colorMap"); //获取着色器的colorMap统一值

glGenTextures(1, &texture);          //生成纹理,指定纹理对象的数量和纹理对象
glBindTexture(GL_TEXTURE_2D, texture);  //绑定纹理,2D
LoadTGATexture("CoolTexture.tga", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_CLAMP_TO_EDGE); //载入纹理贴图

2)void ShutdownRC(void)

glDeleteTextures(1, &texture);   //删除纹理

3)void RenderScene(void)

....

glBindTexture(GL_TEXTURE_2D, texture);  //绑定纹理

glUseProgram(ADSTextureShader); //使用着色器

.......

glUniform1i(locTexture, 0);//设置着色器中纹理统一值,使用标识符为0的纹理单元,由于绑定是默认纹理单元0。

2、Server源码解析

ADSTexture.vp

1)变量

//三个输入属性,顶点位置、法线和纹理坐标属性。这三个输入属性在Client的SetupRC的gltMakeSphere函数中分配了内存。

in vec4 vVertex;
in vec3 vNormal;
in vec4 vTexture0;

//统一值声明,在Client的程序可以获取并设置值。

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

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

smooth out vec3 vVaryingNormal;   //视坐标系的个顶点法线坐标
smooth out vec3 vVaryingLightDir; //光源的方向向量
smooth out vec2 vTexCoords;    //要传递的纹理坐标(2分量的向量)

2)void main(void) 

//用法线矩阵乘以法线坐标得到视坐标的法向量。normalMatrix在Client程序管线管理中获取设置,vNormal是在gltMakeSphere设置图元坐标时设置。

 vVaryingNormal = normalMatrix * vNormal;

//得到视坐标中顶点的位置坐标。用模型视图矩阵乘以顶点坐标向量再除以w分量。mvMatrix在Client程序管线管理中获取设置,vNormal是在gltMakeSphere设置图元坐标时设置。

vec4 vPosition4 = mvMatrix * vVertex;

vec3 vPosition3 = vPosition4.xyz / vPosition4.w;

//得到光源向量。用光源的位置坐标向量减去各个顶点的位置坐标。

vVaryingLightDir = normalize(vLightPosition - vPosition3);

//传递纹理坐标的s和t分量给输出属性值,输出给片段着色器

vTexCoords = vTexture0.st;

//设置渲染的顶点位置(即图元)。用模型视图矩阵乘以图元的顶点坐标。

gl_Position = mvpMatrix * vVertex;


ADSTexture.fp

1)变量

//将要进行光栅化的输出颜色值

out vec4 vFragColor; 

//声明统一值。1.环境光颜色值。2.漫射光颜色值。3.镜面光颜色值。4.采样器:代表将要采样的纹理所绑定的纹理单元。此示例默认绑定的是纹理单元0。

uniform vec4      ambientColor;
uniform vec4      diffuseColor;   
uniform vec4      specularColor;
uniform sampler2D colorMap;

//从顶点着色器输入过来的属性值。1.法向量。2.光源方向向量。3.纹理坐标。

smooth in vec3 vVaryingNormal;
smooth in vec3 vVaryingLightDir;
smooth in vec2 vTexCoords;

2)void main(void)

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

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

//输出颜色值赋值为漫射光强度乘以漫射光颜色值

vFragColor = diff * diffuseColor;

//输出颜色加等于环境光颜色值

vFragColor += ambientColor;

//输出颜色乘等于(使用纹理坐标采样纹理单元得到的颜色值)

vFragColor *= texture(colorMap, vTexCoords);

//求镜面光的颜色,输出颜色加等镜面光颜色值。

//把朝向光源坐标作为入射向量,即-normalize(vVaryingLightDir)。再求入射向量的反射向量

    vec3 vReflection = normalize(reflect(-normalize(vVaryingLightDir), normalize(vVaryingNormal)));

//镜面光强为法向量和反射向量的点乘积,当diff漫射光强度不为0时,进行128次幂得到。
    float spec = max(0.0, dot(normalize(vVaryingNormal), vReflection));

    if(diff != 0) {
        float fSpec = pow(spec, 128.0);
        vFragColor.rgb += vec3(fSpec, fSpec, fSpec);
//输出颜色加等精光光强颜色值
        }
    }

三、小结

此示例使用加载着色器程序,访问纹理贴图,结合ADSPhong光照模型,进行对小球图元的渲染。下个示例学习,丢弃片段--图元腐蚀渲染效果。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值