OpenGL 随笔

2023-12-27 17:47:01

GLTools

GLTools是一款OpenGL驱动程序和3D优化及伪装显卡参数的应用,可以模拟Tegra以支持部分挑剔的游戏,对手机系统进行优化,支持在手机上模拟GPU和CPU,从而去玩一些某种处理器的专属游戏,保障大型游戏运行的流畅性。

GLTools应用支持对每个软件做出单独设置(需root权限),如果在使用中机器遇到了问题,可以在Recovery中使用自带的uninstall_gltools.zip进行卸载。

需要注意的是,使用GLTools软件可能存在一定的风险,请谨慎使用。

GLMatrixStack

GLMatrixStack是OpenGL中用于管理矩阵堆栈的类,其特性是先进后出。该类的主要函数包括:

  • LoadIdentity():调用顶部载入单元矩阵。

  • LoadMatrix(const M3DMatrix44f mMatrix):向矩阵堆栈中压入一个矩阵,与PushMatrix相同。
  • PushMatrix(const M3DMatrix44f mMatrix):向矩阵堆栈中压入一个矩阵。
  • PopMatrix():向矩阵堆栈中推出矩阵

通过使用GLMatrixStack类,可以在OpenGL程序中轻松地管理多个矩阵,并在需要时进行加载、压入和弹出操作。这在处理复杂的变换和渲染逻辑时非常有用。

要使用GLMatrixStack类来进行矩阵的加载、压入和弹出操作,可以按照以下步骤进行:

  • 加载单元矩阵:调用LoadIdentity()函数在堆栈顶部载入一个单元矩阵。
  • 加载任意矩阵:调用LoadMatrix(const M3DMatrix44f m)函数在堆栈顶部载入一个4*4矩阵。
  • 矩阵相乘:调用MultMatrix(const M3DMatrix44f m)函数可以将矩阵乘以堆栈顶部矩阵,相乘结果存储到堆栈的顶部。
  • 获取矩阵堆栈顶部的值:可以调用GetMatrix()函数获取堆栈顶部的值,该函数有两种形式,一种是为了适应GLShaderManager的使用,另一种是获取顶部矩阵的副本。
  • 压栈:可以调用PushMatrix()函数将当前矩阵压入堆栈,该函数表示将所有矩阵依次压入堆栈中,顶部矩阵是第二个矩阵的备份。
  • 出栈:调用PopMatrix()函数将堆栈顶部的矩阵弹出,令原第二个矩阵成为顶部矩阵,接受当前操作,故原顶部矩阵被破坏。当堆栈中仅存一个矩阵时,不能进行弹出操作,否则会出错。

除了GLMatrixStack类,还有其他一些类可以用于管理矩阵堆栈,例如:

  • OpenGlFrame类:用于管理帧的相关操作,其中包括矩阵堆栈的操作。
  • OpenGlFrustum类:用于管理视锥体的相关操作,其中包括矩阵堆栈的操作。
  • OpenGlGeometryTransform类:用于管理几何变换的相关操作,其中包括矩阵堆栈的操作。

这些类的具体使用方法可能因具体的应用场景和需求而有所不同。如果你需要使用矩阵堆栈管理,可以根据你所使用的图形库或框架来选择适合的类。

UseStockShader(GLT_STOCK_SHADER nShaderID, ...)

?

UseStockShader(GLT_STOCK_SHADER nShaderID, ...)?是一个函数调用,用于在计算机图形学中使用库存着色器(Stock Shader)。

参数解释:

  • GLT_STOCK_SHADER nShaderID:指定要使用的库存着色器的 ID。nShaderID是一个枚举值,代表不同类型的库存着色器。
  • ...:可变数量的参数,具体取决于所选的库存着色器。

这个函数通常用于在图形渲染引擎中快速应用一些常见的着色效果,而无需编写自定义的着色器代码。库存着色器是预定义的、可重用的着色器,它们提供了一些基本的渲染效果,例如平面着色、光照模型、纹理映射等。

