专注于 JetBrains IDEA 全家桶,永久激活,教程
持续更新 PyCharm,IDEA,WebStorm,PhpStorm,DataGrip,RubyMine,CLion,AppCode 永久激活教程

案例:图元绘制

该文章主要针对OpenGL渲染正方形&平移文中的绘制连接方式的运用.

51_1.png

绘制流程

整体的绘制流程,仍旧主要使用了main函数,ChangeSize函数,SetupRC函数,RenderScene函数;

main函数

自定义函数的注册以及glutMainLoop,进入GLUT事件处理循环

SetupRC函数

上下文中进行必要的初始化

  • 背景颜色
  • 固定着色器初始化
shaderManager.InitializeStockShaders();

  • 顶点数据的创建和传输
// 例如 `GL_POINTS` 点的绘制方式
GLfloat vCoast[9] = {
        3,3,0,
        0,3,0,
        3,0,0
    };
// 提交批次类pointBatch
// 1.点 
pointBatch.Begin(GL_POINTS, 3);
//copy方法会将顶点数据传输到着色器中
pointBatch.CopyVertexData3f(vCoast);
pointBatch.End();

  • 设置变换管道
// 初始化几何变换的管道
GLGeometryTransform transformPipeline;

//模型视图矩阵栈与投影矩阵栈放到变换管道中,可以帮助快速进行矩阵相乘,在RenderScene函数中可以直接通过变换管道的Get方法得到相应的矩阵结果
transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);

51_2.png

  • 设置观察者的位置
// 观察者位置 负数=拉远观察者的位置
cameraFrame.MoveForward(-15.0f); 

ChangeSize函数

  • 在setupRC对图形绘制做初始化后,调用设置视口,当改变屏幕窗口时也会调用,重新设置.
  • 创建投影矩阵,将它载入投影矩阵栈中
//投影矩阵
GLFrustum           viewFrustum;
//投影矩阵栈
GLMatrixStack       projectionMatrix;   
/*
     SetPerspective:设置透视投影
     void SetPerspective(float fFov, float fAspect, float fNear, float fFar)
     * fFov:眼睛打开的角度 
     * fAspect:纵横比 w/h
     * fNear:近裁剪面距离
     * fFar:远距离
     SetOrthographic:是设置正投影
 */
    viewFrustum.SetPerspective(35.0f, float(w)/float(h), 1.0f, 500.0f);

    // viewFrustum.GetProjectionMatrix() 获取投影矩阵
    // LoadMatrix 加载存储到投影矩阵栈
    projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());

因为我们同样需要模型矩阵的数据,将投影矩阵和模型矩阵相乘后,才是最终绘制的矩阵数据,所以此处先将投影矩阵存入投影矩阵栈中.

RenderScene函数

在图元绘制案例中,RenderScene中需要将观察者矩阵和物体矩阵相乘后,存储在模型视图矩阵栈,根据变换管道的get方法获取相应的矩阵,进行渲染.

  • 首先会在模型视图矩阵栈中压入一个单元矩阵,作用类似1,与任何数据相乘,数据都不变
  • 将观察者矩阵放到模型视图矩阵栈中
// 观察者矩阵初始化变量
GLFrame cameraFrame;   

M3DMatrix44f mCamera;
cameraFrame.GetCameraMatrix(mCamera);
// 矩阵乘以矩阵堆栈的顶部矩阵,相乘的结果 存储在栈的顶部
modelViewMatrix.MultMatrix(mCamera);

  • 将物体矩阵放到模型视图矩阵栈中
// 物体矩阵初始化变量
GLFrame objectFrame;        

M3DMatrix44f mObjectFrame;
// 只要使用GetMatrix 函数就可以获取矩阵栈顶部的值。 这个函数可以进行2次重载,用来使用GLShaderManager的使用,或者是获取顶部矩阵的顶点副本数据
objectFrame.GetMatrix(mObjectFrame);
// 矩阵乘以矩阵堆栈的顶部矩阵,相乘的结果 存储在栈的顶部
modelViewMatrix.MultMatrix(mObjectFrame);

  • 渲染从变换管道中get到的矩阵
