绘制一个三角形,并制作移动动画(OPenGL+C++)

A.1从顶点构建对象(绘制一个三角形)

我们想要绘制的不仅仅是一个单独的点,而是由很多顶点组成的对象。现在让我们先用三个顶点来绘制一个三角形。

如何绘制呢?

  1. 修改顶点着色器,以便让3个不同的点输出到后续的管线阶段

  2. 修改glDrawArrays(),指定绘制的图形为三角形

代码实现:

1.修改vertShader.glsl文件

 //vertShader.glsl文件
 #version 430 
 void main(void) 
 {
     if(gl_VertexID == 0)//内置变量
         gl_Position = vec4(0.25, -0.25, 0.0, 1.0);
     else if(gl_VertexID == 1)
         gl_Position = vec4(-0.25, -0.25, 0.0, 1.0);
     else
         gl_Position = vec4(0.25, 0.25, 0.0, 1.0); 
 }

2.修改fragShader.glsl文件

 //fragShader.glsl文件
 #version 430   
 out vec4 color;   
 void main(void)   
 { 
     color = vec4(1.0, 0.0, 0.0, 1.0); 
 }

3.修改.cpp文件

//Display函数修改
 //glPointSize(430.0f);//设置点的大小
 glDrawArrays(GL_TRIANGLES, 0, 3);

4.运行结果输出

image-20231126183819536

5.cpp完整代码

 #include <GL/glew.h>
 #include <GLFW/glfw3.h>
 #include <iostream>
 #include <fstream>
 #include <string>
 #define numVAOs 1
 unsigned int renderingProgram;
 unsigned int vao[numVAOs];//顶点数组,必须要有
 unsigned int CreateShaderProgram();
 //读取文件中的GLSL的源代码
 std::string ReadShaderSource(const char* filePath)
 {
     std::string content;
     std::ifstream fileStream(filePath, std::ios::in);
     std::string line = "";
     while (!fileStream.eof())
     {
         getline(fileStream, line);
         content.append(line + '\n');
     }
     fileStream.close();
     return content;
 }
 ​
 //捕获GLSL代码编译失败信息函数
 void PrintShaderLog(unsigned int shader)
 {
     int len = 0;
     int chWrittn = 0;
     char* log;
     glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &len);
     if (len > 0)
     {
         log = (char*)malloc(len);
         glGetShaderInfoLog(shader, len, &chWrittn, log);
         std::cout << "Shader Info Log: " << log << std::endl;
         free(log);
     }
 }
 //捕获GLSL链接失败信息函数
 void PrintProgramLog(int prog)
 {
     int len = 0;
     int chWrittn = 0;
     char* log;
     glGetShaderiv(prog, GL_INFO_LOG_LENGTH, &len);
     if (len > 0)
     {
         log = (char*)malloc(len);
         glGetProgramInfoLog(prog, len, &chWrittn, log);
         std::cout << "Program Info Log: " << std::endl;
         free(log);
     }
 }
 //检查OpenGL错误函数
 bool CheckOpenGLError()
 {
     bool foundError = false;
     int glErr = glGetError();
     while (glErr != GL_NO_ERROR)
     {
         std::cout << "glError: " << glErr << std::endl;
         foundError = true;
         glErr = glGetError();
     }
     return foundError;
 }
 ​
 void Init(GLFWwindow* window)
 {
     renderingProgram = CreateShaderProgram();
     glGenVertexArrays(numVAOs, vao);//生成顶点数组对象名称,用numVAOs存储
     glBindVertexArray(vao[0]);//绑定vao[0]
 }
 ​
 void Display(GLFWwindow* window, double currentTime)
 {
     glUseProgram(renderingProgram);//激活程序对象
     //glPointSize(430.0f);//设置点的大小
     glDrawArrays(GL_TRIANGLES, 0, 3);//绘制方式,绘制三角形
 }
 unsigned int CreateShaderProgram()
 {
     //从文件读取GLSL代码
     std::string vertShaderStr = ReadShaderSource("./res/shaders/vertShader.glsl");
     std::string fragShaderStr = ReadShaderSource("./res/shaders/fragShader.glsl");
     const char* vertShaderSrc = vertShaderStr.c_str();
     const char* fragShaderSrc = fragShaderStr.c_str();
     //捕获编译着色器时的错误
     int vertComplied;
     int fragComplied;
     int linked;
     //创建顶点着色器和片段着色器
     unsigned int vShader = glCreateShader(GL_VERTEX_SHADER);
     unsigned int fShader = glCreateShader(GL_FRAGMENT_SHADER);
     //替换vShader,fShader中的源代码,使用自定义的编码
     glShaderSource(vShader, 1, &vertShaderSrc, NULL);
     glShaderSource(fShader, 1, &fragShaderSrc, NULL);
     //对着色器对象进行编译
     glCompileShader(vShader);
     CheckOpenGLError();
     glGetShaderiv(vShader, GL_COMPILE_STATUS, &vertComplied);
     if (vertComplied != 1)
     {
         std::cout << "vertex compilation faild" << std::endl;
         PrintShaderLog(vShader);
     }
     glCompileShader(fShader);
     CheckOpenGLError();
     glGetShaderiv(fShader, GL_COMPILE_STATUS, &fragComplied);
     if (fragComplied != 1)
     {
         std::cout << "fragment compilation faild" << std::endl;
         PrintShaderLog(fShader);
     }
     //创建一个Program链接着色器对象,执行的就是链接有着色器对象的程序
     unsigned int vfProgram = glCreateProgram();
     //把之前编译的着色器附加到程序对象上,然后用glLinkProgram链接它们
     glAttachShader(vfProgram, vShader);
     glAttachShader(vfProgram, fShader);
     glLinkProgram(vfProgram);
     CheckOpenGLError();
     glGetProgramiv(vfProgram, GL_LINK_STATUS, &linked);
     if (linked != 1)
     {
         std::cout << "linking faild" << std::endl;
         PrintProgramLog(vfProgram);
     }
     //返回连接好的着色器程序
     return vfProgram;
 }
 int main()
 {
     if (!glfwInit())
         exit(EXIT_FAILURE);
     glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
     glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
     GLFWwindow* window = glfwCreateWindow(600, 600, "Hello, world", nullptr, nullptr);
     glfwMakeContextCurrent(window);
 ​
     if (glewInit() != GLEW_OK)
         exit(EXIT_FAILURE);
     glfwSwapInterval(1);
 ​
     Init(window);
 ​
     while (!glfwWindowShouldClose(window))
     {
         Display(window, glfwGetTime());
         glfwSwapBuffers(window);
         glfwPollEvents();
     }
 ​
     glfwDestroyWindow(window);
     glfwTerminate();
     exit(EXIT_SUCCESS);
 }

