在上一篇OpenGL 没有纹理的星系试、OpenGL 金字塔基础上修改main.cpp
文件,完成添加纹理的星系。bash
#include "GLMatrixStack.h"
#include "GLFrame.h"
#include "GLFrustum.h"
#include "GLBatch.h"
#include "GLGeometryTransform.h"
#include <math.h>
#include <GLUT/GLUT.h>
#include "GLTools.h"
#include "StopWatch.h"
#include <stdio.h>
GLShaderManager shaderManager;
GLMatrixStack modelViewMatrix;
GLMatrixStack projectionMatrix;
//视景体
GLFrustum viewFrustum;
GLGeometryTransform transformPipeline;
GLFrame cameraFrame;
GLTriangleBatch sunBatch;
GLTriangleBatch earthBatch;
GLTriangleBatch otherStarsBatch;
GLBatch theMilkyWayBatch;
//纹理标记ID
GLuint uiTextures[3];
#define NUMBER_STARS 100
GLFrame stars[NUMBER_STARS];
static GLfloat vTheMilkyWayColor[] = {0.96f,0.92f,0.23f,0.6f};
//将TGA文件加载为2D纹理
bool loadTGATexture(const char *szFileName, GLenum minFilter, GLenum magFileter, GLenum wrapMode) {
GLbyte *pBits;
int nWidth, nHeight, nComponents;
GLenum eFormat;
//读取纹理 pBits:指向图像数据的指针 arg2:纹理文件宽度地址 arg4:文件组件地址 arg5:文件格式地址
pBits = gltReadTGABits(szFileName, &nWidth, &nHeight, &nComponents, &eFormat);
if (pBits == NULL) {
return false;
}
//设置过滤方式
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFileter);
//设置环绕模式
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapMode);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapMode);
//载入纹理 arg2:mip贴图层次 arg7:像素数据类型(GL_UNSIGNED_BYTE 每一个颜色份量都是一个8位无符号整型)
glTexImage2D(GL_TEXTURE_2D, 0, nComponents, nWidth, nHeight, 0, eFormat, GL_UNSIGNED_BYTE, pBits);
//释放ppBits
free(pBits);
//只有minFilter 等于如下四种模式,才能够生成Mip贴图
//GL_NEAREST_MIPMAP_NEAREST具备很是好的性能,而且闪烁现象很是弱
//GL_LINEAR_MIPMAP_NEAREST经常用于对游戏进行加速,它使用了高质量的线性过滤器
//GL_LINEAR_MIPMAP_LINEAR 和GL_NEAREST_MIPMAP_LINEAR 过滤器在Mip层之间执行了一些额外的插值,以消除他们之间的过滤痕迹。
//GL_LINEAR_MIPMAP_LINEAR 三线性Mip贴图。纹理过滤的黄金准则,具备最高的精度。
if(minFilter == GL_LINEAR_MIPMAP_LINEAR ||
minFilter == GL_LINEAR_MIPMAP_NEAREST ||
minFilter == GL_NEAREST_MIPMAP_LINEAR ||
minFilter == GL_NEAREST_MIPMAP_NEAREST)
//加载Mip
glGenerateMipmap(GL_TEXTURE_2D);
return true;
}
void setupRC() {
glClearColor(0.27f, 0.24f, 0.34f, 1.0f);
shaderManager.InitializeStockShaders();
cameraFrame.MoveForward(10.0f);
glEnable(GL_DEPTH_TEST);
//开启正背面剔除,倒影时效果
glEnable(GL_CULL_FACE);
//星带
GLfloat texSize = 20.0f;
theMilkyWayBatch.Begin(GL_TRIANGLE_FAN, 4,1);
theMilkyWayBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
theMilkyWayBatch.Vertex3f(-30.0f,-0.5f,30.0f);
theMilkyWayBatch.MultiTexCoord2f(0, texSize, 0.0f);
theMilkyWayBatch.Vertex3f(30.0f, -0.5f, 30.0f);
theMilkyWayBatch.MultiTexCoord2f(0, texSize, texSize);
theMilkyWayBatch.Vertex3f(30.0f, -0.5f, -30.0f);
theMilkyWayBatch.MultiTexCoord2f(0, 0.0f, texSize);
theMilkyWayBatch.Vertex3f(-30.0f, -0.5f, -30.0f);
theMilkyWayBatch.End();
//太阳
gltMakeSphere(sunBatch, 0.4f, 50, 100);
//地球
gltMakeSphere(earthBatch, 0.1f, 50, 100);
//其余星体位置
gltMakeSphere(otherStarsBatch, 0.1f, 50, 100);
for (int i = 0; i < NUMBER_STARS; i++) {
GLfloat x = ((GLfloat)(rand() % 500 -200)) * 0.12f;
GLfloat z = ((GLfloat)(rand() % 500 -200)) * 0.12f;
stars[i].SetOrigin(x, 0.0f, z);
}
//命名纹理对象
glGenTextures(3, uiTextures);
glBindTexture(GL_TEXTURE_2D, uiTextures[0]);
loadTGATexture("milkey.tga", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_REPEAT);
glBindTexture(GL_TEXTURE_2D, uiTextures[1]);
loadTGATexture("sun.tga", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_REPEAT);
glBindTexture(GL_TEXTURE_2D, uiTextures[2]);
loadTGATexture("earth.tga", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_REPEAT);
}
void drawUniverse(GLfloat yRot) {
//漫反射颜色
static GLfloat vWhite[] = { 1.0f, 1.0f, 1.0f, 1.0f};
static M3DMatrix44f vLightPos = {0.0f,20.0f,10.0f,1.0f};
modelViewMatrix.Translate(0.0f, 0.0f, -5.0f);
modelViewMatrix.PushMatrix();
modelViewMatrix.Rotate(yRot, 0.0f, 1.0f, 0.0f);
glBindTexture(GL_TEXTURE_2D, uiTextures[1]);
shaderManager.UseStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF,
transformPipeline.GetModelViewMatrix(),
transformPipeline.GetProjectionMatrix(),
vLightPos,
vWhite,
0);
sunBatch.Draw();
modelViewMatrix.PopMatrix();
//绘制地球
modelViewMatrix.PushMatrix();
//要先旋转后平移,矩阵乘法不遵循交换律要将旋转后的矩阵平移
modelViewMatrix.Rotate(yRot * -2.0f, 0.0f, 1.0f, 0.0f);
modelViewMatrix.Translate(0.7f, 0.0f, 0.0f);
glBindTexture(GL_TEXTURE_2D, uiTextures[2]);
shaderManager.UseStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF,
transformPipeline.GetModelViewMatrix(),
transformPipeline.GetProjectionMatrix(),
vLightPos,
vWhite,
0);
earthBatch.Draw();
modelViewMatrix.PopMatrix();
//其余星体
glBindTexture(GL_TEXTURE_2D, uiTextures[1]);
for (int i = 0; i < NUMBER_STARS; i++) {
modelViewMatrix.PushMatrix();
modelViewMatrix.MultMatrix(stars[i]);
shaderManager.UseStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF,
transformPipeline.GetModelViewMatrix(),
transformPipeline.GetProjectionMatrix(),
vLightPos,
vWhite,
0);
otherStarsBatch.Draw();
modelViewMatrix.PopMatrix();
}
}
void changeSize(int w, int h) {
glViewport(0, 0, w, h);
//设置透视投影
viewFrustum.SetPerspective(25.0f, float(w) / float(h), 2.0f, 400.0f);
projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
}
void renderScene() {
//清理缓冲区
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
static CStopWatch rotTimer;
float yRot = rotTimer.GetElapsedSeconds() * 60.0f;
//照相机矩阵
modelViewMatrix.PushMatrix(cameraFrame);
//倒影
modelViewMatrix.PushMatrix();
modelViewMatrix.Scale(1.0f, -1.0f, 1.0f);
modelViewMatrix.Translate(0.0f, 1.0f, 0.0f);
//设定顺时针为正面
glFrontFace(GL_CW);
drawUniverse(yRot);
//回复逆时针为正面
glFrontFace(GL_CCW);
modelViewMatrix.PopMatrix();
//theMilky
glEnable(GL_BLEND);
//颜色混合方程
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBindTexture(GL_TEXTURE_2D, uiTextures[0]);
/**纹理调整着色器(将一个基本色乘以一个取自纹理的单元nTextureUnit的纹理)
arg1:GLT_SHADER_TEXTURE_MODULATE
arg2:模型视图投影矩阵
arg3:颜色
arg4:纹理单元(第0层的纹理单元)
*/
shaderManager.UseStockShader(GLT_SHADER_TEXTURE_MODULATE,
transformPipeline.GetModelViewProjectionMatrix(),
vTheMilkyWayColor,
0);
theMilkyWayBatch.Draw();
glDisable(GL_BLEND);
drawUniverse(yRot);
modelViewMatrix.PopMatrix();
glutSwapBuffers();
glutPostRedisplay();
}
void specialKeys(int key,int x,int y){
float step = 0.4f;
float angular = float(m3dDegToRad(2.0f));
if (key == GLUT_KEY_UP) {
cameraFrame.MoveForward(-step);
}
if (key == GLUT_KEY_DOWN) {
cameraFrame.MoveForward(step);
}
if (key == GLUT_KEY_LEFT) {
cameraFrame.RotateWorld(angular, 0.0f, 1.0f, 0.0f);
}
if (key == GLUT_KEY_RIGHT) {
cameraFrame.RotateWorld(-angular, 0.0f, 1.0f, 0.0f);
}
}
void shutdownRC(void)
{
glDeleteTextures(3, uiTextures);
}
int main(int argc, char* argv[]) {
gltSetWorkingDirectory(argv[0]);
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
glutInitWindowSize(375, 750);
glutCreateWindow("dowZhang");
glutReshapeFunc(changeSize);
glutDisplayFunc(renderScene);
glutSpecialFunc(specialKeys);
GLenum err = glewInit();
if (GLEW_OK != err) {
return 1;
}
setupRC();
glutMainLoop();
shutdownRC();
return 0;
}
复制代码
当启用混合功能时,参考以下方程:oop
Cf = (Cs * S) + (Cd * D)
Cf: 最终计算结果颜色
Cs: 源颜色
Cd: 目标颜色
S: 源混合因子
D:目标混合因子
复制代码
设置混合因子方程:post
glBlendFunc(GLenum S,GLenum D)
复制代码
混合因子参考表: 性能