我是编程和OpenGL的新手,并且正在关注Cherno的OpenGL初学者教程。但是,它没有显示三角形,而是显示了黑屏。
我相信我的着色器已正确解析和编译。我将Mac OS 10.13与OpenGL 3.2配合使用。 GLFW在加载窗口后确实给出了错误,但我已阅读到该错误不会产生任何严重的后果。我在下面列出了错误。
我非常关注Cherno的教程,但是由于缺乏OpenGL的经验,我很难找到类似于我的问题。我确实在Basic.shader中的main()函数之后删除了分号,因为着色器在那里时无法编译。
这是我第一次发布到StackOverflow,所以我不格式化问题。对于荷兰的评论,我们深感抱歉,从现在开始,我将用英语撰写;)如果我的代码难以遵循,请发表评论或发送电子邮件至afas460x@gmail.com
编辑1:我发现它与VAO有关。我不知道它是什么或如何使用。该文档非常令人困惑。有人可以解释吗?
main.cpp:
// OpenGL test
// Geschreven door Job Winterdijk
// 18-11-2018
// foutcodes door return:
// 2 : !glfwInit
// 3 : !glfwCreateWindow
// 4 : glewInit != GLEW_OK
// 5 : CompileShader()
// 6 : ParseShader() > ongedefieneerde shader
// debug macros
#define DEBUG_OUTPUT_PARSE_SHADER 1
#define DEBUG_OUTPUT_ARGV_0 1
#define DEBUG_OUTPUT_GLSL_VERSION 1
// gedeelde libs
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <cstring>
// GLEW moet eerder geinclude worden dan ander GL libs
#include "include/GL/glew.h"
// Gedeelde OpenGL libs
#include <OpenGL/OpenGL.h>
#include <GLUT/GLUT.h>
// Statische libs
#include "include/GLFW/glfw3.h"
struct ShaderSource
{
std::string VertexShader;
std::string FragmentShader;
};
static void TerminateWithError(unsigned int err)
{
// dit is niet goed :(
std::cout << "weg ermee..." << std::endl;
glfwTerminate();
exit(err);
}
static ShaderSource ParseShader(const std::string& path)
{
// maakt een enum type aan om by te houden naar welke stream er geschreven moet worden
enum class ShaderTarget
{
NONE=-1, VERTEX=0, FRAGMENT=1
};
ShaderTarget target = ShaderTarget::NONE;
// maakt een nieuwe input stream aan
std::ifstream stream(path);
// maakt twee nieuwe output streams aan
// 0 = de vertex shader
// 1 = de fragment shader
std::stringstream out[2];
// houd een lijn uit het bestand vast
std::string line;
// deze loop blijft lopen totdat getline == null AKA het einde van het bestand
while (getline(stream, line)) {
if (line.find("#shader") != std::string::npos) {
if (line.find("vertex") != std::string::npos) {
// de vertex shader is gevonden, schrijf naar vertex shader string
target = ShaderTarget::VERTEX;
} else if (line.find("fragment") != std::string::npos){
// de fragment shader is gevonden, schrijf naar fragment shader string
target = ShaderTarget::FRAGMENT;
} else {
TerminateWithError(6);
}
} else {
// de gelezen lijn is een lijn die code bevat
out[(int) target] << line << '\n';
}
}
return {out[0].str(), out[1].str()};
}
static unsigned int CompileShader(const std::string& inputShader, unsigned int type)
{
unsigned int id = glCreateShader(type); // maakt een lege shader aan
const char* inputShaderCS = inputShader.c_str(); // maakt een char pointer naar het eerste element van de CS van std::string, werkt alleen maar zolang de oorspronkelijke string ook blijft bestaan
glShaderSource(id, 1, &inputShaderCS, nullptr); // geeft de ongecompileerde shader door aan OpenGL
glCompileShader(id); // compileert de shader
// hopa we gaan nu error handelen hebbe we er een beetje zin in!!!!!
// glGetShaderiv() haalt informatie over een shader op en stopt dit in een var waar de pointer naar wijst
int result;
glGetShaderiv(id, GL_COMPILE_STATUS, &result);
// kijken of het compileren succesvol was
if (result == GL_FALSE) {
// als het niet succesvol was wordt de rede opgeslagen in de info log
// die kan je met getShaderiv() lezen
// net zoals de lengte van de info log
int length;
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length);
// message moet op de heap gealloceerd worden omdat je pas tijdens runtime weet hoelang de foutmelding is
char* message = new char[length];
glGetShaderInfoLog(id, length, &length, message);
// zet het type shader om in menselijke taal
char ShaderTypeString[10];
if (type == GL_VERTEX_SHADER) {
strcpy(ShaderTypeString, "VERTEX");
} else if (type == GL_FRAGMENT_SHADER) {
strcpy(ShaderTypeString, "FRAGMENT");
}
// schrijf een foutmelding naar stderr stream
std::cerr << "[CompileShader(in, type) | main.cpp] Er is een fout opgetreden tijdens het compileren van een shader." << std::endl;
std::cerr << "shader type: " << ShaderTypeString << std::endl;
std::cerr << "Shader info log:\n" << message << std::endl;
delete [] message;
TerminateWithError(5);
}
return id; // returned de aangemaakte en gecompileerde shader
}
static unsigned int CreateShaders(const std::string& vertexShader, const std::string& fragmentShader)
{
unsigned int program = glCreateProgram(); // een programma zorgt ervoor dat meerdere shaders aan elkaar gekoppeld kunnen worden
// compilleert bijde shaders
unsigned int vertexShaderID = CompileShader(vertexShader, GL_VERTEX_SHADER);
unsigned int fragmentShaderID = CompileShader(fragmentShader, GL_FRAGMENT_SHADER);
// voegt bijde shader aan het programma toe
glAttachShader(program, vertexShaderID);
glAttachShader(program, fragmentShaderID);
// linkt het programma AKA maakt het programma uitvoerbaar
glLinkProgram(program);
// kijkt of het programma in ?deze staat? uitgevoerd kan worden
glValidateProgram(program);
// verwijderd de shaders, dit kan omdat de shaders nu onderdeel zijn van de program (net als .o bestanden zegmaar)
glDeleteShader(vertexShaderID);
glDeleteShader(fragmentShaderID);
// returned het ID van de program
return program;
}
int main(int argc, char *argv[])
{
// (debug) print de uitvoer van argv[0] met als doel te achterhalen wat het path is waarvan main uitgevoerd wordt
#if DEBUG_OUTPUT_ARGV_0==1
std::cout << "executable path: \n" << argv[0] << "\n\n";
#endif
GLFWwindow *window; // het scherm
// initialiseert glfw en tekent een scherm
if (!glfwInit()) return 2;
// dit gaat er hopenlijk voor zorgen dat ik OpenGL 3.3 kan gebruiken
// anders ga ik huilen :(
// ben letterlijk een uur bezig geweest met dit oplossen ;-;
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
// glfwCreateWindow geeft een foutmelding
window = glfwCreateWindow(500, 500, "OpenGL test/yehes", NULL, NULL);
if (!window) {
glfwTerminate();
return 3;
}
// selecteert een OpenGL context
glfwMakeContextCurrent(window);
// print de ondersteunde GLSL versie
// handige reminder: dit kan alleen maar als er een actieve OpenGL context is
// anders krijg je eem EXC_BAD_ACCES en dan ben je echt een jaar bezig met de oplossing zoeken
#if DEBUG_OUTPUT_GLSL_VERSION==1
std::cout << "Ondersteunde GLSL versie is: " << glGetString(GL_SHADING_LANGUAGE_VERSION) << "\n" << std::endl;
#endif
// initialiseert GLEW
if (glewInit() != GLEW_OK) {
return 4;
}
// de buffer is wat er aan de GPU wordt doorgegeven
unsigned int buffer; // buffer ID
glGenBuffers(1, &buffer); // maakt buffer aan
glBindBuffer(GL_ARRAY_BUFFER, buffer); // selecteert de buffer
// dit verteld OpenGL?of de shader? of de GPU? hoed de vertex geformat is
glEnable(0); // activeert de type vertex
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float)*2, 0); // definieert de type vertex
// dit zijn de vertexen die in de buffer geladen gaan worden
float data[6] = {
-0.5f,-0.5f,
0.0f, 0.5f,
0.5f, -0.5f
};
// maakt de buffer aan en laad de data in de buffer
// als je nog geen dat in de buffer wil laden dan kan je NULL invullen op de plek waarnu data staat
glBufferData(GL_ARRAY_BUFFER, 6*sizeof(float), data, GL_STATIC_DRAW);
// de shaders worden het geheugen in geladen
ShaderSource source = ParseShader("./res/Shaders/Basic.shader");
// (debug) laat de uitvoer van de geparste shaders zien
// om de mysterieuze bug op te lossen
#if DEBUG_OUTPUT_PARSE_SHADER==1
std::cout << "ParseShader : VERTEX\r" << source.VertexShader << "\rParseShader : FRAGMENT\r" << source.FragmentShader << std::endl;
std::cout << "---END---" << "\n" << std::endl;
#endif
// het programma wordt aangemaakt en de shaders worden eraan gebonden
unsigned int program = CreateShaders(source.VertexShader, source.FragmentShader);
// het programma wordt geselecteerd
glUseProgram(program);
// dit is de game loop
while (!glfwWindowShouldClose(window)) {
// docs.gl zegt dat dit de buffer leeg haalt maar wss is dat een andere buffer want anders zou de driehoek toch verdwijnen?
glClear(GL_COLOR_BUFFER_BIT);
// hier moet je renderen
glDrawArrays(GL_TRIANGLES, 0, 3);
// hier moet je stoppen met renderen
// glfw heeft twee buffers de front en de back buffer
// de front buffer is wat er nu op het scherm staat
// de back buffer is waar je naar rendert
// glfwSwapBuffers() wisselt deze om
glfwSwapBuffers(window);
// glfwPollEvents() haalt nieuwe informatie van de window system om te kijken of er nieuwe gebruikers input is
// deze gebruik je als je een continue game loop hebt
// als er alleen maar iets hoeft te veranderen als er gebruikersinvoer is hebruik je glfwWaitEvents()
glfwPollEvents();
}
// het programma moet verwijderd worden
glDeleteProgram(program);
glfwTerminate();
return 0;
}
Basic.shader:
#shader vertex
#version 330 core
layout(location = 0) in vec4 position;
void main()
{
gl_Position = position;
}
#shader fragment
#version 330 core
layout(location = 0) out vec4 color;
void main()
{
color = vec4(1.0, 0.0, 0.0, 1.0);
}
调用glfwCreateWindow()后显示的错误消息:
Setting <GLFWContentView: 0x1007650c0> as the first responder for window <GLFWWindow: 0x10073bea0>, but it is in a different window ((null))! This would eventually crash when the view is freed. The first responder will be set to nil.
(
0 AppKit 0x00007fff2e896862 -[NSWindow _validateFirstResponder:] + 578
1 AppKit 0x00007fff2dfdd5f0 -[NSWindow _setFirstResponder:] + 31
2 AppKit 0x00007fff2e07bd5d -[NSWindow _realMakeFirstResponder:] + 448
3 OpenGL test 0x0000000100035c3a createNativeWindow + 1034
4 OpenGL test 0x00000001000355cf _glfwPlatformCreateWindow + 63
5 OpenGL test 0x000000010002de57 glfwCreateWindow + 887
6 OpenGL test 0x00000001000014d7 main + 231
7 libdyld.dylib 0x00007fff588ec015 start + 1
)