2020-07-17 OpenGL 案例

225 阅读3分钟

使用OpenGL渲染大球自转+小球公转+移动

实例讲解

流程
主要函数及功能
  • main函数
  • ChangeSize函数
  • setupRC函数
    • mainloop循环
    • 重塑消息
    • 重绘
    • 键位输入
  • RendeScene函数
  • SpecialKeys函数接收输入
构造地板,大球以及小球
  • 地板 SetupRC函数并定义地板的顶点数据 RenderScene利用平面着色器绘制地板
  • 大球 绘制完地板之后开始绘制大球 * 设置定时器记录当前时间自转大球的旋转角度 * 设置大球变换并绘制大球 * 开启定时器,通过提交重新渲染的请求,出发定时器并渲染
    //5.使得大球位置平移(3.0)向屏幕里面
    modelViewMatrix.Translate(0.0f, 0.0f, -3.0f);
    //6.压栈(复制栈顶)
    modelViewMatrix.PushMatrix();
    //7.大球自转
    modelViewMatrix.Rotate(yRot, 0.0f, 1.0f, 0.0f);
    
  • 小球
    • 初始化小球数据
    • 绘制小球
    • 绘制50个小球,小球都需要入栈和出栈
    • 小球加入动态

公转小球需要与大球保持距离

旋转原理

代码

//相关定义
GLShaderManager		shaderManager;			// 着色器管理器
GLMatrixStack		modelViewMatrix;		// 模型视图矩阵堆栈
GLMatrixStack		projectionMatrix;		// 投影矩阵堆栈
GLFrustum			viewFrustum;			// 视景体
GLGeometryTransform	transformPipeline;		// 几何图形变换管道

GLTriangleBatch		torusBatch;             //大球
GLTriangleBatch     sphereBatch;            //小球
GLBatch             floorBatch;          //地板
//角色帧 照相机角色帧
GLFrame   cameraFrame;
GLFrame  objectFrame;

//**4、添加附加随机球
#define NUM_SPHERES 50
GLFrame spheres[NUM_SPHERES];
void SetupRC()
{
    //1. 初始化
    glClearColor(0, 0, 0, 1);
    shaderManager.InitializeStockShaders();
    glEnable(GL_DEPTH_TEST);
    
    //3. 地板数据(物体坐标系)
    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();
    
    //4. 设置一个球体(基于gltools模型)
    gltMakeSphere(torusBatch, 0.4f, 40, 80);
    
    //5. 绘制小球;
    gltMakeSphere(sphereBatch, 0.1f, 13, 26);
    //6. 随机位置放置小球球
    for (int i = 0; i < NUM_SPHERES; i++) {
        
        //y轴不变,X,Z产生随机值
        GLfloat x = ((GLfloat)((rand() % 400) - 200 ) * 0.1f);
        GLfloat z = ((GLfloat)((rand() % 400) - 200 ) * 0.1f);
        
        //在y方向,将球体设置为0.0的位置,这使得它们看起来是飘浮在眼睛的高度
        //对spheres数组中的每一个顶点,设置顶点数据
        spheres[i].SetOrigin(x, 0.0f, z);
    }
    
}
//进行调用以绘制场景
void RenderScene(void)
{
    //3.
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
    //1. 颜色(地板,大球颜色,小球颜色)
    static GLfloat vFloorColor[] = {0.0f,1.0f,0.0f,1.0f};
    static GLfloat vTorusColor[] = {1.0f,0.0f,0.0f,1.0f};
    static GLfloat vSpereColor[] = {0.0f,0.0f,1.0f,1.0f};
    
    
    //2. 动画
    static CStopWatch rotTimer;
    float yRot = rotTimer.GetElapsedSeconds()*60.0f;
    
    modelViewMatrix.PushMatrix();
    
    M3DMatrix44f mCamera;
    cameraFrame.GetCameraMatrix(mCamera);
    modelViewMatrix.PushMatrix(mCamera);
    
    
    //4.地面绘制;
    shaderManager.UseStockShader(GLT_SHADER_FLAT,transformPipeline.GetModelViewProjectionMatrix(),vFloorColor);
    floorBatch.Draw();
    
    
    //5. 设置点光源位置
    M3DVector4f vLightPos = {0,10,5,1};
    
    //6. 使得整个大球往里平移3.0
    modelViewMatrix.Translate(0.0f, 0.0f, -3.0f);
    
    //7. 大球
    modelViewMatrix.PushMatrix();
    modelViewMatrix.Rotate(yRot, 0, 1, 0);
    shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF,transformPipeline.GetModelViewMatrix(),transformPipeline.GetProjectionMatrix(),vLightPos,vTorusColor);
    torusBatch.Draw();
    modelViewMatrix.PopMatrix();
    
    
    //8. 小球
    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(),vLightPos,vSpereColor);
        sphereBatch.Draw();
        modelViewMatrix.PopMatrix();
        
    }
    
    
    //9.让一个小球围着大球公转;
    modelViewMatrix.Rotate(yRot * -2.0f, 0, 1, 0);
    modelViewMatrix.Translate(0.8f, 0.0f, 0.0f);
    shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF,transformPipeline.GetModelViewMatrix(),transformPipeline.GetProjectionMatrix(),vLightPos,vSpereColor);
    sphereBatch.Draw();
    
    
    modelViewMatrix.PopMatrix();
    modelViewMatrix.PopMatrix();
    glutSwapBuffers();
    glutPostRedisplay();
    
    
}

