(1)移动旋转方块代码分析
这个代码是基于最开始的代码分析当中对方块的移动的代码。
实现每一次移动方块,方块都会进行旋转相应的角度。通过对旋转矩阵的增加,并且将旋转矩阵和移动矩阵进行综合,并且将其作为参数投入到shadermanagement当中,从而使得每一个顶点都会遵循相应的移动矩阵方式对其进行移动。
#pragma comment(lib,"GLTools.lib")
#include <GLTools.h> // OpenGL toolkit
#include <GLShaderManager.h>
#include <math3d.h>
#include <GL/glut.h>
//渲染队列
GLBatch squareBatch;
GLShaderManager shaderManager;
GLfloat blockSize = 0.1f;
GLfloat vVerts[] = { -blockSize, -blockSize, 0.0f,
blockSize, -blockSize, 0.0f,
blockSize, blockSize, 0.0f,
-blockSize, blockSize, 0.0f };
GLfloat xPos = 0.0f;
GLfloat yPos = 0.0f;
///////////////////////////////////////////////////////////////////////////////
// 初始化渲染场景
void SetupRC()
{
// 设置背景颜色
glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
//初始化渲染器管理器
shaderManager.InitializeStockShaders();
//对squareBatch进行渲染。
squareBatch.Begin(GL_TRIANGLE_FAN, 4);
squareBatch.CopyVertexData3f(vVerts);
squareBatch.End();
}
// 设置按键对其进行控制
void SpecialKeys(int key, int x, int y)
{
GLfloat stepSize = 0.025f;
//设置不同按键
if (key == GLUT_KEY_UP)
yPos += stepSize;
if (key == GLUT_KEY_DOWN)
yPos -= stepSize;
if (key == GLUT_KEY_LEFT)
xPos -= stepSize;
if (key == GLUT_KEY_RIGHT)
xPos += stepSize;
// 碰撞检测
if (xPos < (-1.0f + blockSize)) xPos = -1.0f + blockSize;
if (xPos > (1.0f - blockSize)) xPos = 1.0f - blockSize;
if (yPos < (-1.0f + blockSize)) yPos = -1.0f + blockSize;
if (yPos > (1.0f - blockSize)) yPos = 1.0f - blockSize;
glutPostRedisplay();
}
///////////////////////////////////////////////////////////////////////////////
// 正真的渲染函数
//注意其矩阵操作的方法。
void RenderScene(void)
{
// 清除当前的缓冲区
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
//设置红色
GLfloat vRed[] = { 1.0f, 0.0f, 0.0f, 1.0f };
//设置当前的矩阵
//最终矩阵、移动矩阵、旋转矩阵
M3DMatrix44f mFinalTransform, mTranslationMatrix, mRotationMatrix;
// 初始化使用相关的移动参数生成相关的矩阵
m3dTranslationMatrix44(mTranslationMatrix, xPos, yPos, 0.0f);
// 每一次操作,进行5个单位的旋转
static float yRot = 0.0f;
yRot += 5.0f;
//不断的绕着z轴进行旋转,利用不同的旋转参数生成矩阵
m3dRotationMatrix44(mRotationMatrix, m3dDegToRad(yRot), 0.0f, 0.0f, 1.0f);
//利用矩阵乘法生成一个综合矩阵
m3dMatrixMultiply44(mFinalTransform, mTranslationMatrix, mRotationMatrix);
//利用上述的参数对相关的点参数进行变换
shaderManager.UseStockShader(GLT_SHADER_FLAT, mFinalTransform, vRed);
squareBatch.Draw();
// 手动更新
glutSwapBuffers();
}
///////////////////////////////////////////////////////////////////////////////
void ChangeSize(int w, int h)
{
glViewport(0, 0, w, h);
}
///////////////////////////////////////////////////////////////////////////////
// 主函数
int main(int argc, char* argv[])
{
gltSetWorkingDirectory(argv[0]);
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
glutInitWindowSize(600, 600);
glutCreateWindow("Move Block with Arrow Keys");
GLenum err = glewInit();
if (GLEW_OK != err)
{
// Problem: glewInit failed, something is seriously wrong.
fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
return 1;
}
glutReshapeFunc(ChangeSize);
glutDisplayFunc(RenderScene);
glutSpecialFunc(SpecialKeys);
SetupRC();
glutMainLoop();
return 0;
}
(2)模型投影矩阵应用
注意模型投影矩阵的应用
生成透视投影:GLFrustum viewFrustum;
在窗口控制函数中:viewFrustum.SetPerspective(35.0f, float(w) / float(h), 1.0f, 1000.0f);
最终和模型矩阵综合:m3dMatrixMultiply44(mModelViewProjection,viewFrustum.GetProjectionMatrix(), mModelview);
#pragma comment(lib,"GLTools.lib")
#include <GLTools.h> // OpenGL toolkit
#include <GLMatrixStack.h>
#include <GLFrame.h>
#include <GLFrustum.h>
#include <GLGeometryTransform.h>
#include <GLBatch.h>
#include <StopWatch.h>
#include <GL/glut.h>
// 透视投影
GLFrustum viewFrustum;
// 渲染器管理器
GLShaderManager shaderManager;
// 渲染队列
GLTriangleBatch torusBatch;
void ChangeSize(int w, int h)
{
// 避免下面设置透视的时候出错
if (h == 0)
h = 1;
// 将视口设置到窗口的规模
glViewport(0, 0, w, h);
//设置透视投影
viewFrustum.SetPerspective(35.0f, float(w) / float(h), 1.0f, 1000.0f);
}
// 渲染窗口
void RenderScene(void)
{
// 动画设置的秒表
static CStopWatch rotTimer;
//得到当前的时间并且计算旋转
float yRot = rotTimer.GetElapsedSeconds() * 60.0f;
// 清除相关缓冲区
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// 设置当前的矩阵变量
M3DMatrix44f mTranslate, mRotate, mModelview, mModelViewProjection;
// 初始化移动矩阵
m3dTranslationMatrix44(mTranslate, 0.0f, 0.0f, -2.5f);
// 初始化旋转矩阵
m3dRotationMatrix44(mRotate, m3dDegToRad(yRot), 0.0f, 1.0f, 0.0f);
// 将上述两个矩阵综合进模型矩阵
m3dMatrixMultiply44(mModelview, mTranslate, mRotate);
// 将模型矩阵装入到投影矩阵当中
// 生成最终的模型投影矩阵
m3dMatrixMultiply44(mModelViewProjection, viewFrustum.GetProjectionMatrix(), mModelview);
// 对各个顶点进行绘制
GLfloat vBlack[] = { 0.0f, 0.0f, 0.0f, 1.0f };
shaderManager.UseStockShader(GLT_SHADER_FLAT, mModelViewProjection, vBlack);
torusBatch.Draw();
// Swap buffers, and immediately refresh
glutSwapBuffers();
glutPostRedisplay();
}
// 渲染环境初始化
void SetupRC()
{
// 背景颜色设置
glClearColor(0.8f, 0.8f, 0.8f, 1.0f);
glEnable(GL_DEPTH_TEST);
shaderManager.InitializeStockShaders();
// 调用生成花拖的函数。
gltMakeTorus(torusBatch, 0.4f, 0.15f, 30, 30);
//正反面都用线框渲染
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
}
///
// 主函数
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("ModelViewProjection Example");
glutReshapeFunc(ChangeSize);
glutDisplayFunc(RenderScene);
GLenum err = glewInit();
if (GLEW_OK != err) {
fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
return 1;
}
SetupRC();
glutMainLoop();
return 0;
}
(3)渲染一个简单世界
这里包含了一个完整的渲染顺序
实例化两个MatrixStack,一个作为模型矩阵,一个作为投影矩阵。
然后实例化一个渲染管线。
ChangeSize当中对投影矩阵进行赋值,并且利用两个矩阵堆栈对渲染管线初始化。
RenderScene当中对模型矩阵进行操作,按照先渲染静止物体,在渲染移动物体的原则。
注意这里对地面的动态设置渲染:对于floorBatch不断为期增加点,对其渲染器进行装填。
floorBatch.Begin(GL_LINES, 324);
for (GLfloat x = -20.0; x <= 20.0f; x += 0.5) {
//设置定点
floorBatch.Vertex3f(x, -0.55f, 20.0f);
floorBatch.Vertex3f(x, -0.55f, -20.0f);
floorBatch.Vertex3f(20.0f, -0.55f, x);
floorBatch.Vertex3f(-20.0f, -0.55f, x);
}
#pragma comment(lib,"GLTools.lib")
#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>
#include <GL/glut.h>
GLShaderManager shaderManager; // Shader Manager
GLMatrixStack modelViewMatrix; // 模型视图矩阵
GLMatrixStack projectionMatrix; // 投影矩阵
GLFrustum viewFrustum; // 视景体
GLGeometryTransform transformPipeline; // 几何变换管线
GLTriangleBatch torusBatch;
GLBatch floorBatch;
//
// 渲染环境初始化
void SetupRC()
{
// 初始化ShaderManager。
shaderManager.InitializeStockShaders();
//开启深度测试
glEnable(GL_DEPTH_TEST);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
//背景颜色为黑色
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
// 创建花拖
gltMakeTorus(torusBatch, 0.4f, 0.15f, 30, 30);
//设置地板
//使用计算方法动态生成
floorBatch.Begin(GL_LINES, 324);
for (GLfloat x = -20.0; x <= 20.0f; x += 0.5) {
//设置定点
floorBatch.Vertex3f(x, -0.55f, 20.0f);
floorBatch.Vertex3f(x, -0.55f, -20.0f);
floorBatch.Vertex3f(20.0f, -0.55f, x);
floorBatch.Vertex3f(-20.0f, -0.55f, x);
}
floorBatch.End();
}
///
// 设置屏幕大小
void ChangeSize(int nWidth, int nHeight)
{
glViewport(0, 0, nWidth, nHeight);
// 创建透视矩阵,GLFrustum类的viewFrustum实例会为我们设置投影矩阵
//载入投影矩阵对象
viewFrustum.SetPerspective(35.0f, float(nWidth) / float(nHeight), 1.0f, 100.0f);
//透视矩阵加载到透视矩阵堆栈中
projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
//初始化渲染管线
// 设置变换管线,从而可以使用两个矩阵堆栈
transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
//注意:我们本可以在SetupRC当中完成这项工作。但是窗口大小
//改变的时候,重新设置它们并没有坏处。并且可以一次性完成
//矩阵和管线的设置。
}
// 绘制两个物体
void RenderScene(void)
{
// 设置绘制不同物体的颜色。
static GLfloat vFloorColor[] = { 0.0f, 1.0f, 0.0f, 1.0f };
static GLfloat vTorusColor[] = { 1.0f, 0.0f, 0.0f, 1.0f };
// 设置秒表计时器
static CStopWatch rotTimer;
float yRot = rotTimer.GetElapsedSeconds() * 60.0f;
// 清除相应的缓冲区
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// 保存当前的矩阵,单位矩阵
modelViewMatrix.PushMatrix();
// 使用平面渲染器对其进行渲染
shaderManager.UseStockShader(GLT_SHADER_FLAT,
transformPipeline.GetModelViewProjectionMatrix(),
vFloorColor);
floorBatch.Draw();
// 绘制旋转的花拖
modelViewMatrix.Translate(0.0f, 0.0f, -2.5f);
modelViewMatrix.Rotate(yRot, 0.0f, 1.0f, 0.0f);
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(),
vTorusColor);
torusBatch.Draw();
// 恢复初始的矩阵
modelViewMatrix.PopMatrix();
// Do the buffer Swap
glutSwapBuffers();
// Tell GLUT to do it again
glutPostRedisplay();
}
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);
GLenum err = glewInit();
if (GLEW_OK != err) {
fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
return 1;
}
SetupRC();
glutMainLoop();
return 0;
}
(4)为世界添加一个移动的摄像机
以下程序说明对摄像机的控制,同时也多次渲染了一个球体。
渲染摄像机的步骤:
GLFrame cameraFrame:首先使用角色帧来完成一个摄像机的创建。
M3DMatrix44f mCamera:在render里面新创建一个矩阵。
cameraFrame.GetCameraMatrix(mCamera):找出符合条件的摄像机矩阵。
modelViewMatrix.PushMatrix(mCamera):把摄像机矩阵压入模型矩阵中。
在上述操作之后,在SpecialKey当中,也设置诸多的key对其进行渲染:
cameraFrame.RotateWorld(angular, 0.0f, 1.0f, 0.0f);
cameraFrame.MoveForward(-linear);
对于渲染多个物体:
modelViewMatrix.PopMatrix();多次使用pop来取消之前的矩阵操作,从而之后的操作不会对之前的操作产生影响。
#pragma comment(lib,"GLTools.lib")
#include <GLTools.h>
#include <GLShaderManager.h>
#include <GLFrustum.h>
#include <GLBatch.h>
#include <GLFrame.h>
#include <GLMatrixStack.h>
#include <GLGeometryTransform.h>
#include <StopWatch.h>
#include <math.h>
#include <stdio.h>
#include <GL/glut.h>
GLShaderManager shaderManager; // 渲染管理器
GLMatrixStack modelViewMatrix; // 模型矩阵
GLMatrixStack projectionMatrix; // 透视矩阵
GLFrustum viewFrustum; // 透视
GLGeometryTransform transformPipeline; // 渲染管线
GLTriangleBatch torusBatch;
GLBatch floorBatch;
GLTriangleBatch sphereBatch;
//设置角色帧,作为相机
GLFrame cameraFrame;
//
// 渲染环境设置
void SetupRC()
{
//初始化渲染管理器
shaderManager.InitializeStockShaders();
//开启深度测试
glEnable(GL_DEPTH_TEST);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
// 创建一个花拖
gltMakeTorus(torusBatch, 0.4f, 0.15f, 30, 30);
//创建一个球
gltMakeSphere(sphereBatch, 0.1f, 26, 13);
//创建地板
floorBatch.Begin(GL_LINES, 324);
for (GLfloat x = -20.0; x <= 20.0f; x += 0.5) {
floorBatch.Vertex3f(x, -0.55f, 20.0f);
floorBatch.Vertex3f(x, -0.55f, -20.0f);
floorBatch.Vertex3f(20.0f, -0.55f, x);
floorBatch.Vertex3f(-20.0f, -0.55f, x);
}
floorBatch.End();
}
///
// 改变窗口大小
void ChangeSize(int nWidth, int nHeight)
{
glViewport(0, 0, nWidth, nHeight);
// 设置透视模式,初始化其透视矩阵
viewFrustum.SetPerspective(35.0f, float(nWidth) / float(nHeight), 1.0f, 100.0f);
//把透视矩阵加载到透视矩阵对阵中
projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
// 初始化渲染管线。
transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
}
// 键位设置,通过不同的键位对其进行设置
//控制Camera的移动,从而改变视口。
void SpecialKeys(int key, int x, int y)
{
//设置移动的分量
float linear = 0.1f;
//设置旋转的分量
float angular = float(m3dDegToRad(5.0f));
//注意其如何对Camera进行操作
if (key == GLUT_KEY_UP)
cameraFrame.MoveForward(linear);
if (key == GLUT_KEY_DOWN)
cameraFrame.MoveForward(-linear);
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);
}
// Called to draw scene
void RenderScene(void)
{
//三种渲染颜色
static GLfloat vFloorColor[] = { 0.0f, 1.0f, 0.0f, 1.0f };
static GLfloat vTorusColor[] = { 1.0f, 0.0f, 0.0f, 1.0f };
static GLfloat vSphereColor[] = { 0.0f, 0.0f, 1.0f, 1.0f };
// 计时器,从而做出基础动画
static CStopWatch rotTimer;
float yRot = rotTimer.GetElapsedSeconds() * 60.0f;
// 清除缓冲区
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// 装载当前的单位矩阵
modelViewMatrix.PushMatrix();
//创建一个矩阵作为摄像机矩阵
M3DMatrix44f mCamera;
//这个函数用来检索条件适合的照相机矩阵并且初始化给mCamera。
cameraFrame.GetCameraMatrix(mCamera);
//将照相机矩阵压入模型矩阵堆栈
modelViewMatrix.PushMatrix(mCamera);
// 绘制地面
shaderManager.UseStockShader(GLT_SHADER_FLAT,
transformPipeline.GetModelViewProjectionMatrix(),
vFloorColor);
floorBatch.Draw();
// 绘制花拖进行移动
modelViewMatrix.Translate(0.0f, 0.0f, -2.5f);
// 对上面的操作进行保存
modelViewMatrix.PushMatrix();
// 旋转一个角度。
modelViewMatrix.Rotate(yRot, 0.0f, 1.0f, 0.0f);
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(),
vTorusColor);
torusBatch.Draw();
modelViewMatrix.PopMatrix(); //去掉Rotate的操作
// 应用一个其他的球体,并且对它进行移动。
modelViewMatrix.Rotate(yRot * -2.0f, 0.0f, 1.0f, 0.0f);
modelViewMatrix.Translate(0.8f, 0.0f, 0.0f);
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(),
vSphereColor);
sphereBatch.Draw();
// Restore the previous modleview matrix (the identity matrix)
modelViewMatrix.PopMatrix();
modelViewMatrix.PopMatrix();
// 因为是GLUT_DOUBLE,所以需要后台渲染,再交换到前台
glutSwapBuffers();
// 手动刷新
glutPostRedisplay();
}
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");
glutSpecialFunc(SpecialKeys);
glutReshapeFunc(ChangeSize);
glutDisplayFunc(RenderScene);
GLenum err = glewInit();
if (GLEW_OK != err) {
fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
return 1;
}
SetupRC();
glutMainLoop();
return 0;
}
(5)对世界渲染更多事物
渲染多个物体所遵循的原则和上面基本一致:
先渲染静态物体
再渲染动态物体
动态物体注意不断pop矩阵堆栈
摄像机矩阵添加到模型视图矩阵队列
投影矩阵添加到投影视图矩阵队列
#pragma comment(lib,"GLTools.lib")
#include <GLTools.h>
#include <GLShaderManager.h>
#include <GLFrustum.h>
#include <GLBatch.h>
#include <GLFrame.h>
#include <GLMatrixStack.h>
#include <GLGeometryTransform.h>
#include <StopWatch.h>
#include <math.h>
#include <stdio.h>
#include <GL/glut.h>
#define NUM_SPHERES 50
GLFrame spheres[NUM_SPHERES];
GLShaderManager shaderManager; // 渲染管理器
GLMatrixStack modelViewMatrix; // 模型渲染矩阵
GLMatrixStack projectionMatrix; // 投影矩阵
GLFrustum viewFrustum; // 视图矩阵
GLGeometryTransform transformPipeline; // 渲染管线
GLTriangleBatch torusBatch;
GLBatch floorBatch;
GLTriangleBatch sphereBatch;
GLFrame cameraFrame;
//
// 渲染环境初始化
void SetupRC()
{
// 渲染器管理器初始化
shaderManager.InitializeStockShaders();
//开启深度检测
glEnable(GL_DEPTH_TEST);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
//设置黑色为背景颜色
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
// 创建花拖
gltMakeTorus(torusBatch, 0.4f, 0.15f, 30, 30);
// 创建球体
gltMakeSphere(sphereBatch, 0.1f, 26, 13);
//创建地面
floorBatch.Begin(GL_LINES, 324);
for (GLfloat x = -20.0; x <= 20.0f; x += 0.5) {
floorBatch.Vertex3f(x, -0.55f, 20.0f);
floorBatch.Vertex3f(x, -0.55f, -20.0f);
floorBatch.Vertex3f(20.0f, -0.55f, x);
floorBatch.Vertex3f(-20.0f, -0.55f, x);
}
floorBatch.End();
// 随机分配相关的x、z位置
for (int i = 0; i < NUM_SPHERES; i++) {
GLfloat x = ((GLfloat)((rand() % 400) - 200) * 0.1f);
GLfloat z = ((GLfloat)((rand() % 400) - 200) * 0.1f);
//注意这个函数,设置其位置
spheres[i].SetOrigin(x, 0.0f, z);
}
}
///
// 屏幕改变的时候需要调节的参数
void ChangeSize(int nWidth, int nHeight)
{
glViewport(0, 0, nWidth, nHeight);
// 对GLFrustum生成投影矩阵
viewFrustum.SetPerspective(35.0f, float(nWidth) / float(nHeight), 1.0f, 100.0f);
//把投影矩阵压入相关的投影矩阵堆栈
projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
// 初始化渲染管线
transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
}
// 实际渲染的方式
void RenderScene(void)
{
// 设置相应的颜色参数
static GLfloat vFloorColor[] = { 0.0f, 1.0f, 0.0f, 1.0f };
static GLfloat vTorusColor[] = { 1.0f, 0.0f, 0.0f, 1.0f };
static GLfloat vSphereColor[] = { 0.0f, 0.0f, 1.0f, 1.0f };
// 计时器的计算
static CStopWatch rotTimer;
float yRot = rotTimer.GetElapsedSeconds() * 60.0f;
// 清楚相关的缓冲区
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// 对模型矩阵压入单位矩阵
modelViewMatrix.PushMatrix();
//设置一个Camera矩阵
M3DMatrix44f mCamera;
//对于创建的角色帧得到符合条件的摄像机矩阵
cameraFrame.GetCameraMatrix(mCamera);
//把得到的摄像机矩阵压入对应的模型矩阵
modelViewMatrix.PushMatrix(mCamera);
// 利用平面渲染器渲染地面,同时把模型视图矩阵传递给渲染器
shaderManager.UseStockShader(GLT_SHADER_FLAT,
transformPipeline.GetModelViewProjectionMatrix(),
vFloorColor);
floorBatch.Draw();
//对于球体进行相应的渲染
for (int i = 0; i < NUM_SPHERES; i++) {
//模型视图矩阵压入矩阵
//把球体的渲染信息压入模型视图矩阵
modelViewMatrix.PushMatrix();
//对于球体进行渲染
modelViewMatrix.MultMatrix(spheres[i]);
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(),
vSphereColor);
sphereBatch.Draw();
modelViewMatrix.PopMatrix();
//每一次渲染之后,都需要对矩阵堆栈进行弹出
//清理之前的操作矩阵,并且向其中压入新的操作矩阵
}
//渲染静态物体结束
//开始渲染动态物体
//向模型视图矩阵堆栈传递位置矩阵
modelViewMatrix.Translate(0.0f, 0.0f, -2.5f);
// 保存其操作
modelViewMatrix.PushMatrix();
// 应用旋转
modelViewMatrix.Rotate(yRot, 0.0f, 1.0f, 0.0f);
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(),
vTorusColor);
torusBatch.Draw();
modelViewMatrix.PopMatrix(); //清空当前旋转操作矩阵
// 应用另外一个旋转矩阵
modelViewMatrix.Rotate(yRot * -2.0f, 0.0f, 1.0f, 0.0f);
modelViewMatrix.Translate(0.8f, 0.0f, 0.0f);
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(),
vSphereColor);
sphereBatch.Draw();
// 让矩阵堆栈回到初始默认状态,单位矩阵。
modelViewMatrix.PopMatrix();
modelViewMatrix.PopMatrix();
// 交换渲染区
glutSwapBuffers();
// 手动渲染
glutPostRedisplay();
}
// 通过按键来完成对相机的操作。
void SpecialKeys(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)
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");
glutSpecialFunc(SpecialKeys);
glutReshapeFunc(ChangeSize);
glutDisplayFunc(RenderScene);
GLenum err = glewInit();
if (GLEW_OK != err) {
fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
return 1;
}
SetupRC();
glutMainLoop();
return 0;
}
(6)光线渲染
关于光线的设置。需要设置一个光源矩阵。
并且把光源矩阵和之前得到的 GetCameraMatrix(mCamera)做Transform操作,得到一个结果矩阵。
然后把结果矩阵传入到对应的渲染器当中作为一个重要参数。参考之前的《基础渲染》文章,当中的诸多渲染器方法可供选择,选择一个可行的方式对想要操作的对象进行渲染。
#pragma comment(lib,"GLTools.lib")
#include <GLTools.h>
#include <GLShaderManager.h>
#include <GLFrustum.h>
#include <GLBatch.h>
#include <GLFrame.h>
#include <GLMatrixStack.h>
#include <GLGeometryTransform.h>
#include <StopWatch.h>
#include <math.h>
#include <stdio.h>
#include <GL/glut.h>
#define NUM_SPHERES 50
GLFrame spheres[NUM_SPHERES];
GLShaderManager shaderManager; // Shader Manager
GLMatrixStack modelViewMatrix; // Modelview Matrix
GLMatrixStack projectionMatrix; // Projection Matrix
GLFrustum viewFrustum; // View Frustum
GLGeometryTransform transformPipeline; // Geometry Transform Pipeline
GLTriangleBatch torusBatch;
GLBatch floorBatch;
GLTriangleBatch sphereBatch;
GLFrame cameraFrame;
//
// This function does any needed initialization on the rendering
// context.
void SetupRC()
{
shaderManager.InitializeStockShaders();
glEnable(GL_DEPTH_TEST);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
gltMakeTorus(torusBatch, 0.4f, 0.15f, 30, 30);
gltMakeSphere(sphereBatch, 0.1f, 26, 13);
floorBatch.Begin(GL_LINES, 324);
for (GLfloat x = -20.0; x <= 20.0f; x += 0.5) {
floorBatch.Vertex3f(x, -0.55f, 20.0f);
floorBatch.Vertex3f(x, -0.55f, -20.0f);
floorBatch.Vertex3f(20.0f, -0.55f, x);
floorBatch.Vertex3f(-20.0f, -0.55f, x);
}
floorBatch.End();
for (int i = 0; i < NUM_SPHERES; i++) {
GLfloat x = ((GLfloat)((rand() % 400) - 200) * 0.1f);
GLfloat z = ((GLfloat)((rand() % 400) - 200) * 0.1f);
spheres[i].SetOrigin(x, 0.0f, z);
}
}
///
void ChangeSize(int nWidth, int nHeight)
{
glViewport(0, 0, nWidth, nHeight);
viewFrustum.SetPerspective(35.0f, float(nWidth) / float(nHeight), 1.0f, 100.0f);
projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
}
void RenderScene(void)
{
static GLfloat vFloorColor[] = { 0.0f, 1.0f, 0.0f, 1.0f };
static GLfloat vTorusColor[] = { 1.0f, 0.0f, 0.0f, 1.0f };
static GLfloat vSphereColor[] = { 0.0f, 0.0f, 1.0f, 1.0f };
static CStopWatch rotTimer;
float yRot = rotTimer.GetElapsedSeconds() * 60.0f;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
modelViewMatrix.PushMatrix();
M3DMatrix44f mCamera;
cameraFrame.GetCameraMatrix(mCamera);
modelViewMatrix.PushMatrix(mCamera);
// 设置光源位置。注意,光源位置的全局坐标系存储在vLightPos
//包含了光源位置的x、y、z和w坐标。
M3DVector4f vLightPos = { 0.0f, 10.0f, 5.0f, 1.0f };
M3DVector4f vLightEyePos; //最终传入到渲染器的矩阵
//m3dTransformVector4使用该函数对光源位置进行变换
m3dTransformVector4(vLightEyePos, vLightPos, mCamera);
//注意地板的渲染器是平面渲染器
shaderManager.UseStockShader(GLT_SHADER_FLAT,
transformPipeline.GetModelViewProjectionMatrix(),
vFloorColor);
floorBatch.Draw();
//而对于其他的模型使用点光源渲染器
for (int i = 0; i < NUM_SPHERES; i++) {
modelViewMatrix.PushMatrix();
modelViewMatrix.MultMatrix(spheres[i]);
shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF, transformPipeline.GetModelViewMatrix(),
transformPipeline.GetProjectionMatrix(), vLightEyePos, vSphereColor);
//注意传入的参数:模型视图矩阵、投影矩阵、光纤位置、渲染的漫反射颜色
sphereBatch.Draw();
modelViewMatrix.PopMatrix();
}
modelViewMatrix.Translate(0.0f, 0.0f, -2.5f);
modelViewMatrix.PushMatrix();
modelViewMatrix.Rotate(yRot, 0.0f, 1.0f, 0.0f);
shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF, transformPipeline.GetModelViewMatrix(),
transformPipeline.GetProjectionMatrix(), vLightEyePos, vTorusColor);
torusBatch.Draw();
modelViewMatrix.PopMatrix(); // 删除之前的参数
modelViewMatrix.Rotate(yRot * -2.0f, 0.0f, 1.0f, 0.0f);
modelViewMatrix.Translate(0.8f, 0.0f, 0.0f);
shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF, transformPipeline.GetModelViewMatrix(),
transformPipeline.GetProjectionMatrix(), vLightEyePos, vSphereColor);
sphereBatch.Draw();
// 弹出之前所做的操作
modelViewMatrix.PopMatrix();
modelViewMatrix.PopMatrix();
// 因为是双渲染管道,需要交换后台和前台的渲染信息。
glutSwapBuffers();
//手动渲染
glutPostRedisplay();
}
void SpecialKeys(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)
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");
glutSpecialFunc(SpecialKeys);
glutReshapeFunc(ChangeSize);
glutDisplayFunc(RenderScene);
GLenum err = glewInit();
if (GLEW_OK != err) {
fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
return 1;
}
SetupRC();
glutMainLoop();
return 0;
}