C++/OpenGL - 如何获得从类继承的正确变量

Posted

技术标签:

【中文标题】C++/OpenGL - 如何获得从类继承的正确变量【英文标题】:C++/OpenGL - How to get the right variable inherited from class 【发布时间】:2019-10-26 01:18:48 【问题描述】:

所以问题是我的代码没有运行正确的 glUseProgram 函数。

我已经测试了它应该需要什么值并且它可以工作,但我显然不想硬编码它。

Shader.cpp(我在头文件中声明了programID)

#include "Shader.h"

#include <GL/glew.h>
#include <iostream>
#include <fstream>

GLuint vertexShaderID, fragmentShaderID;

Shader::Shader() 



Shader::Shader(const GLchar* vertexFile, const GLchar* fragmentFile) 
    GLint success;
    GLchar infoLog[512];

    vertexShaderID = loadShader(vertexFile, GL_VERTEX_SHADER);
    fragmentShaderID = loadShader(fragmentFile, GL_FRAGMENT_SHADER);
    programID = glCreateProgram();
    glAttachShader(programID, vertexShaderID);
    glAttachShader(programID, fragmentShaderID);
    glLinkProgram(programID);
    //glValidateProgram(programID);

    glGetProgramiv(programID, GL_LINK_STATUS, &success);
    if (!success) 
        glGetProgramInfoLog(programID, 512, NULL, infoLog);
        std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
    

    //bindAttributes();

    std::cout << "SHADER::LOADED\n" << std::endl;

    glDeleteShader(vertexShaderID);
    glDeleteShader(fragmentShaderID);
    std::cout << "PROGRAM::" << programID << std::endl;


void Shader::Start() const

    glUseProgram(programID);
    std::cout << "p:" << programID << std::endl;


void Shader::cleanUp() 
    glUseProgram(0);
    glDetachShader(programID, vertexShaderID);
    glDetachShader(programID, fragmentShaderID);
    glDeleteShader(vertexShaderID);
    glDeleteShader(fragmentShaderID);
    glDeleteProgram(programID);

TestShader.cpp

#include "TestShader.h"
#include "Shader.h"

const GLchar* VERTEX_FILE = "shaders/shader.vs";
const GLchar* FRAGMENT_FILE = "shaders/shader.frag";

TestShader::TestShader() 
    Shader::Shader(VERTEX_FILE, FRAGMENT_FILE);


main.cpp

#include <iostream>

// GLEW
#define GLEW_STATIC
#include <GL/glew.h>

// GLFW
#include <GLFW/glfw3.h>

// SOIL
#include <SOIL2/SOIL2.h>

// GLM
#include <GLM/glm.hpp>

// Other includes
#include "TestShader.h"

// GameEngine
#include "Display.h"
#include "Mesh.h"

const GLuint WIDTH = 800, HEIGHT = 600;

int main()

    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);

    Display display(WIDTH, HEIGHT, "GameEngine");

    glewExperimental = GL_TRUE;
    glewInit();

    TestShader s;

    Vertex vertices[] = 
        Vertex(glm::vec3(-0.5 , -0.5, 0)),
        Vertex(glm::vec3(0, 0.5, 0)),
        Vertex(glm::vec3(0.5, -0.5, 0))
    ;

    Mesh mesh(vertices, sizeof(vertices) / sizeof(vertices[0]));


    while (!display.IsClosed())
    
        glfwPollEvents();

        display.Clear(0.0f, 0.0f, 0.3f, 0.0f);

        s.Start();

        mesh.Draw();

        s.cleanUp();

        display.Update();
    

    glfwTerminate();
    return 0;


TestShader.h

#ifndef TESTSHADER_H
#define TESTSHADER_H

#include "Shader.h"

#include <GL/glew.h>
#include <iostream>

class TestShader : public Shader 
public:
    TestShader();
private:
protected:
    void bindAttributes() override;
;

#endif // TESTSHADER_H

着色器.h

#ifndef SHADER_H
#define SHADER_H

#include <string>
#include <fstream>
#include <sstream>
#include <iostream>

#include <GL/glew.h>

class Shader

private:
    GLuint programID;

protected:
    int getUniformLocation(GLchar * uniformName);

public:
    Shader();
    Shader(const GLchar* vertexFile, const GLchar* fragmentFile);
    ~Shader();

    GLuint loadShader(const GLchar * shaderSourcePath, GLuint type);

    virtual void bindAttributes();
    void bindAttribute(int attribute, GLchar* variableName);
    void Start() const;
    void cleanUp();
;

#endif // !SHADER_H

如果我在构造函数中计算出 programID,我会得到值 3,但如果我在 Start 函数中计算出它,我会得到 3435973836(总是......我认为)。

我猜可能是继承有问题。但是,如果我在 Start 函数中硬编码 3 而不是 programID,为什么它会起作用?

控制台输出(我的 programID 值更改):

【问题讨论】:

请显示Shader 类的定义。为什么顶点和片段着色器 ids 是全局变量? 我认为我只是在全局保存它们以在清理功能中删除它们。不确定这是否真的需要。但是有一个更好的解决方案。 cleanUp() 调用可能不应该出现在您的显示循环中。但我有点怀疑这会导致你看到的行为。 @Ahriox 为什么要破坏显示循环中的着色器? (s.cleanUp();) 现在这无关紧要,正如我之前所说。当我将 glUseProgram(3) 放入 Start 函数时,我的着色器工作。我的问题是为什么programID不再是3了。 【参考方案1】:

问题出在对象TestShader的构造函数中:

TestShader::TestShader() 
   Shader::Shader(VERTEX_FILE, FRAGMENT_FILE);

Shader::Shader(VERTEX_FILE, FRAGMENT_FILE); 语句没有按照您的预期执行。它不会“构造”分别初始化基类,它会在构造函数的主体范围内生成一个全新的对象。

您必须在构造函数的初始化列表中指定基类的构造函数(参见Constructors and member initializer lists):

TestShader::TestShader() 
  : Shader(VERTEX_FILE, FRAGMENT_FILE) 

请注意,在您的代码中,实际上对象TestShader s 的属性programID 从未设置,因为默认构造函数用于构造基类。 但是在TestShader的构造函数体内又生成了一个对象。该对象成功生成了着色器程序并设置了它自己的属性programID(即输出第一行中打印的内容)。 当然这个对象会立即被销毁,但这并不重要,因为 OpenGL 着色器程序对象仍然存在于 GPU 上。 所以(“硬编码”)调用glUsePrgram(3) 会安装着色器程序。

【讨论】:

非常感谢。我认为我的方法按我的预期工作。无论哪种方式,起初这有点令人困惑(主要来自 c#),但它现在可以工作了。再说一次,谢谢。

以上是关于C++/OpenGL - 如何获得从类继承的正确变量的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 OpenGL 在 SDL 中获得正确的 SourceOver alpha 合成

如何从类方法返回枚举元素?

如何直接从类调用从接口继承的方法?

我如何知道哪些类从类或接口继承? [复制]

C ++无法从类中检索私有变量[关闭]

从类对象继承属性的类对象的python dict