通过调用UseStockShader函数,并传递相应的库存着色器 ID 和可能的参数,你可以在渲染场景时应用相应的着色效果。这样可以简化渲染设置,提高开发效率。

    //**4、绘制悬浮球体
    //使用sphereBatch 绘制。
    //思路:循环绘制50个蓝色悬浮球体,绘制一个压栈一个,绘制完成出栈一个
    for (int i = 0; i < NUM_SPHERES; i++) {
        //shaderManager.UseStockShader(GLT_SHADER_FLAT,transformPipeline.GetModelViewProjectionMatrix(),vSphereColor);
        //**4、绘制光源,修改着色器管理器
        /**绘制光源,修改着色器管理器
         参数1:GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF
         参数2:模型视图矩阵
         参数3:投影矩阵
         参数4:视点坐标系中的光源位置
         参数5:基本漫反射颜色
         参数6:颜色
         */
        
        
        modelViewMatrix.PushMatrix();
        modelViewMatrix.MultMatrix(spheres[i]);
        
        shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF,transformPipeline.GetModelViewMatrix(),
                                     transformPipeline.GetProjectionMatrix(),vLightEyePos,vSphereColor);
        sphereBatch.Draw();
        modelViewMatrix.PopMatrix();
    }

GLBatch

GLBatch是GLTools中的一个简单容器类,利用它可以传输顶点/光照/纹理/颜色数据到存储着色器中。它可以作为7种几何图元简单批次容器使用,而且它知道如何在使用

支持的任意存储着色器时对图元进行渲染。

GLShaderManager

GLShaderManager 是一个用于管理和加载 OpenGL 着色器的类,它提供了一种方便的方式来组织和管理多个着色器程序。

它的主要功能包括:

  • 加载和编译着色器源代码:GLShaderManager 可以从文件加载着色器的源代码,并使用 OpenGL API 编译它们。
  • 管理着色器程序:GLShaderManager 可以存储已编译的着色器程序,并提供方法来获取和使用这些程序。
  • 绑定和链接着色器:GLShaderManager 可以将着色器程序与OpenGL 渲染上下文相关联,并将它们链接在一起以形成可执行的图形管道。
  • 管理uniform 变量:GLShaderManager 可以帮助管理着色器程序中的uniform 变量,并提供方法来设置和获取它们的值。

使用 GLShaderManager 可以简化着色器管理的任务,使开发人员能够更专注于图形渲染的其他方面。

如何使用GLShaderManager类加载和编译着色器源代码?

要使用GLShaderManager类加载和编译着色器源代码,你可以按照以下步骤进行操作:

? ? ?1.创建GLShaderManager对象:首先,你需要创建一个GLShaderManager对象来管理着色器。

  • GLShaderManager shaderManager;
  • 2.加载着色器源代码:使用GLShaderManageraddShader方法加载你的顶点着色器和片段着色器的源代码。
  • shaderManager.addShader(GL_VERTEX_SHADER, "vertex_shader.glsl");
    shaderManager.addShader(GL_FRAGMENT_SHADER, "fragment_shader.glsl");

    这里的vertex_shader.glslfragment_shader.glsl是你的着色器源代码文件的路径。

  • 3. 编译着色器:调用GLShaderManagerlinkShaders方法来编译并链接你加载的着色器。
shaderManager.linkShaders();

4.获取着色器程序:使用GLShaderManagergetShaderProgram方法获取已编译和链接的着色器程序。

GLuint shaderProgram = shaderManager.getShaderProgram();

5.使用着色器程序:将获取到的着色器程序与OpenGL 渲染上下文关联,并使用它进行图形渲染

glUseProgram(shaderProgram);
class GLShaderManager
	{
	public:
		GLShaderManager(void);
		~GLShaderManager(void);
		
		// Call before using
		bool InitializeStockShaders(void);
	
		// Find one of the standard stock shaders and return it's shader handle. 
		GLuint GetStockShader(GLT_STOCK_SHADER nShaderID);

		// Use a stock shader, and pass in the parameters needed
		GLint UseStockShader(GLT_STOCK_SHADER nShaderID, ...);

		// Load a shader pair from file, return NULL or shader handle. 
		// Vertex program name (minus file extension)
		// is saved in the lookup table
		GLuint LoadShaderPair(const char *szVertexProgFileName, const char *szFragProgFileName);

		// Load shaders from source text.
		GLuint LoadShaderPairSrc(const char *szName, const char *szVertexSrc, const char *szFragSrc);

		// Ditto above, but pop in the attributes
		GLuint LoadShaderPairWithAttributes(const char *szVertexProgFileName, const char *szFragmentProgFileName, ...);
		GLuint LoadShaderPairSrcWithAttributes(const char *szName, const char *szVertexProg, const char *szFragmentProg, ...);

		// Lookup a previously loaded shader
		GLuint LookupShader(const char *szVertexProg, const char *szFragProg = 0);
	
	protected:
		GLuint	uiStockShaders[GLT_SHADER_LAST];
//		vector <SHADERLOOKUPETRY>	shaderTable;

	};