/**
 GLShaderManager 中的Uniform 值 -- 平面着色器
 参数1:平面着色器
 参数2:运行为几何图形变换 指定一个 4*4 变换矩阵 -- transformPipeline.GetModelViewProjectionMatrix() 获取的  GetMatrix函数就可以获得矩阵堆栈顶部的值  它是一个变换矩阵
 参数3:颜色值
 */
shaderManager.UseStockShader(GLT_SHADER_FLAT,transformPipeline.GetModelViewProjectionMatrix(),vBlack);

变换管道transformPipeline可通过get到的矩阵有四种:

方式 矩阵
GetProjectionMatrix() 投影矩阵
GetNormalMatrix() 法线矩阵
GetModelViewMatrix() 模型视图矩阵
GetModelViewProjectionMatrix() 模型视图投影矩阵
  • 渲染后记得要将模型视图矩阵中相乘的结果进行出栈,恢复栈顶为默认的单元矩阵

51_3.png

辅助函数有:

  • SpecialKeys:对特殊键位的回调处理,上下左右
  • KeyPressFunc:对空格键的回调处理
  • DrawWireFrameBatch:对立体图形的填充,边框绘制

图元绘制方式

GL_POINTS 点

// 点初始化
GLBatch             pointBatch;         

//setupRC中构建顶点数据以及传输
GLfloat vCoast[9] = {
    3,3,0,
    0,3,0,
    3,0,0
};

// 1.点
pointBatch.Begin(GL_POINTS, 3);
pointBatch.CopyVertexData3f(vCoast);
pointBatch.End();

//RenderScene中绘制
//设置点的大小
glPointSize(4.0f);
pointBatch.Draw();
glPointSize(1.0f); // 恢复

51_4.png

GL_LINES 线段

// 线初始化
GLBatch             lineBatch;          

//setupRC中构建顶点数据同样使用上边vCoast的顶点数据
// 2.线
lineBatch.Begin(GL_LINES, 3);
lineBatch.CopyVertexData3f(vCoast);
lineBatch.End();

//RenderScene中
glLineWidth(2.0f);
lineBatch.Draw();
glLineWidth(1.0f);

// GL_LINES是对每一对顶点定义线段,只有三个点,所有绘制了一条线

51_5.png

GL_LINE_STRIP线环

// 初始化线段
GLBatch             lineStripBatch;     

//SetupRC中
// 3.线段
lineStripBatch.Begin(GL_LINE_STRIP, 3);
lineStripBatch.CopyVertexData3f(vCoast);
lineStripBatch.End();

//RenderScene
// 线段
glLineWidth(2.0f);
lineStripBatch.Draw();
glLineWidth(1.0f);

//GL_LINE_STRIP 从第一个顶点以此经过每一个后续顶点绘制的线条

51_6.png

GL_LINE_LOOP

// 初始化
GLBatch             lineLoopBatch;

// SetupRC中
// 4.线环
lineLoopBatch.Begin(GL_LINE_LOOP, 3);
lineLoopBatch.CopyVertexData3f(vCoast);
lineLoopBatch.End();

// RenderScene中
glLineWidth(2.0f);
lineLoopBatch.Draw();
glLineWidth(1.0f);

// GL_LINE_LOOP 会将第一个顶点和最后一个顶点进行连接构成环

51_7.png

triangleBatch

// 初始化
GLBatch             triangleBatch;

// SetupRC中
// 5.三角形
    GLfloat vPyramid[12][3] = {
        -2.0f, 0.0f, -2.0f,
        2.0f, 0.0f, -2.0f,
        0.0f, 4.0f, 0.0f,

        2.0f, 0.0f, -2.0f,
        2.0f, 0.0f, 2.0f,
        0.0f, 4.0f, 0.0f,

        2.0f, 0.0f, 2.0f,
        -2.0f, 0.0f, 2.0f,
        0.0f, 4.0f, 0.0f,

        -2.0f, 0.0f, 2.0f,
        -2.0f, 0.0f, -2.0f,
        0.0f, 4.0f, 0.0f

    };

    triangleBatch.Begin(GL_TRIANGLES, 12);
    triangleBatch.CopyVertexData3f(vPyramid);
    triangleBatch.End();

