ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

阅读《计算机图形学编程(使用OpenGL和C++)》3

2022-01-28 18:02:34  阅读:265  来源: 互联网

标签:std 1.0 OpenGL 0.25 Utils 图形学 C++ char gl


GLSL运行在GPU上,想要调试需要一个用于捕获和显示GLSL错误的模块。

Utils.h

#pragma once
#include "GL\glew.h"
#include <string>
class Utils
{
public:
    Utils();
    ~Utils();static void printShaderLog(GLuint shader);
    static void printProgramLog(int prog);
    static bool checkOpenGLError();
    static GLuint createShaderProgram();
};

Utils.cpp

#include "Utils.h"
#include <iostream>
#include <fstream>
#include <SOIL2/SOIL2.h>

Utils::Utils()
{
}

Utils::~Utils()
{
}

// 当GLSL编译失败时,显示OpenGL日志内容
void Utils::printShaderLog(GLuint shader)
{
    int len = 0;
    int chWritten = 0;
    char *log;
    glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &len); // 提供有关编译过的GLSL着色器的信息
    if (len > 0)
    {
        log = (char *)malloc(len);
        glGetShaderInfoLog(shader, len, &chWritten, log);
        std::cout << "Shader Info Log: " << log << std::endl;
        free(log);
    }
}

// 当GLSL链接失败时,显示OpenGL日志内容
void Utils::printProgramLog(int prog)
{
    int len = 0;
    int chWritten = 0;
    char *log;
    glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &len); // 提供有关编译过的程序的信息
    if (len > 0)
    {
        log = (char *)malloc(len);
        glGetProgramInfoLog(prog, len, &chWritten, log);
        std::cout << "Program Info Log: " << log << std::endl;
        free(log);
    }
}

// 检查OpenGL错误标志,即是否发生OpenGL错误,既用于检测GLSL编译错误,又用于检测OpenGL运行时的错误
bool Utils::checkOpenGLError()
{
    bool foundError = false;
    int glErr = glGetError();
    while (glErr != GL_NO_ERROR)
    {
        std::cout << "glError: " << glErr << std::endl;
        foundError = true;
        glErr = glGetError();
    }
    return foundError;
}

GLuint Utils::createShaderProgram()
{
    GLint vertCompiled;
    GLint fragCompiled;
    GLint linked;

    const char* vshaderSource =
        "#version 460 \n"
        "void main(void) \n"
        "{ gl_Position = vec4(0.0, 0.0, 0.0, 1.0); }";

    const char* fshaderSource =
        "#version 460 \n"
        "out vec4 color; \n"
        "void main(void) \n"
        "{ color = vec4(0.0, 0.0, 1.0, 1.0); }";

    GLuint vShader = glCreateShader(GL_VERTEX_SHADER);
    GLuint fShader = glCreateShader(GL_FRAGMENT_SHADER);

    glShaderSource(vShader, 1, &vshaderSource, NULL);
    glShaderSource(fShader, 1, &fshaderSource, NULL);

    // 捕获编译着色器时的错误
    glCompileShader(vShader);
    checkOpenGLError();
    glGetShaderiv(vShader, GL_COMPILE_STATUS, &vertCompiled);
    if (vertCompiled != 1)
    {
        std::cout << "vertex compilation failed" << std::endl;
        printShaderLog(vShader);
    }

    glCompileShader(fShader);
    checkOpenGLError();
    glGetShaderiv(fShader, GL_COMPILE_STATUS, &fragCompiled);
    if (fragCompiled != 1)
    {
        std::cout << "fragment compilation failed" << std::endl;
        printShaderLog(fShader);
    }

    GLuint vfProgram = glCreateProgram();

    // 捕获链接着色器时的错误
    glAttachShader(vfProgram, vShader);
    glAttachShader(vfProgram, fShader);
    glLinkProgram(vfProgram);
    checkOpenGLError();
    glGetProgramiv(vfProgram, GL_LINK_STATUS, &linked);
    if (linked != 1)
    {
        std::cout << "linking failed" << std::endl;
        printProgramLog(vfProgram);
    }
    return vfProgram;
}