A.2实现简单的场景动画

如何实现呢?

我们只需要定义一个变量,再定义一个变量增量,这样我们可以对那三个顶点的坐标的值加上变量的值,通过控制增量的变化来控制绘制出的三角形的移动。

代码实现:(沿X轴运动)

 //vertShader.glsl文件
 #version 430 
 uniform float offset;//声明一个全局的着色器变量
 void main(void) 
 {
     if(gl_VertexID == 0)
         gl_Position = vec4(0.25+offset, -0.25, 0.0, 1.0);
     else if(gl_VertexID == 1)
         gl_Position = vec4(-0.25+offset, -0.25, 0.0, 1.0);
     else
         gl_Position = vec4(0.25+offset, 0.25, 0.0, 1.0); 
 }
 //fragShader.glsl文件
 #version 430   
 out vec4 color;   
 void main(void)   
 { 
     color = vec4(1.0, 0.0, 0.0, 1.0); 
 }
 //.cpp文件新增全局变量
 float x = 0.0f;//X轴范围判断
 float inc = 0.01f;//X轴增量
 //修改.cpp文件中的Display函数
 void Display(GLFWwindow* window, double currentTime)
 {
     //不是必须的,我们在隐藏面消除需要同时用到颜色缓冲区和深度缓冲区
     // 每帧初始化深度缓冲区是必要的
     //确保深度对比不会受旧的深度的影响
     glClear(GL_DEPTH_BUFFER_BIT);
     glClearColor(0.0, 0.0, 1.0, 1.0);
     glClear(GL_COLOR_BUFFER_BIT);//相当于在设置显示区域的背景,比如此刻我将其设置为蓝色
     glUseProgram(renderingProgram);//激活程序对象
     x += inc;
     if (x > 1.0) inc = -inc;
     if (x < -1.0) inc = -inc;
     //指定要查询的程序对象为renderingProgram,查询其位置的统一变量的名称为offset
     unsigned int offsetLoc = glGetUniformLocation(renderingProgram, "offset");
     //为指定的程序对象指定统一变量的值,当前只有一个为offsetLoc,指定新值为x
     glProgramUniform1f(renderingProgram, offsetLoc, x);
     //glPointSize(430.0f);//设置点的大小
     glDrawArrays(GL_TRIANGLES, 0, 3);//绘制方式,绘制三角形
 }

 .cpp完整代码