// RenderScene中会调用DrawWireFramedBatch方法,对立体图形中的面和边框进行绘制

特殊键位调整后

51_8.png

GL_TRIANGLE_FAN 三角形扇

//初始化
GLBatch             triangleFanBatch;

// 6.三角形扇面-六边形
    // 初始化顶点数组
    GLfloat vPoints[100][3];
    int nVerts = 0;
    // 半径
    GLfloat r = 3.0f;
    // 原点
    vPoints[nVerts][0] = 0.0f;
    vPoints[nVerts][1] = 0.0f;
    vPoints[nVerts][2] = 0.0f;

    // M3D_2PI 就是2Pi的意思 就是一个圆, 绘制圆
    // angle角度。 圆/6 = 360/60
    for (GLfloat angle = 0; angle < M3D_2PI; angle += M3D_2PI / 6.0f) {

        // 数组下标自增 ,每次自增代表一个顶点
        nVerts ++;

        // x点坐标 cos(angle) * 半径
        vPoints[nVerts][0] = float(cos(angle)) * r;
        // y点坐标 sin(angle) * 半径
        vPoints[nVerts][1] = float(sin(angle)) * r;
        // z点坐标
        vPoints[nVerts][2] = -0.5f;
    }

    // 结束扇形 前面循环中一共绘制了7个顶点(包括圆心)
    // 添加闭合的终点
    // 课程添加演示:
    nVerts ++;
    vPoints[nVerts][0] = r;
    vPoints[nVerts][1] = 0.0f;
    vPoints[nVerts][2] = 0.0f;

    // 加载
    triangleFanBatch.Begin(GL_TRIANGLE_FAN, 8);
    triangleFanBatch.CopyVertexData3f(vPoints);
    triangleFanBatch.End();

同样在RenderScene中调用DrawWireFramedBatch

51_9.png

GL_TRIANGLE_STRIP

//初始化
GLBatch             triangleStripBatch;

//SetupRC中
//7.三角形条带 一个小环或圆柱段
    // 初始化顶点下标
    int iCounter = 0;
    // 半径
    GLfloat radius = 3.0f;
    // 从0度到360度,以0.3弧度为步长
    for (GLfloat angle = 0.0f; angle <= (2.0f*M3D_PI); angle+=0.3f) {
        //获取圆形的顶点的X,Y
        GLfloat x = radius * sin(angle);
        GLfloat y = radius * cos(angle);

        //绘制2个三角形(他们的x,y顶点一样,只是z点不一样)
        vPoints[iCounter][0] = x;
        vPoints[iCounter][1] = y;
        vPoints[iCounter][2] = -0.5;
        iCounter++;

        vPoints[iCounter][0] = x;
        vPoints[iCounter][1] = y;
        vPoints[iCounter][2] = 0.5;
        iCounter++;
    }

    // 关闭循环
    printf("三角形带的顶点数:%d\n",iCounter);
    //结束循环,在循环位置生成2个三角形
    vPoints[iCounter][0] = vPoints[0][0];
    vPoints[iCounter][1] = vPoints[0][1];
    vPoints[iCounter][2] = -0.5;
    iCounter++;

    vPoints[iCounter][0] = vPoints[1][0];
    vPoints[iCounter][1] = vPoints[1][1];
    vPoints[iCounter][2] = 0.5;
    iCounter++;

    triangleStripBatch.Begin(GL_TRIANGLE_STRIP, iCounter);
    triangleStripBatch.CopyVertexData3f(vPoints);
    triangleStripBatch.End();

RenderScene中调用DrawWireFramedBatch

51_10.png

推荐:

文章永久链接:https://tech.souyunku.com/31386

未经允许不得转载:搜云库技术团队 » 案例:图元绘制

JetBrains 全家桶,激活、破解、教程

提供 JetBrains 全家桶激活码、注册码、破解补丁下载及详细激活教程,支持 IntelliJ IDEA、PyCharm、WebStorm 等工具的永久激活。无论是破解教程,还是最新激活码,均可免费获得,帮助开发者解决常见激活问题,确保轻松破解并快速使用 JetBrains 软件。获取免费的破解补丁和激活码,快速解决激活难题,全面覆盖 2024/2025 版本!

联系我们联系我们