• OpenGL-综合案例:旋转的大小球


    不停的演示正方形和三角形已经有点乏味了,这篇文章我们来一个综合案例,绘制公转自转的大小球

    一些main函数的准备工作,这里就不多阐述了,不了解的可以看之前的文章

    1.地板绘制

    还是熟悉的ChangeSize函数开始:

    • 设置视口glviewport
    • 设置图形投影的方式:因为是立体图形,所以选择透视投影设置透视投影(3d效果)
    1 //参数1:垂直方向上的视场角度
    2 //参数2:视口纵横比 = w/h
    3 //参数3:近裁剪面距离
    4 //参数4:远裁剪面距离
    5 viewFrustum.SetPerspective(35.0f, float(w)/float(h), 1.0f, 500.0f);
    • 通过设置的投影方式获得投影矩阵,并将其存入投影矩阵中
    1 projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
    • 将模型视图矩阵和投影矩阵放到变换管道中(方便快速进行矩阵相乘)
    1 transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);

    然后来到第二个部分,SetupRC初始化:

    设置背景色->初始化着色器->开启深度测试->设置地板的顶点数据

    接下来通过RenderScene绘制场景:

    设置地板颜色->清理颜色缓冲区和深度缓冲区->绘制地板->交换缓冲区

    1     // 绘制地板
    2     shaderManager.UseStockShader(GLT_SHADER_FLAT,
    3                                  transformPipeline.GetModelViewProjectionMatrix(),
    4                                  vFloorColor);
    5     floorBatch.Draw();

    绘制地板这里我们采用最简单的平面着色器,然后通过我们之前设置的变换管道,获取模型视图投影矩阵(MVP)放入其中,并设置上地板颜色进行绘制,我们的地板就绘制成功了。

    2.绘制大球

    在地板绘制完成的基础上,我们开始绘制大球,并实现其自转功能

    首先是SetupRC函数,初始化大球的顶点数据,这里我们用到gltMakeSphere函数,引用一个三角形批次、设置球半径和组成球体的片段及其堆叠数量,

    我们可以将球体想象成围绕成球形的一系列三角形带:

    1 // 参数iStacks是这些从球体底部堆叠到顶部的三角形的数量。
    2 // 参数iSlices是围绕球体排列的三角形对数
    3 void gltMakeSphere(GLTriangleBatch& sphereBatch, GLfloat fRadius, GLint iSlices, GLint iStacks);

    大球的旋转上,首先设置一个定时器,通过这个定时器得到弧度,再通过大球的绘制配合旋转方法实现大球的自转。

    1 static GLfloat vTorusColor[] = { 1.0f, 0.0f, 0.0f, 1.0f };
    2 //设置点光源位置
    3 M3DVector4f vLightPos = {0,10,10,1};
    4 modelViewMatrix.Translate(0.0f, 0.2f, -3.0f);
    5 modelViewMatrix.PushMatrix();
    6 modelViewMatrix.Rotate(yRot, 0, 1, 0);
    7 shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF,transform Pipeline.GetModelViewMatrix(),transformPipeline.GetProjectionMatrix(),vLightPos,vTorusColor);
    8 torusBatch.Draw();
    9 modelViewMatrix.PopMatrix();
    • Translate:移动一段距离,便于观察
    • PushMatrix:拷贝矩阵堆栈栈顶并压栈
    • Rotate:大球围绕y轴旋转,实现自转

    3.绘制小球

    小球的绘制和大球步骤是一样的,首先SetupRC函数,初始化小球的顶点数据

     1 // 设置小球球模型
     2     gltMakeSphere(sphereBatch, 0.1f, 13, 26);
     3     // 随机位置放置小球
     4     for (int i = 0; i < NUM_SPHERES; i++) {
     5         
     6         //y轴不变,X,Z产生随机值
     7         GLfloat x = ((GLfloat)((rand() % 400) - 200 ) * 0.1f);
     8         GLfloat z = ((GLfloat)((rand() % 400) - 200 ) * 0.1f);
     9         
    10         //在y方向,将球体设置为0.0的位置,这使得它们看起来是飘浮在眼睛的高度
    11         //对spheres数组中的每一个顶点,设置顶点数据
    12         spheres[i].SetOrigin(x, 0.0f, z);
    13     }

    然后RenderScene绘制:

     1 // 画小球
     2     for (int i = 0; i < NUM_SPHERES; i++) {
     3         modelViewMatrix.PushMatrix();
     4         modelViewMatrix.MultMatrix(spheres[i]);
     5         shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF, transformPipeline.GetModelViewMatrix(),
     6                                      transformPipeline.GetProjectionMatrix(), vLightPos, vSphereColor);
     7         sphereBatch.Draw();
     8         modelViewMatrix.PopMatrix();
     9         
    10     }

    多个静态小球,每绘制一个小球都需要进行push和pop操作。

    4.让小蓝球围着大红球转起来

    1 // 让小蓝球围绕大球转起来
    2     modelViewMatrix.Rotate(yRot * -2.0f, 0.0f, 1.0f, 0.0f);
    3     modelViewMatrix.Translate(0.8f, 0.0f, 0.0f);
    4     shaderManager.UseStockShader(GLT_SHADER_FLAT,transformPipeline.GetModelViewProjectionMatrix(),vSphereColor);
    5     sphereBatch.Draw();

    这个案例的重点和难点,就在RenderScene函数里面的矩阵堆栈的理解。

    在OpenGL 的维度:

    变换顶点向量 = M_pro * M_view * M_model * V_local

    变换顶点向量 = 投影矩阵 ✖ 视图变换矩阵 ✖ 模型矩阵 ✖ 顶点

     

    • 使用PushMatrix方法,会将栈顶信息复制一份,放入栈顶。
    • 使用MultMatrix方法做矩阵相乘时,将该矩阵与栈顶矩阵相乘,覆盖栈顶矩阵。
    • 使用PopMatrix做出栈操作时,移除栈顶矩阵对象。(根据栈的特点,只能pop栈顶) 

     

    后续的移动操作就是在增加特殊键位的移动即可

     1 void SpeacialKeys(int key,int x,int y){
     2     
     3     float linear = 0.1f;
     4     float angular = float(m3dDegToRad(5.0f));
     5     
     6     if (key == GLUT_KEY_UP) {
     7         cameraFrame.MoveForward(linear);
     8     }
     9     if (key == GLUT_KEY_DOWN) {
    10         cameraFrame.MoveForward(-linear);
    11     }
    12     
    13     if (key == GLUT_KEY_LEFT) {
    14         cameraFrame.RotateWorld(angular, 0, 1, 0);
    15     }
    16     if (key == GLUT_KEY_RIGHT) {
    17         cameraFrame.RotateWorld(-angular, 0, 1, 0);
    18     }
    19 
    20 }
  • 相关阅读:
    UnityShaderVariant的一些探究心得
    NGUI在使用AssetBubble 出现材质丢失错误的情况
    [转] unity调试lua工具和方法
    各种文件的mime类型
    Javascript 随机数
    jQuery文字上下滚动
    Asp.Net Color转换
    Asp.Net 清除Html标签
    jQuery Ajax实例
    Asp.Net Cookie用法
  • 原文地址:https://www.cnblogs.com/hadyt/p/13346706.html
Copyright © 2020-2023  润新知