GLFrame

“GLFrame”类是OpenGL中用于表示物体或观察者的坐标的类。它提供了旋转、移动的函数,如“MoveForward”“MoveUp”和“MoveRight”,以及“RotateWorld”式的旋转函数,可以快速完成平移和旋转操作。

GLFrame类还可以存储世界坐标系中任意物体的位置和方向。它包含一个世界坐标点和两个世界坐标下的方向向量,分别表示当前位置点、向前方向向量和向上方向向量。无论是相机还是模型,都可以使用GLFrame来表示。

如何使用GLFrame类进行物体的旋转和移动?

要使用GLFrame类进行物体的旋转和移动,你可以按照以下步骤进行操作:

  1. 创建GLFrame对象:使用GLFrame类的构造函数创建一个GLFrame对象,并设置其初始位置和方向。

  2. 使用旋转函数:GLFrame类提供了多个旋转函数,如RotateWorld、RotateX、RotateY和RotateZ等,你可以根据需要选择合适的函数来旋转物体。

  3. 使用移动函数:GLFrame类提供了多个移动函数,如MoveForward、MoveUp和MoveRight等,你可以根据需要选择合适的函数来移动物体。

  4. 更新GLFrame对象:在每次旋转或移动后,使用GLFrame对象的函数来更新其位置和方向,以反映物体的新位置和方向。

  5. 渲染物体:在每次更新GLFrame对象后,使用OpenGL函数将其位置和方向传递给渲染管线,以绘制旋转或移动后的物体

请注意,具体的实现方式可能因你使用的OpenGL库或框架而有所不同,但基本原理和步骤应该是相似的。

static void SpecialFunc(int key, int x, int y) {
    float linear = 0.1f;
    float angular = float(m3dDegToRad(5.0f));
    
    if (key == GLUT_KEY_UP) {
       
        //MoveForward 平移
        cameraFrame.MoveForward(linear);
    }
    
    if (key == GLUT_KEY_DOWN) {
        cameraFrame.MoveForward(-linear);
    }
    
    if (key == GLUT_KEY_LEFT) {
        //RotateWorld 旋转
        cameraFrame.RotateWorld(angular, 0.0f, 1.0f, 0.0f);
    }
    
    if (key == GLUT_KEY_RIGHT) {
        cameraFrame.RotateWorld(-angular, 0.0f, 1.0f, 0.0f);
    }

}

GLGeometryTransform

GLGeometryTransform类是用于在OpenGL中进行几何变换的类,它提供了一些函数来对顶点坐标进行平移、旋转和缩放等操作。

static void glutShape(int w, int h) {
    if (h == 0) {
        h == 1.0f;
    }
    glViewport(0, 0, w, h);
    
    /// 创建投影矩阵
    viewFrustum.SetPerspective(35.0f,  float(w)/float(h), 1.0f, 100.0f);
    //viewFrustum.GetProjectionMatrix()  获取viewFrustum投影矩阵
    //并将其加载到投影矩阵堆栈上
    projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
    // 设置变换管道以使用两个矩阵堆栈(变换矩阵modelViewMatrix ,投影矩阵projectionMatrix)
    //初始化GLGeometryTransform 的实例transformPipeline.通过将它的内部指针设置为模型视图矩阵堆栈 和 投影矩阵堆栈实例,来完成初始化
    //当然这个操作也可以在SetupRC 函数中完成,但是在窗口大小改变时或者窗口创建时设置它们并没有坏处。而且这样可以一次性完成矩阵和管线的设置。

    transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
    
    
}


        shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF,transformPipeline.GetModelViewMatrix(),
                                     transformPipeline.GetProjectionMatrix(),vLightEyePos,vSphereColor);

