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 - 如何获得从类继承的正确变量的主要内容,如果未能解决你的问题,请参考以下文章