//.cpp文件完整代码
 #include <GL/glew.h>
 #include <GLFW/glfw3.h>
 #include <iostream>
 #include <fstream>
 #include <string>
 #define numVAOs 1
 unsigned int renderingProgram;
 unsigned int vao[numVAOs];//顶点数组,必须要有
 unsigned int CreateShaderProgram();
 float x = 0.0f;//X轴范围判断
 float inc = 0.01f;//X轴增量
 //读取文件中的GLSL的源代码
 std::string ReadShaderSource(const char* filePath)
 {
     std::string content;
     std::ifstream fileStream(filePath, std::ios::in);
     std::string line = "";
     while (!fileStream.eof())
     {
         getline(fileStream, line);
         content.append(line + '\n');
     }
     fileStream.close();
     return content;
 }
 ​
 //捕获GLSL代码编译失败信息函数
 void PrintShaderLog(unsigned int shader)
 {
     int len = 0;
     int chWrittn = 0;
     char* log;
     glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &len);
     if (len > 0)
     {
         log = (char*)malloc(len);
         glGetShaderInfoLog(shader, len, &chWrittn, log);
         std::cout << "Shader Info Log: " << log << std::endl;
         free(log);
     }
 }
 //捕获GLSL链接失败信息函数
 void PrintProgramLog(int prog)
 {
     int len = 0;
     int chWrittn = 0;
     char* log;
     glGetShaderiv(prog, GL_INFO_LOG_LENGTH, &len);
     if (len > 0)
     {
         log = (char*)malloc(len);
         glGetProgramInfoLog(prog, len, &chWrittn, log);
         std::cout << "Program Info Log: " << std::endl;
         free(log);
     }
 }
 //检查OpenGL错误函数
 bool CheckOpenGLError()
 {
     bool foundError = false;
     int glErr = glGetError();
     while (glErr != GL_NO_ERROR)
     {
         std::cout << "glError: " << glErr << std::endl;
         foundError = true;
         glErr = glGetError();
     }
     return foundError;
 }
 ​
 void Init(GLFWwindow* window)
 {
     renderingProgram = CreateShaderProgram();
     glGenVertexArrays(numVAOs, vao);//生成顶点数组对象名称,用numVAOs存储
     glBindVertexArray(vao[0]);//绑定vao[0]
 }
 ​
 void Display(GLFWwindow* window, double currentTime)
 {
     //不是必须的,我们在隐藏面消除需要同时用到颜色缓冲区和深度缓冲区
     // 每帧初始化深度缓冲区是必要的
     //确保深度对比不会受旧的深度的影响
     glClear(GL_DEPTH_BUFFER_BIT);
     glClearColor(0.0, 0.0, 1.0, 1.0);
     glClear(GL_COLOR_BUFFER_BIT);//相当于在设置显示区域的背景,比如此刻我将其设置为蓝色
     glUseProgram(renderingProgram);//激活程序对象
     x += inc;
     if (x > 1.0) inc = -inc;
     if (x < -1.0) inc = -inc;
     //指定要查询的程序对象为renderingProgram,查询其位置的统一变量的名称为offset
     unsigned int offsetLoc = glGetUniformLocation(renderingProgram, "offset");
     //为指定的程序对象指定统一变量的值,当前只有一个为offsetLoc,指定新值为x
     glProgramUniform1f(renderingProgram, offsetLoc, x);
     //glPointSize(430.0f);//设置点的大小
     glDrawArrays(GL_TRIANGLES, 0, 3);//绘制方式,绘制三角形
 }
 unsigned int CreateShaderProgram()
 {
     //从文件读取GLSL代码
     std::string vertShaderStr = ReadShaderSource("./res/shaders/vertShader.glsl");
     std::string fragShaderStr = ReadShaderSource("./res/shaders/fragShader.glsl");
     const char* vertShaderSrc = vertShaderStr.c_str();
     const char* fragShaderSrc = fragShaderStr.c_str();
     //捕获编译着色器时的错误
     int vertComplied;
     int fragComplied;
     int linked;
     //创建顶点着色器和片段着色器
     unsigned int vShader = glCreateShader(GL_VERTEX_SHADER);
     unsigned int fShader = glCreateShader(GL_FRAGMENT_SHADER);
     //替换vShader,fShader中的源代码,使用自定义的编码
     glShaderSource(vShader, 1, &vertShaderSrc, NULL);
     glShaderSource(fShader, 1, &fragShaderSrc, NULL);
     //对着色器对象进行编译
     glCompileShader(vShader);
     CheckOpenGLError();
     glGetShaderiv(vShader, GL_COMPILE_STATUS, &vertComplied);
     if (vertComplied != 1)
     {
         std::cout << "vertex compilation faild" << std::endl;
         PrintShaderLog(vShader);
     }
     glCompileShader(fShader);
     CheckOpenGLError();
     glGetShaderiv(fShader, GL_COMPILE_STATUS, &fragComplied);
     if (fragComplied != 1)
     {
         std::cout << "fragment compilation faild" << std::endl;
         PrintShaderLog(fShader);
     }
     //创建一个Program链接着色器对象,执行的就是链接有着色器对象的程序
     unsigned int vfProgram = glCreateProgram();
     //把之前编译的着色器附加到程序对象上,然后用glLinkProgram链接它们
     glAttachShader(vfProgram, vShader);
     glAttachShader(vfProgram, fShader);
     glLinkProgram(vfProgram);
     CheckOpenGLError();
     glGetProgramiv(vfProgram, GL_LINK_STATUS, &linked);
     if (linked != 1)
     {
         std::cout << "linking faild" << std::endl;
         PrintProgramLog(vfProgram);
     }
     //返回连接好的着色器程序
     return vfProgram;
 }
 int main()
 {
     if (!glfwInit())
         exit(EXIT_FAILURE);
     glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
     glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
     GLFWwindow* window = glfwCreateWindow(600, 600, "Hello, world", nullptr, nullptr);
     glfwMakeContextCurrent(window);
 ​
     if (glewInit() != GLEW_OK)
         exit(EXIT_FAILURE);
     glfwSwapInterval(1);
 ​
     Init(window);
 ​
     while (!glfwWindowShouldClose(window))
     {
         Display(window, glfwGetTime());
         glfwSwapBuffers(window);
         glfwPollEvents();
     }
 ​
     glfwDestroyWindow(window);
     glfwTerminate();
     exit(EXIT_SUCCESS);
 }