投影矩阵和模型视图矩阵

投影矩阵和模型视图矩阵在计算机图形学中是用于将三维场景转换为二维屏幕坐标的重要矩阵。

投影矩阵负责将三维坐标投影到二维平面上,通常用于定义相机的视野范围、纵横比以及近裁剪平面和远裁剪平面等参数。它将场景中的物体从三维空间映射到相机的视口中,并根据相机的位置和方向进行缩放和扭曲。

模型视图矩阵则是将物体的三维坐标转换为相对于相机的坐标。它结合了模型矩阵和视图矩阵的变换,用于将物体从其本地坐标系转换到相机坐标系中。模型矩阵用于表示物体的缩放、旋转和平移等变换,而视图矩阵则用于表示相机的位置和方向。

在渲染过程中,首先应用模型视图矩阵将物体转换到相机坐标系中,然后应用投影矩阵将其投影到二维屏幕上。这两个矩阵的乘积共同确定了每个像素在屏幕上的位置和深度信息,从而实现了三维场景的可视化

在 OpenGL 中,应用投影矩阵和模型视图矩阵需要进行以下步骤:

  1. 设置投影矩阵:使用glMatrixMode函数将当前矩阵模式设置为投影矩阵(通常是GL_PROJECTION)。

  2. 加载投影矩阵:使用glLoadIdentity函数将投影矩阵重置为单位矩阵。

  3. 设置相机参数:根据需要设置相机的视野范围(field of view)、纵横比(aspect ratio)、近裁剪平面和远裁剪平面等参数。

  4. 创建并应用投影矩阵:使用glOrthoglPerspective等函数创建适当的投影矩阵,并使用glMultMatrix函数将其应用到当前矩阵。

  5. 设置模型视图矩阵:使用glMatrixMode函数将当前矩阵模式设置为模型视图矩阵(通常是GL_MODELVIEW)。

  6. 加载模型视图矩阵:使用glLoadIdentity函数将模型视图矩阵重置为单位矩阵。

  7. 设置模型和相机位置:根据需要设置模型的位置、旋转和缩放,以及相机的位置和方向。

  8. 创建并应用模型视图矩阵:使用glTranslateglRotateglScale等函数创建模型视图矩阵,并使用glMultMatrix函数将其应用到当前矩阵。】

  9. 通过以上步骤,你可以在 OpenGL 中正确地应用投影矩阵和模型视图矩阵,从而实现对三维场景的渲染。具体的实现方式可能因编程语言和上下文而有所不同,但基本原理是相同的。

GetModelViewMatrix

GetModelViewMatrix是指获取模型视图矩阵,它是一种用于在计算机图形学和3D渲染中变换场景和视图的矩阵。

在渲染图形时,为了将3D场景中的物体正确地显示在屏幕上,需要将场景中每个物体的位置、方向和大小等信息变换为屏幕坐标系中的坐标。这个过程需要使用模型视图矩阵来进行变换。

模型视图矩阵是一个的矩阵,其中包含了用于变换坐标系的四个基本向量。这四个基本向量的取值不同,可以组合成不同的矩阵,从而变换出不同的视图方向。

在OpenGL中,如何使用模型视图矩阵?

  1. 创建一个模型视图矩阵:使用glMatrixMode函数将当前矩阵模式设置为模型视图矩阵(通常是GL_MODELVIEW)。

  2. 加载模型视图矩阵:使用glLoadIdentity函数将模型视图矩阵重置为单位矩阵。

  3. 设置相机位置和方向:使用glTranslateglRotateglScale等函数来设置相机的位置和方向。

  4. 将模型视图矩阵乘以投影矩阵:使用glMultMatrix函数将模型视图矩阵乘以投影矩阵,以获得最终的变换矩阵。

  5. 使用最终的变换矩阵:在绘制物体时,使用最终的变换矩阵来进行坐标变换。

GetProjectionMatrix

