球體世界效果圖
球體世界
代碼實(shí)現(xiàn)
#include "GLTools.h"
#include "GLShaderManager.h"
#include "GLFrustum.h"
#include "GLBatch.h"
#include "GLMatrixStack.h"
#include "GLGeometryTransform.h"
#include "StopWatch.h"
#include <math.h>
#include <stdio.h>
#ifdef __APPLE__
#include <glut/glut.h>
#else
#define FREEGLUT_STATIC
#include <GL/glut.h>
#endif
//1味榛、添加附加隨機(jī)球
#define NUM_SPHERES 50
GLFrame spheres[NUM_SPHERES];
GLShaderManager shaderManager; // 著色器管理器
GLMatrixStack modelViewMatrix; // 模型視圖矩陣
GLMatrixStack projectionMatrix; // 投影矩陣
GLFrustum viewFrustum; // 視景體
GLGeometryTransform transformPipeline; // 幾何圖形變換管道
GLTriangleBatch torusBatch; // 花托批處理
GLBatch floorBatch; // 地板批處理
//2八千、定義公轉(zhuǎn)球的批處理(公轉(zhuǎn)自轉(zhuǎn))
GLTriangleBatch sphereBatch; //球批處理
//3忘分、角色幀 照相機(jī)角色幀(全局照相機(jī)實(shí)例)
GLFrame cameraFrame;
//5缸剪、添加紋理
//紋理標(biāo)記數(shù)組
GLuint uiTextures[3];
bool LoadTGATexture(const char *szFileName, GLenum minFilter, GLenum magFilter, GLenum wrapMode)
{
GLbyte *pBits;
int nWidth, nHeight, nComponents;
GLenum eFormat;
//1.讀取紋理數(shù)據(jù)
pBits = gltReadTGABits(szFileName, &nWidth, &nHeight, &nComponents, &eFormat);
if(pBits == NULL)
return false;
//2策添、設(shè)置紋理參數(shù)
//參數(shù)1:紋理維度
//參數(shù)2:為S/T坐標(biāo)設(shè)置模式
//參數(shù)3:wrapMode,環(huán)繞模式
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapMode);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapMode);
//參數(shù)1:紋理維度
//參數(shù)2:線性過(guò)濾
//參數(shù)3:wrapMode,環(huán)繞模式
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter);
//3.載入紋理
//參數(shù)1:紋理維度
//參數(shù)2:mip貼圖層次
//參數(shù)3:紋理單元存儲(chǔ)的顏色成分(從讀取像素圖是獲得)-將內(nèi)部參數(shù)nComponents改為了通用壓縮紋理格式GL_COMPRESSED_RGB
//參數(shù)4:加載紋理寬
//參數(shù)5:加載紋理高
//參數(shù)6:加載紋理的深度
//參數(shù)7:像素?cái)?shù)據(jù)的數(shù)據(jù)類型(GL_UNSIGNED_BYTE材部,每個(gè)顏色分量都是一個(gè)8位無(wú)符號(hào)整數(shù))
//參數(shù)8:指向紋理圖像數(shù)據(jù)的指針
glTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB, nWidth, nHeight, 0,
eFormat, GL_UNSIGNED_BYTE, pBits);
//使用完畢釋放pBits
free(pBits);
//只有minFilter 等于以下四種模式,才可以生成Mip貼圖
//GL_NEAREST_MIPMAP_NEAREST具有非常好的性能唯竹,并且閃爍現(xiàn)象非常弱
//GL_LINEAR_MIPMAP_NEAREST常常用于對(duì)游戲進(jìn)行加速乐导,它使用了高質(zhì)量的線性過(guò)濾器
//GL_LINEAR_MIPMAP_LINEAR 和GL_NEAREST_MIPMAP_LINEAR 過(guò)濾器在Mip層之間執(zhí)行了一些額外的插值,以消除他們之間的過(guò)濾痕跡摩窃。
//GL_LINEAR_MIPMAP_LINEAR 三線性Mip貼圖兽叮。紋理過(guò)濾的黃金準(zhǔn)則芬骄,具有最高的精度。
if(minFilter == GL_LINEAR_MIPMAP_LINEAR ||
minFilter == GL_LINEAR_MIPMAP_NEAREST ||
minFilter == GL_NEAREST_MIPMAP_LINEAR ||
minFilter == GL_NEAREST_MIPMAP_NEAREST)
//4.加載Mip,紋理生成所有的Mip層
//參數(shù):GL_TEXTURE_1D鹦聪、GL_TEXTURE_2D账阻、GL_TEXTURE_3D
glGenerateMipmap(GL_TEXTURE_2D);
return true;
}
void SetupRC()
{
//1.
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
shaderManager.InitializeStockShaders();
transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
//2.開啟深度測(cè)試/背面剔除
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
//3.設(shè)置大球
gltMakeSphere(torusBatch, 0.4f, 40, 80);
//4.設(shè)置小球(公轉(zhuǎn)自轉(zhuǎn))
gltMakeSphere(sphereBatch, 0.1f, 26, 13);
//5.設(shè)置地板頂點(diǎn)數(shù)據(jù)&地板紋理
GLfloat texSize = 10.0f;
floorBatch.Begin(GL_TRIANGLE_FAN, 4, 1);
floorBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
floorBatch.Vertex3f(-20.f, -0.41f, 20.0f);
floorBatch.MultiTexCoord2f(0, texSize, 0.0f);
floorBatch.Vertex3f(20.0f, -0.41f, 20.f);
floorBatch.MultiTexCoord2f(0, texSize, texSize);
floorBatch.Vertex3f(20.0f, -0.41f, -20.0f);
floorBatch.MultiTexCoord2f(0, 0.0f, texSize);
floorBatch.Vertex3f(-20.0f, -0.41f, -20.0f);
floorBatch.End();
//6.隨機(jī)小球頂點(diǎn)坐標(biāo)數(shù)據(jù)
for (int i = 0; i < NUM_SPHERES; i++) {
//y軸不變,X,Z產(chǎn)生隨機(jī)值
GLfloat x = ((GLfloat)((rand() % 400) - 200 ) * 0.1f);
GLfloat z = ((GLfloat)((rand() % 400) - 200 ) * 0.1f);
//在y方向泽本,將球體設(shè)置為0.0的位置淘太,這使得它們看起來(lái)是飄浮在眼睛的高度
//對(duì)spheres數(shù)組中的每一個(gè)頂點(diǎn),設(shè)置頂點(diǎn)數(shù)據(jù)
spheres[i].SetOrigin(x, 0.0f, z);
}
//7.創(chuàng)建3個(gè)紋理對(duì)象
glGenTextures(3, uiTextures);
//8.將TGA文件加載為2D紋理规丽。
//參數(shù)1:紋理文件名稱
//參數(shù)2&參數(shù)3:需要縮小&放大的過(guò)濾器
//參數(shù)4:紋理坐標(biāo)環(huán)繞模式
glBindTexture(GL_TEXTURE_2D, uiTextures[0]);
LoadTGATexture("marble.tga", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_REPEAT);
glBindTexture(GL_TEXTURE_2D, uiTextures[1]);
LoadTGATexture("marslike.tga", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_CLAMP_TO_EDGE);
glBindTexture(GL_TEXTURE_2D, uiTextures[2]);
LoadTGATexture("moonlike.tga", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_CLAMP_TO_EDGE);
}
//刪除紋理
void ShutdownRC()
{
glDeleteTextures(3, uiTextures);
}
// 屏幕更改大小或已初始化
void ChangeSize(int nWidth, int nHeight)
{
//1.設(shè)置視口
glViewport(0, 0, nWidth, nHeight);
//2.設(shè)置投影方式
viewFrustum.SetPerspective(35.0f, float(nWidth)/float(nHeight), 1.0f, 100.0f);
//3.將投影矩陣加載到投影矩陣堆棧,
projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
modelViewMatrix.LoadIdentity();
}
void drawSomething(GLfloat yRot)
{
//1.定義光源位置&漫反射顏色
static GLfloat vWhite[] = { 1.0f, 1.0f, 1.0f, 1.0f };
static GLfloat vLightPos[] = { 0.0f, 3.0f, 0.0f, 1.0f };
//2.繪制懸浮小球
glBindTexture(GL_TEXTURE_2D, uiTextures[2]);
for(int i = 0; i < NUM_SPHERES; i++) {
modelViewMatrix.PushMatrix();
modelViewMatrix.MultMatrix(spheres[i]);
shaderManager.UseStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF,
modelViewMatrix.GetMatrix(),
transformPipeline.GetProjectionMatrix(),
vLightPos,
vWhite,
0);
sphereBatch.Draw();
modelViewMatrix.PopMatrix();
}
//3.繪制大球
modelViewMatrix.Translate(0.0f, 0.2f, -2.5f);
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,
modelViewMatrix.GetMatrix(),
transformPipeline.GetProjectionMatrix(),
vLightPos,
vWhite,
0);
torusBatch.Draw();
modelViewMatrix.PopMatrix();
//4.繪制公轉(zhuǎn)小球(公轉(zhuǎn)自轉(zhuǎn))
modelViewMatrix.PushMatrix();
modelViewMatrix.Rotate(yRot * -2.0f, 0.0f, 1.0f, 0.0f);
modelViewMatrix.Translate(0.8f, 0.0f, 0.0f);
glBindTexture(GL_TEXTURE_2D, uiTextures[2]);
shaderManager.UseStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF,
modelViewMatrix.GetMatrix(),
transformPipeline.GetProjectionMatrix(),
vLightPos,
vWhite,
0);
sphereBatch.Draw();
modelViewMatrix.PopMatrix();
}
//進(jìn)行調(diào)用以繪制場(chǎng)景
void RenderScene()
{
//1.地板顏色值蒲牧,注意alpha值,用于混合
static GLfloat vFloorColor[] = { 40.0/255.0, 150.0/255.0, 200.0/255.0, 0.75f};
//2.基于時(shí)間動(dòng)畫
static CStopWatch rotTimer;
float yRot = rotTimer.GetElapsedSeconds() * 60.0f;
//3.清除顏色緩存區(qū)和深度緩沖區(qū)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//4.壓入棧(棧頂)
modelViewMatrix.PushMatrix();
//5.設(shè)置觀察者矩陣
M3DMatrix44f mCamera;
cameraFrame.GetCameraMatrix(mCamera);
modelViewMatrix.MultMatrix(mCamera);
//6.壓棧(鏡面)
modelViewMatrix.PushMatrix();
//7.---添加反光效果---
//翻轉(zhuǎn)Y軸
modelViewMatrix.Scale(1.0f, -1.0f, 1.0f);
//鏡面世界圍繞Y軸平移一定間距赌莺,因?yàn)殓R面了冰抢,所以是向下移動(dòng)0.8
modelViewMatrix.Translate(0.0f, 0.8f, 0.0f);
// 鏡面后,原來(lái)逆時(shí)針為正面艘狭,現(xiàn)在順時(shí)針為正面
//8.指定順時(shí)針為正面
glFrontFace(GL_CW);
//9.繪制地面以外其他部分(鏡面)
drawSomething(yRot);
//10.恢復(fù)為逆時(shí)針為正面
glFrontFace(GL_CCW);
//11.繪制鏡面完畢挎扰,恢復(fù)矩陣
modelViewMatrix.PopMatrix();
//12.開啟混合功能(繪制地板)
glEnable(GL_BLEND);
//13. 指定 glBlendFunc 顏色混合方程式
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//14.綁定地面紋理
glBindTexture(GL_TEXTURE_2D, uiTextures[0]);
/*15.
紋理調(diào)整著色器(將一個(gè)基本色乘以一個(gè)取自紋理的單元nTextureUnit的紋理)
參數(shù)1:GLT_SHADER_TEXTURE_MODULATE
參數(shù)2:模型視圖投影矩陣
參數(shù)3:顏色
參數(shù)4:紋理單元(第0層的紋理單元)
*/
shaderManager.UseStockShader(GLT_SHADER_TEXTURE_MODULATE,
transformPipeline.GetModelViewProjectionMatrix(),
vFloorColor,
0);
//開始繪制
floorBatch.Draw();
//繪制完畢,取消混合
glDisable(GL_BLEND);
//16.繪制地面以外其他部分
drawSomething(yRot);
//17.繪制完巢音,恢復(fù)矩陣
modelViewMatrix.PopMatrix();
//18.交換緩存區(qū)
glutSwapBuffers();
//19.提交重新渲染
glutPostRedisplay();
}
//3.移動(dòng)照相機(jī)參考幀遵倦,來(lái)對(duì)方向鍵作出響應(yīng)
void SpeacialKeys(int key,int x,int y)
{
float linear = 0.1f;
float angular = float(m3dDegToRad(5.0f));
if (key == GLUT_KEY_UP) {
cameraFrame.MoveForward(linear);
}
if (key == GLUT_KEY_DOWN) {
cameraFrame.MoveForward(-linear);
}
if (key == GLUT_KEY_LEFT) {
//RotateWorld 旋轉(zhuǎn)
cameraFrame.RotateWorld(angular, 0.0f, 1.0f, 0.0f);
}
if (key == GLUT_KEY_RIGHT) {
cameraFrame.RotateWorld(-angular, 0.0f, 1.0f, 0.0f);
}
}
int main(int argc, char* argv[])
{
gltSetWorkingDirectory(argv[0]);
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(800,600);
glutCreateWindow("OpenGL SphereWorld");
glutReshapeFunc(ChangeSize);
glutDisplayFunc(RenderScene);
glutSpecialFunc(SpeacialKeys);
GLenum err = glewInit();
if (GLEW_OK != err) {
fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
return 1;
}
SetupRC();
glutMainLoop();
ShutdownRC();
return 0;
}
代碼片段解析
地板
用一整塊大地板,并使用10倍的紋理坐標(biāo)大小官撼,實(shí)現(xiàn)效果梧躺。
//5.設(shè)置地板頂點(diǎn)數(shù)據(jù)&地板紋理
GLfloat texSize = 10.0f;
floorBatch.Begin(GL_TRIANGLE_FAN, 4, 1);
floorBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
floorBatch.Vertex3f(-20.f, -0.41f, 20.0f);
floorBatch.MultiTexCoord2f(0, texSize, 0.0f);
floorBatch.Vertex3f(20.0f, -0.41f, 20.f);
floorBatch.MultiTexCoord2f(0, texSize, texSize);
floorBatch.Vertex3f(20.0f, -0.41f, -20.0f);
floorBatch.MultiTexCoord2f(0, 0.0f, texSize);
floorBatch.Vertex3f(-20.0f, -0.41f, -20.0f);
floorBatch.End();
紋理
依次讀取3個(gè)紋理,并使用了mipmap技術(shù)
//7.創(chuàng)建3個(gè)紋理對(duì)象
glGenTextures(3, uiTextures);
//8.將TGA文件加載為2D紋理傲绣。
//參數(shù)1:紋理文件名稱
//參數(shù)2&參數(shù)3:需要縮小&放大的過(guò)濾器
//參數(shù)4:紋理坐標(biāo)環(huán)繞模式
glBindTexture(GL_TEXTURE_2D, uiTextures[0]);
LoadTGATexture("marble.tga", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_REPEAT);
glBindTexture(GL_TEXTURE_2D, uiTextures[1]);
LoadTGATexture("marslike.tga", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_CLAMP_TO_EDGE);
glBindTexture(GL_TEXTURE_2D, uiTextures[2]);
LoadTGATexture("moonlike.tga", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_CLAMP_TO_EDGE);
球的貼圖
不管是大球還是小球掠哥,繪制方式基本和原來(lái)一樣。只是多了紋理的綁定斜筐,同時(shí)使用的shader從GLT_SHADER_POINT_LIGHT_DIFF變?yōu)榱薌LT_SHADER_TEXTURE_POINT_LIGHT_DIFF龙致。
//2.繪制懸浮小球
glBindTexture(GL_TEXTURE_2D, uiTextures[2]);
for(int i = 0; i < NUM_SPHERES; i++) {
modelViewMatrix.PushMatrix();
modelViewMatrix.MultMatrix(spheres[i]);
shaderManager.UseStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF,
modelViewMatrix.GetMatrix(),
transformPipeline.GetProjectionMatrix(),
vLightPos,
vWhite,
0);
sphereBatch.Draw();
modelViewMatrix.PopMatrix();
}
鏡面效果
鏡面效果通過(guò)鏡像繪制小球,并和地板進(jìn)行混合達(dá)到鏡面效果顷链。
鏡面之后目代,y軸的前后移動(dòng)會(huì)反向;原來(lái)正面為逆時(shí)針嗤练,現(xiàn)在為順時(shí)針榛了。
// 添加反光效果
//翻轉(zhuǎn)Y軸
modelViewMatrix.Scale(1.0f, -1.0f, 1.0f);
//鏡面世界圍繞Y軸平移一定間距,因?yàn)殓R面了煞抬,所以是向下移動(dòng)0.8
modelViewMatrix.Translate(0.0f, 0.8f, 0.0f);
// 鏡面后霜大,原來(lái)逆時(shí)針為正面,現(xiàn)在順時(shí)針為正面
//8.指定順時(shí)針為正面
glFrontFace(GL_CW);
//9.繪制地面以外其他部分(鏡面)
drawSomething(yRot);
//10.恢復(fù)為逆時(shí)針為正面
glFrontFace(GL_CCW);
//11.繪制鏡面完畢革答,恢復(fù)矩陣
modelViewMatrix.PopMatrix();
//12.開啟混合功能(繪制地板)
glEnable(GL_BLEND);
//13. 指定 glBlendFunc 顏色混合方程式
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//14.綁定地面紋理
glBindTexture(GL_TEXTURE_2D, uiTextures[0]);
/*15.
紋理調(diào)整著色器(將一個(gè)基本色乘以一個(gè)取自紋理的單元nTextureUnit的紋理)
參數(shù)1:GLT_SHADER_TEXTURE_MODULATE
參數(shù)2:模型視圖投影矩陣
參數(shù)3:顏色
參數(shù)4:紋理單元(第0層的紋理單元)
*/
shaderManager.UseStockShader(GLT_SHADER_TEXTURE_MODULATE,
transformPipeline.GetModelViewProjectionMatrix(),
vFloorColor,
0);
//開始繪制
floorBatch.Draw();
//繪制完畢战坤,取消混合
glDisable(GL_BLEND);