//屏幕更改大小或已初始化
void ChangeSize(int nWidth, int nHeight)
{
    //1. 设置视口
    glViewport(0, 0, nWidth, nHeight);

    //2. 创建投影矩阵
    viewFrustum.SetPerspective(35.0f, float(nWidth)/float(nHeight), 1.0f, 100.0f);
    projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
    
    //3. 变换管道设置2个矩阵堆栈(管理)
    transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
    
}
glutReshapeFunc(ChangeSize);
    glutDisplayFunc(RenderScene);
    glutSpecialFunc(SpeacialKeys);
    
    GLenum err = glewInit();
    if (GLEW_OK != err) {
        fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
        return 1;
    }
    
    
    SetupRC();

常用的API记录

//改变像素存储方式
void glPixelStorei(GLenum pname,Glint param);
//恢复像素存储方式
void glPixelStoref(GLenum pname,Glint param);
//从颜色缓存区内容作为像素图直接读取
void glReadPixels(Glint x,Glint y,GLSizei width,GLSizei height,GLenum format,GLenum type,const void *pixels);

//载入纹理
void glTexImage1D(GLenum target,Glint level,Glint internalformat,GLsizei width,GLint border,GLenum format,GLenum type,void *data);
void glTexImage2D(GLenum target,Glint level,Glint internalformat,GLsizei width,GLSizei height,GLint border,GLenum format,GLenum type,void *data);
void glTexImage3D(GLenum target,Glint level,Glint internalformat,GLsizei width,GLSizei height,GLsizei depth,GLint border,GLenum format,GLenum type,void *data);
//更新纹理
void glTexSubImage1D(GLenum target,GLint level,GLint xoffset,GLsizei width,GLenum format,GLenum type,const GLvoid *data);
//插入替换纹理
void glCopyTexSubImage1D(GLenum target,GLint level,GLint xoffset,GLint x,GLint y,GLsize width);

纹理相关内容

  • 设置纹理参数
    glTexParameterf(GLenum target,GLenum pname,GLFloat param);
    glTexParameteri(GLenum target,GLenum pname,GLint param);
    glTexParameterfv(GLenum target,GLenum pname,GLFloat *param);
    glTexParameteriv(GLenum target,GLenum pname,GLint *param);
    参数1:target,指定这些参数将要应⽤用在那个纹理理模式上,⽐比如GL_TEXTURE_1D、GL_TEXTURE_2D、GL_TEXTURE_3D。 参数2:pname,指定需要设置那个纹理理参数
    参数3:param,设定特定的纹理理参数的值
    
  • 纹理的过滤方式
    • 临近过滤(GL_NEAREST)
    • 线性过滤 (GL_LINEAR)