GetProjectionMatrix?是一个在计算机图形学和 3D 渲染中常见的函数调用,用于获取投影矩阵。

投影矩阵用于将 3D 坐标转换为 2D 坐标,以便在屏幕上显示。它定义了相机的视野、纵横比和近裁剪平面、远裁剪平面等参数。

具体的实现方式和参数可能因编程语言和图形库而有所不同。以下是在一些常见的图形库或 API 中的示例:

OpenGL:在 OpenGL 中,可以使用?glGetProjectionMatrix()?函数来获取当前的投影矩阵。你可以在 C++ 中通过调用该函数来获取投影矩阵,并将其存储在一个矩阵对象中进行后续操作。

Unity:在 Unity 游戏引擎中,可以通过?Camera.main.projectionMatrix?属性来获取主相机的投影矩阵。

DirectX:在 DirectX 中,可以使用?ID3D11DeviceContext::GetProjectionMatrix()?方法来获取当前的投影矩阵。

#include "GLTools.h"
#include "GLBatch.h"
#include "GLMatrixStack.h"
#include "GLShaderManager.h"
#include "GLFrame.h"
#include "GLFrustum.h"
#include "StopWatch.h"
#include "GLGeometryTransform.h"
#ifdef __APPLE__
#include <GLUT/GLUT.h>
#else
#include <GL/glut.h>
#endif
static GLShaderManager shaderManager; // 着色器管理器
static GLMatrixStack modelViewMatrix; // 模型视图矩阵
static GLMatrixStack projectionMatrix; // 投影矩阵
static GLFrustum     viewFrustum;      // 视景体
static GLGeometryTransform transformPipeline; // 几何图形变换管道

static GLTriangleBatch        torusBatch;             // 花托批处理
static GLBatch                floorBatch;             // 地板批处理
//**定义公转球的批处理(公转自转)**
static GLTriangleBatch     sphereBatch;            //球批处理
//角色帧 照相机角色帧
static GLFrame             cameraFrame;

//**4、添加附加随机球
#define NUM_SPHERES 50
static GLFrame spheres[NUM_SPHERES];

static void SpecialFunc(int key, int x, int y) {
    float linear = 0.1f;
    float angular = float(m3dDegToRad(5.0f));
    
    if (key == GLUT_KEY_UP) {
       
        //MoveForward 平移
        cameraFrame.MoveForward(linear);
    }
    
    if (key == GLUT_KEY_DOWN) {
        cameraFrame.MoveForward(-linear);
    }
    
    if (key == GLUT_KEY_LEFT) {
        //RotateWorld 旋转
        cameraFrame.RotateWorld(angular, 0.0f, 1.0f, 0.0f);
    }
    
    if (key == GLUT_KEY_RIGHT) {
        cameraFrame.RotateWorld(-angular, 0.0f, 1.0f, 0.0f);
    }

}
static void glutKeyboardFunc(unsigned char key, int x, int y) {
    
    
}
static void glutShape(int w, int h) {
    if (h == 0) {
        h == 1.0f;
    }
    glViewport(0, 0, w, h);
    viewFrustum.SetOrthographic(0.0,  23, 10.0, 22.0, 22.0, 23.0);
    /// 创建投影矩阵
    viewFrustum.SetPerspective(35.0f,  float(w)/float(h), 1.0f, 100.0f);
    //viewFrustum.GetProjectionMatrix()  获取viewFrustum投影矩阵
    //并将其加载到投影矩阵堆栈上
    projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
    // 设置变换管道以使用两个矩阵堆栈(变换矩阵modelViewMatrix ,投影矩阵projectionMatrix)
    //初始化GLGeometryTransform 的实例transformPipeline.通过将它的内部指针设置为模型视图矩阵堆栈 和 投影矩阵堆栈实例,来完成初始化
    //当然这个操作也可以在SetupRC 函数中完成,但是在窗口大小改变时或者窗口创建时设置它们并没有坏处。而且这样可以一次性完成矩阵和管线的设置。

    transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
    
    
}
static void loadData() {
     /// 着色管理器初始化
    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, 500);
    for (GLfloat x = -20.0; x < 20.0f; x += 0.5f) {
        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、在场景中随机位置对球体进行初始化
    //随机放置球体
    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);
    }

    
}