运行结果

QQ录屏20231126185628_-original-original

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
使用NDK和OpenGL ES 3.0来绘制一个三角形可以分为以下几个步骤: 1. 首先,创建一个安卓项目,并配置NDK环境。 2. 在项目的jni目录下,创建一个C/C++源文件triangle.c。 3. 在triangle.c文件中,引入相关的头文件,包括<jni.h>和<GLES3/gl3.h>。 4. 在triangle.c文件中,实现一个JNI函数,用于绘制三角形。函数的参数为Surface对象。 5. 在JNI函数中,通过EGL和GLES初始化OpenGL环境,并创建一个EGLSurface用于后续的绘制操作。 6. 在JNI函数中,创建一个顶点数组和顶点缓冲,并将顶点数据存入顶点缓冲。 7. 在JNI函数中,编写着色器代码,包括顶点着色器和片段着色器,并编译和链接它们。 8. 在JNI函数中,通过glClearColor()函数设置清空屏幕时的颜色。 9. 在JNI函数中,通过glClear()函数清空屏幕,并启用深度测试。 10. 在JNI函数中,通过glViewport()函数设置视口大小。 11. 在JNI函数中,通过glUseProgram()函数使用着色器程序。 12. 在JNI函数中,通过glVertexAttribPointer()函数设置顶点数据的属性,并启用顶点属性。 13. 在JNI函数中,通过glDrawArrays()函数绘制三角形。 14. 在JNI函数中,通过eglSwapBuffers()函数交换绘制的缓冲区。 15. 在JNI函数中,清理OpenGL环境,并释放资源。 16. 在Java层的MainActivity中,通过JNI调用C/C++函数进行绘制。 以上是绘制一个三角形的大致步骤。具体的细节和代码实现可以参考相关的OpenGL ES 3.0和NDK的文档和示例代码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值