我刚开始我的图形计算之旅,所以我开始理解本教程:https://learnopengl.com/Getting-started/Hello-Triangle。
在冒险尝试做一些“动态”绘画之前我想过变换 这成为一个“渲染器”类会很有趣这是结果:
#pragma once
#include <fstream>
#include <vector>
#include "pch.h"
class Renderer {
public:
Renderer(GLFWwindow*);
void initVertexShaders(std::vector<std::string>&);
void initFragmentShaders(std::vector<std::string>&);
void load(float*, size_t);
void draw();
const GLubyte* renderer;
const GLubyte* version;
private:
GLFWwindow* window = nullptr;
GLuint vbo;
GLuint vao;
GLuint shaderProgram = 0; //= glCreateProgram();
GLuint vs[100];
GLuint fs[100];
};
pch.h是一个预编译的头文件,以便在每次构建项目时都不编译glm,glfw和glew。
我的想法是隔离不同的实用程序,我会使用load(float *,size_t)将信息发送到gpu,并在主窗口循环期间使用draw()。我们的想法是首次逼近2d无摄像头渲染引擎。
无论如何,源代码是:
#include "Renderer.hpp"
Renderer::Renderer(GLFWwindow* window) {
this->window = window;
glfwMakeContextCurrent(window);
glewExperimental = GL_TRUE;
glewInit();
this->renderer = glGetString(GL_RENDERER);
this->version = glGetString(GL_VERSION);
this->vao = 0;
this->vbo = 0;
}
void Renderer::load(float* points, size_t memory) {
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, memory, points, GL_STATIC_DRAW);
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
}
void Renderer::draw() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(shaderProgram);
glBindVertexArray(vao);
glDrawArrays(GL_TRIANGLES, 0, 6);
}
void Renderer::initVertexShaders(std::vector<std::string>& paths) {
int i = 0;
std::ifstream ifs;
if(this->shaderProgram == 0) shaderProgram = glCreateProgram();
for (const auto& path : paths){
ifs.open(path);
std::string program_str(( std::istreambuf_iterator<char>(ifs)),
( std::istreambuf_iterator<char>() ));
const char* program_src = program_str.c_str();
vs[i] = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vs[i], 1, &program_src, NULL);
glCompileShader(vs[i]);
glAttachShader(shaderProgram, vs[i]);
i++;
}
glLinkProgram(shaderProgram);
}
void Renderer::initFragmentShaders(std::vector<std::string>& paths) {
int i = 0;
std::ifstream ifs;
if(this->shaderProgram == 0) shaderProgram = glCreateProgram();
for (const auto& path : paths){
ifs.open();
std::string program_str(( std::istreambuf_iterator<char>(ifs)),
( std::istreambuf_iterator<char>() ));
const char* program_src = program_str.c_str();
fs[i] = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fs[i], 1, &program_src, NULL);
glCompileShader(fs[i]);
glAttachShader(shaderProgram, fs[i]);
i++;
}
glLinkProgram(shaderProgram);
}
问题来自着色器时间,我可以毫无问题地阅读文件,但它们什么都不做。
问题是:将所有着色器存储在数组中是否有意义? 着色器程序可以包含多个顶点着色器/片段着色器吗? 错误在另一个地方吗? 全班都有意义吗?
谢谢。
编辑:来自main.cpp的代码
#include "Renderer.hpp"
float points[] = {
0.5f, 0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
-0.5f, -0.5f, 0.0f,
//
0.5f, 0.5f, 0.0f,
-0.5f, 0.5f, 0.0f,
-0.5f, -0.5f, 0.0f
};
int main() {
std::vector<std::string> vertexShaders;
std::vector<std::string> fragmentShaders;
vertexShaders.push_back("shader/vs.glsl");
fragmentShaders.push_back("shader/fs.glsl");
glfwInit(); //glfwGetPrimaryMonitor()
GLFWwindow *window = glfwCreateWindow(960, 540, "Hello Triangle", NULL, NULL);
Renderer Ren(window);
Ren.load(points, sizeof(points));
Ren.initVertexShaders(vertexShaders);
Ren.initFragmentShaders(fragmentShaders);
while (!glfwWindowShouldClose(window)) {
Ren.draw();
glfwPollEvents();
glfwSwapBuffers(window);
}
glfwTerminate();
return 0;
}
答案 0 :(得分:2)
在编译完所有附加的着色器对象后,将着色器程序对象链接一次就足够了。
OpenGL 4.6 API Core Profile Specification; 7.3. PROGRAM OBJECTS; page 94:
在将源代码加载到着色器对象之前,或者在着色器对象编译或专用之前,可以将着色器对象附加到程序对象。
注意,着色器对象在连接到它的着色器程序对象之前被成功编译就足够了。
OpenGL 4.6 API Core Profile Specification; 7.3. PROGRAM OBJECTS; page 94:
可以将多个相同类型的着色器对象附加到单个程序对象,并且可以将单个着色器对象附加到多个程序对象。
e.g。
一个着色器对象包含一个函数(FragColor
)
#version 460
uniform sampler2D u_texture;
vec4 FragColor(vec2 uv)
{
return texture(u_texture, uv);
}
同一类型的第二个着色器对象包含函数签名(但不是实现)和函数的用法。
#version 460
in vec2 vUV;
out vec4 fragColor;
vec4 FragColor(vec2 uv);
void main()
{
fragColor = FragColor(vUV);
}
上述两个代码段都可以放在2个单独的GL_FRAGMENT_SHADER
类型的着色器对象中。可以成功编译2个着色器对象中的每一个。如果它们附加到同一个着色器程序对象,则可以成功地使用着色器程序对象。
另见Attaching multiple shaders of the same type in a single OpenGL program?
此外,我建议检查着色器对象是否已成功编译:
GLuint shaderObj = .... ;
glCompileShader( shaderObj );
GLint status = GL_TRUE;
glGetShaderiv( shaderObj, GL_COMPILE_STATUS, &status );
if ( status == GL_FALSE )
{
GLint logLen;
glGetShaderiv( shaderObj, GL_INFO_LOG_LENGTH, &logLen );
std::vector< char >log( logLen );
GLsizei written;
glGetShaderInfoLog( shaderObj, logLen, &written, log.data() );
std::cout << "compile error:" << std::endl << log.data() << std::endl;
}
并且着色器程序对象已成功链接:
GLuint progObj = ....;
glLinkProgram( progObj );
GLint status = GL_TRUE;
glGetProgramiv( progObj, GL_LINK_STATUS, &status );
if ( status == GL_FALSE )
{
GLint logLen;
glGetProgramiv( progObj, GL_INFO_LOG_LENGTH, &logLen );
std::vector< char >log( logLen );
GLsizei written;
glGetProgramInfoLog( progObj, logLen, &written, log.data() );
std::cout << "link error:" << std::endl << log.data() << std::endl;
}