static void RenderScene() {
    // 颜色值 地板颜色、甜甜圈颜色
    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);
    
    //将当前的模型视图矩阵压入矩阵堆栈(单位矩阵)
    //因为我们先绘制地面,而地面是不需要有任何变换的。所以在开始渲染时保证矩阵状态,然后在结束时使用相应的PopMatrix恢复它。这样就不必在每一次渲染时重载单位矩阵了。
    modelViewMatrix.PushMatrix();
    //**3、设置照相机矩阵
    M3DMatrix44f mCamera;
    //**3、从camraFrame中获取一个4*4的矩阵;
    cameraFrame.GetCameraMatrix(mCamera);
    //**3、将照相机矩阵压入模型视图堆栈中
    modelViewMatrix.PushMatrix(mCamera);
    //**4、添加光源
    //光源位置的全局坐标存储在vLightPos变量中,其中包含了光源位置x坐标、y坐标、z坐标和w坐标。我们必须保留w坐标为1.0。因为无法用一个3分量去乘以4*4矩阵。
    M3DVector4f vLightPos = {0.0f,10.0f,5.0f,1.0f};
    M3DVector4f vLightEyePos;
    //将照相机矩阵mCamera 与 光源矩阵vLightPos 相乘获得vLightEyePos 矩阵
    m3dTransformVector4(vLightEyePos, vLightPos,mCamera);
    
    shaderManager.UseStockShader(GLT_SHADER_FLAT,transformPipeline.GetModelViewProjectionMatrix(),vFloorColor);
    floorBatch.Draw();
    
    
    //**4、绘制悬浮球体
    //使用sphereBatch 绘制。
    //思路:循环绘制50个蓝色悬浮球体,绘制一个压栈一个,绘制完成出栈一个
    for (int i = 0; i < NUM_SPHERES; i++) {
        //shaderManager.UseStockShader(GLT_SHADER_FLAT,transformPipeline.GetModelViewProjectionMatrix(),vSphereColor);
        //**4、绘制光源,修改着色器管理器
        /**绘制光源,修改着色器管理器
         参数1:GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF
         参数2:模型视图矩阵
         参数3:投影矩阵
         参数4:视点坐标系中的光源位置
         参数5:基本漫反射颜色
         参数6:颜色
         */
        
        
        modelViewMatrix.PushMatrix();
        modelViewMatrix.MultMatrix(spheres[i]);
        
        shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF,transformPipeline.GetModelViewMatrix(),
                                     transformPipeline.GetProjectionMatrix(),vLightEyePos,vSphereColor);
        sphereBatch.Draw();
        modelViewMatrix.PopMatrix();
    }
    
    
    
    
    // 绘制旋转甜甜圈
    //modelViewMatrix 顶部矩阵沿着z轴移动2.5单位
    modelViewMatrix.Translate(0.0f, 0.0f, -2.5f);
    //**保存平移(公转自转)**
    modelViewMatrix.PushMatrix();
    //modelViewMatrix 顶部矩阵旋转yRot度
    modelViewMatrix.Rotate(yRot, 0.0f, 1.0f, 0.0f);
    //使用平面着色器 变换管道中的投影矩阵 和 变换矩阵 相乘的矩阵,指定甜甜圈颜色
    //shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(),vTorusColor);
    shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF, transformPipeline.GetModelViewMatrix(),
                                 transformPipeline.GetProjectionMatrix(), vLightEyePos, vTorusColor);
    //开始绘制
    torusBatch.Draw();
    
    
    // 恢复modelViewMatrix矩阵,移除矩阵堆栈
    //使用PopMatrix推出刚刚变换的矩阵,然后恢复到单位矩阵
    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);
    
    shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF, transformPipeline.GetModelViewMatrix(),
                                 transformPipeline.GetProjectionMatrix(), vLightEyePos, vSphereColor);

    sphereBatch.Draw();
    //**恢复矩阵(公转自转)**
    modelViewMatrix.PopMatrix();
    //**3、恢复矩阵
    modelViewMatrix.PopMatrix();

    // 执行缓存区交换
    glutSwapBuffers();
    
    // 告诉glut在显示一遍
    glutPostRedisplay();

}
int main(int argc,char *argv[]) {
    gltSetWorkingDirectory(argv[0]);
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH);
    glutInitWindowSize(800, 600);
    glutCreateWindow("window");
    
    GLenum error = glewInit();
    
    if (error != GLEW_OK) {
        printf("===============error=\%s\n",glewGetErrorString(error));
        return 1;
    }
    glutSpecialFunc(SpecialFunc);
    
    glutKeyboardFunc(glutKeyboardFunc);
    
    glutReshapeFunc(glutShape);
    
    glutDisplayFunc(RenderScene);
    loadData();
    
    glutMainLoop();
    return 0;
}