当程序更复杂时,GLSL着色器代码存储在字符串中就不可取了,我们应当将着色器代码存在文件中并读入它们。

顶点着色器和片段着色器代码分别放在 "vertShader.glsl" 和 "fragShader.glsl" 中。

Utils.h 增加如下代码:

    static std::string readShaderSource(const char *filePath);
    static GLuint createShaderProgram(const char *vp, const char *fp);

Utils.cpp

// 用于读取着色器的代码
std::string Utils::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;
}

// 读取着色器代码并构建渲染程序,该类很适合重载
GLuint Utils::createShaderProgram(const char * vp, const char * fp)
{
    GLint vertCompiled;
    GLint fragCompiled;
    GLint linked;

    std::string vertShaderStr = readShaderSource(vp);
    std::string fragShaderStr = readShaderSource(fp);

    const char * vertShaderSrc = vertShaderStr.c_str();
    const char * fragShaderSrc = fragShaderStr.c_str();

    GLuint vShader = glCreateShader(GL_VERTEX_SHADER);
    GLuint fShader = glCreateShader(GL_FRAGMENT_SHADER);

    glShaderSource(vShader, 1, &vertShaderSrc, NULL);
    glShaderSource(fShader, 1, &fragShaderSrc, NULL);

    glCompileShader(vShader);
    checkOpenGLError();
    glGetShaderiv(vShader, GL_COMPILE_STATUS, &vertCompiled);
    if (vertCompiled != 1)
    {
        std::cout << "vertex compilation failed" << std::endl;
        printShaderLog(vShader);
    }

    glCompileShader(fShader);
    checkOpenGLError();
    glGetShaderiv(fShader, GL_COMPILE_STATUS, &fragCompiled);
    if (fragCompiled != 1)
    {
        std::cout << "fragment compilation failed" << std::endl;
        printShaderLog(fShader);
    }

    GLuint vfProgram = glCreateProgram();
    glAttachShader(vfProgram, vShader);
    glAttachShader(vfProgram, fShader);
    glLinkProgram(vfProgram);
    checkOpenGLError();
    glGetProgramiv(vfProgram, GL_LINK_STATUS, &linked);
    if (linked != 1)
    {
        std::cout << "linking failed" << std::endl;
        printProgramLog(vfProgram);
    }
    return vfProgram;
}

从文件着色器读取并生成一个三角形的程序,如下:

顶点着色器,vertShader.glsl

#version 460 
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);}

display() 函数中加入代码

...
glDrawArrays(GL_TRIANGLES, 0, 3);

结果如下:

 

 可以使三角形动起来实现动画效果,我们在 main() 函数中只调用了 init() 一次,之后重复调用 display(),在循环中可以一次又一次绘制,只要设计 display() 函数随时间改变绘制的东西。

场景的每一次绘制都叫作一帧,调用 display() 的频率叫作帧率。在程序逻辑中移动的速率可以通过自前一帧到目前经过的时间来控制。

main.cpp

// #include和定义与之前相同

float x = 0.0f;   // 三角形在x轴的位置
float inc = 1.0f; // 移动三角形的偏移量

void display(GLFWwindow* window, double currentTime)
{
    glClear(GL_DEPTH_BUFFER_BIT);
    glClearColor(0.0, 0.0, 0.0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT);        // 每次将背景清除为黑色

    glUseProgram(renderingProgram);

    x += inc;                            // 切换至让三角形向右移动
    if (x > 1.0f)                        // 沿x轴移动三角形
        inc = -0.01f;
    if (x < -1.0f)                        // 切换至让三角形向右移动
        inc = 0.01f;
    GLuint offsetLoc = glGetUniformLocation(renderingProgram, "offset"); // 获取"offset"指针
    glProgramUniform1f(renderingProgram, offsetLoc, x);                     // 将"x"中的值传给"offset"
    glDrawArrays(GL_TRIANGLES, 0, 3);
}
// 其余函数同前

顶点着色器

#version 460 
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);}

结果如下:

 

标签:std,1.0,OpenGL,0.25,Utils,图形学,C++,char,gl
来源: https://www.cnblogs.com/lely/p/15853438.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有