GLFrustum

GLFrustum是OpenGL类库中的函数,它是将当前矩阵与一个透视矩阵相乘,把当前矩阵转变成透视矩阵,在使用它之前,通常会先调用glMatrixMode(GL_PROJECTION)

其函数原型为void glFrustum(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near, GLdouble far);,参数用来确定视角边界的各个点。其中,leftright表示近裁剪平面的左右边界,bottomtop表示近裁剪平面的上下边界,nearfar表示离视点的远近。这些参数通常用于在三维图形渲染中设置相机的视角和投影方式,从而正确显示三维场景。

SetPerspective(float fFov, float fAspect, float fNear, float fFar)

SetPerspective(float fFov, float fAspect, float fNear, float fFar)?是一个在计算机图形学中常见的函数调用,用于设置透视投影矩阵。

参数解释:

  • fFov:表示视野的角度,通常以度为单位。它决定了相机可以看到的水平和垂直方向的视野范围。
  • fAspect:表示宽高比,即窗口的宽度与高度的比值。
  • fNear:表示近裁剪平面的距离。它定义了相机可以看到的最近距离。
  • fFar:表示远裁剪平面的距离。它定义了相机可以看到的最远距离。

这个函数通常用于在三维图形渲染中设置相机的视角和投影方式,以便正确显示三维场景。通过设置这些参数,你可以控制视野的大小、纵横比以及裁剪平面的位置,从而获得想要的投影效果。具体的实现方式可能因编程语言和图形库而有所不同,但基本概念是相似的。

static void glutShape(int w, int h) {
    if (h == 0) {
        h == 1.0f;
    }
    glViewport(0, 0, w, h);
    
    /// 创建投影矩阵
    viewFrustum.SetPerspective(35.0f,  float(w)/float(h), 1.0f, 100.0f);
    //viewFrustum.GetProjectionMatrix()  获取viewFrustum投影矩阵
    //并将其加载到投影矩阵堆栈上
    projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
    // 设置变换管道以使用两个矩阵堆栈(变换矩阵modelViewMatrix ,投影矩阵projectionMatrix)
    //初始化GLGeometryTransform 的实例transformPipeline.通过将它的内部指针设置为模型视图矩阵堆栈 和 投影矩阵堆栈实例,来完成初始化
    //当然这个操作也可以在SetupRC 函数中完成,但是在窗口大小改变时或者窗口创建时设置它们并没有坏处。而且这样可以一次性完成矩阵和管线的设置。

    transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
    
    
}

SetOrthographic(GLfloat xMin, GLfloat xMax, GLfloat yMin, GLfloat yMax, GLfloat zMin, GLfloat zMax)?是一个在计算机图形学中常见的函数调用,用于设置正交投影矩阵。

参数解释:

? ?xMin?和?xMax:表示视野在 X 轴方向上的最小和最大坐标。

  • yMin?和?yMax:表示视野在 Y 轴方向上的最小和最大坐标。
  • zMin?和?zMax:表示视野在 Z 轴方向上的最小和最大坐标。

这个函数通常用于在三维图形渲染中设置相机的视野范围和投影方式,以便正确显示三维场景。通过设置这些参数,你可以控制视野的大小、纵横比以及裁剪平面的位置,从而获得想要的投影效果。具体的实现方式可能因编程语言和图形库而有所不同,但基本概念是相似的。

文章来源:https://blog.csdn.net/weixin_38432324/article/details/135249105
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。