我正在努力学习OpenGL和C,方法是阅读www.example.com教程和JDAH系列关于OpenGL in C的视频。我尤其受到了他的这个项目的启发:learnopengl.com tutorial and the JDAH series of videos about OpenGL in C. I especially got really inspired by this project of him : minecraft in one week .
在www.example.com的照明章节之前,我有一个完美工作的代码,但是我的代码很混乱,我想重构和清理,所以我把Makefile改为JDAH的,把代码分成几个文件。learnopengl.com but my code was messy and I wanted to refactor and clean up so I changed the Makefile to JDAH's one, split the code in several files. Nothing is working anymore.
我花了7个小时来调试这个问题,我发现用C调试segfault并不有趣。不管怎么说,我想我已经找到了问题所在,我第二次调用glEnableVertexAttribArray
解引用了一个空指针,这导致了segfault。我试着把Glew改为Glad。我重新安装了库,试着修改Makefile,但没有任何效果,我失去了希望。
下面你可以找到我的Makefile,我的main. c的一部分和一张在lldb中显示的segfault的图片。我运行在MacOS 13.2上,使用OpenGL 4.1。我在我的/usr/local/include中安装了Glew,但它不是Makefile引用的那些,我不知道这是否会导致问题。
JDAH的代码在我的Mac上运行得很完美,几乎使用了相同的Makefile(不包括噪音),但他使用OpenGL 3.3,我使用OpenGL 4.1,所以我改变了高兴文件夹。
- 生成文件**
UNAME_S = $(shell uname -s)
CC = clang
CFLAGS = -std=c11 -O3 -g -Wall -Wextra -Wpedantic -Wstrict-aliasing
CFLAGS += -Wno-pointer-arith -Wno-newline-eof -Wno-unused-parameter -Wno-gnu-statement-expression
CFLAGS += -Wno-gnu-compound-literal-initializer -Wno-gnu-zero-variadic-macro-arguments
CFLAGS += -Ilib/cglm/include -Ilib/glad/include -Ilib/glfw/include -Ilib/stb -fbracket-depth=1024
LDFLAGS = lib/glad/src/glad.o lib/cglm/libcglm.a lib/glfw/src/libglfw3.a -lm
# GLFW required frameworks on OSX
ifeq ($(UNAME_S), Darwin)
LDFLAGS += -framework OpenGL -framework IOKit -framework CoreVideo -framework Cocoa
endif
ifeq ($(UNAME_S), Linux)
LDFLAGS += -ldl -lpthread
endif
SRC = $(wildcard src/**/*.c) $(wildcard src/*.c) $(wildcard src/**/**/*.c) $(wildcard src/**/**/**/*.c)
OBJ = $(SRC:.c=.o)
BIN = bin
.PHONY: all clean
all: dirs libs game
libs:
cd lib/cglm && cmake . -DCGLM_STATIC=ON && make
cd lib/glad && $(CC) -o src/glad.o -Iinclude -c src/glad.c
cd lib/glfw && cmake . && make
dirs:
mkdir -p ./$(BIN)
run: all
$(BIN)/game
game: $(OBJ)
$(CC) -o $(BIN)/game $^ $(LDFLAGS)
%.o: %.c
$(CC) -o $@ -c $< $(CFLAGS)
clean:
rm -rf $(BIN) $(OBJ)
- main. c**(还有更多代码,但为了可读性起见,我没有包括所有代码。LLDB在第二个glEnableVertexArray上崩溃)
#include "glad/glad.h"
#define GLFW_INCLUDE_NONE
#include "GLFW/glfw3.h"
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <cglm/cglm.h>
#include "gfx/shaders.h"
#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>
int main() {
if (!glfwInit()) {
printf("Error initializing GLFW");
exit(EXIT_FAILURE);
}
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwSetErrorCallback(error_callback);
GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL);
if (window == NULL) {
printf("Failed to create Window\n");
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
glfwSetCursorPosCallback(window, mouse_callback);
int version = gladLoadGLLoader((GLADloadproc) glfwGetProcAddress);
if (version == 0) {
printf("Failed to initialize OpenGL context\n");
return -1;
}
// Successfully loaded OpenGL
printf("Loaded OpenGL %d.%d\n", GLVersion.major, GLVersion.minor);
printf("test");
printf("%s", glGetString(GL_VERSION));
printf("test");
//Enable Depth Buffer
glEnable(GL_DEPTH_TEST);
//Define viewport for the size of the window
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
//Generate a VAO so we don't have to do this configuration for every vertices
unsigned int VAO, VBO;
glGenVertexArrays(1, &VAO);
//Get Vertex Buffer Object from OpenGL
glGenBuffers(1, &VBO);
//Push vertex data into the buffer
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindVertexArray(VAO);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GL_FLOAT), (void*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GL_FLOAT), (void*)(3*sizeof(float)));
glEnableVertexAttribArray(1);
- LLDB的输出**
因为我是C的新手,我可能忘记了一些东西,请随时询问更多的信息,我会尽我所能提供给他们。
(lldb) n
Process 28686 stopped
* thread #1, stop reason = step over
frame #0: 0x000000010000a990 game`main at main.c:238:5 [opt]
235 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GL_FLOAT), (void*)0);
236 glEnableVertexAttribArray(0);
237 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GL_FLOAT), (void*)(3*sizeof(float)));
-> 238 glEnableVertexAttribArray(1);
239
240
241 unsigned int vertexShader;
Target 0: (game) stopped.
(lldb) n
Process 28686 stopped
* thread #1, stop reason = EXC_BAD_ACCESS (code=1, address=0x0)
frame #0: 0x00007ffa20fc4f00
-> 0x7ffa20fc4f00: movl (%rax), %edi
0x7ffa20fc4f02: popq %rbp
0x7ffa20fc4f03: jmpq *%r8
0x7ffa20fc4f06: pushq %rbp
Target 0: (game) stopped.
- EDIT 1**我尝试跟踪Haris输入并捕获错误代码。结果很奇怪,我并不真正理解所有内容。我正在记录GLAD加载后的OpenGL版本,这是涉及的代码行:
// Successfully loaded OpenGL
printf("Loaded OpenGL %d.%d\n", GLVersion.major, GLVersion.minor);
GLenum err;
err = glGetError();
printf("Error: %u", err);
printf("%s", glGetString(GL_VERSION));
err = glGetError();
printf("Error2: %u", err);
由于LLDB没有抱怨地遍历了这些行,我认为它们没有问题,但事实上,只是控制台中的第一个printf有问题。这个观察结果对之后的每个printf都是正确的。我尝试在每个函数调用后执行glGetError()
,但控制台中什么也没有出现。
- 控制台输出**
Loaded OpenGL 4.1
[1] 31313 segmentation fault bin/game
- 编辑2**
我尝试更改错误处理,使其看起来像Haris指出的那样。
// Successfully loaded OpenGL
printf("Loaded OpenGL %d.%d\n", GLVersion.major, GLVersion.minor);
if(!glGetString(GL_VERSION)) {
err = glGetError();
printf("Error %u", err);
return -1;
}
printf("TEST");
err = glGetError();
printf("Error2: %u", err);
至于Derhass请求,你可以在下面找到我的main.c的其余部分。昨天在我开始修改makefile和libs之前,它工作得非常好。
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GL_FLOAT), (void*)(3*sizeof(float)));
err = glGetError();
printf("%u", err);
glEnableVertexAttribArray(1);
err = glGetError();
printf("%u", err);
unsigned int vertexShader;
unsigned int fragmentShaderOrange = glCreateShader(GL_FRAGMENT_SHADER); // the first fragment shader that outputs the color orange
unsigned int shaderProgramOrange = glCreateProgram();
//const char* vertexShaderSourceFromFile = getShader(BASE_VERTEX_SHADER);
compile_shader(&vertexShader, GL_VERTEX_SHADER, BASE_VERTEX_SHADER);
compile_shader(&fragmentShaderOrange, GL_FRAGMENT_SHADER, BASE_FRAGMENT_SHADER);
// link the first program object
glAttachShader(shaderProgramOrange, vertexShader);
glAttachShader(shaderProgramOrange, fragmentShaderOrange);
glLinkProgram(shaderProgramOrange);
// then link the second program object using a different fragment shader (but same vertex shader)
// this is perfectly allowed since the inputs and outputs of both the vertex and fragment shaders are equally matched.
unsigned int texture1;
glGenTextures(1, &texture1);
glBindTexture(GL_TEXTURE_2D, texture1);
// set the texture wrapping/filtering options (on the currently bound texture object)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// load and generate the texture
int width, height, nrChannels;
stbi_set_flip_vertically_on_load(1);
unsigned char *data = stbi_load("./res/tibo.jpg", &width, &height, &nrChannels, 0);
if (data)
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
}
else
{
printf("Failed to load texture.");
}
stbi_image_free(data);
unsigned int texture2;
glGenTextures(1, &texture2);
glBindTexture(GL_TEXTURE_2D, texture2);
// set the texture wrapping/filtering options (on the currently bound texture object)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
data = stbi_load("./res/awesomeface.png", &width, &height, &nrChannels, 0);
if (data)
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
}
stbi_image_free(data);
glUseProgram(shaderProgramOrange);
glUniform1i(glGetUniformLocation(shaderProgramOrange, "texture1"), 0);
glUniform1i(glGetUniformLocation(shaderProgramOrange, "texture2"), 1);
//#FREE RAM
glDeleteShader(vertexShader);
glDeleteShader(fragmentShaderOrange);
mat4 projection;
glm_perspective(glm_rad(45.0f), 800.0f / 600.0f, 0.1f, 100.0f, projection);
unsigned int projectionLoc = glGetUniformLocation(shaderProgramOrange, "projection");
glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, projection[0]);
// uncomment this call to draw in wireframe polygons.
//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
while(!glfwWindowShouldClose(window)) {
processInput(window);
float currentFrame = glfwGetTime();
deltaTime = currentFrame - lastFrame;
lastFrame = currentFrame;
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(shaderProgramOrange);
glBindVertexArray(VAO);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture1);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, texture2);
vec3 cameraTarget;
glm_vec3_add(cameraFront, cameraPos, cameraTarget);
mat4 view;
glm_lookat(
cameraPos,
cameraTarget,
cameraUp,
view);
unsigned int viewLoc = glGetUniformLocation(shaderProgramOrange, "view");
glUniformMatrix4fv(viewLoc, 1, GL_FALSE, view[0]);
for(unsigned int i = 0; i < 10; i++) {
mat4 model;
glm_mat4_identity(model);
glm_translate(model, cubePositions[i]);
glm_rotate(model, glm_rad(20.0f * i), (vec3){1.0f, 0.3f, 0.5f});
unsigned int modelLoc = glGetUniformLocation(shaderProgramOrange, "model");
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, model[0]);
glDrawArrays(GL_TRIANGLES, 0, 36);
}
//glDrawArrays(GL_TRIANGLES, 0, 3);
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwTerminate();
return 0;
}
- 编辑3**
我尝试了一些更老的调试方法,也就是注解每一行代码,然后一个接一个地分解它们,直到我看到崩溃。我得到了一些新的东西,一个38900 bus error bin/game
,当调用我写的函数来编译着色器时。这些函数从文件中读取着色器,将它们作为字符串传递给GLSL,GLSL编译它们并返回它们。
你可以看到下面的代码片段,它是这样做的。它是工作之前,我的重构和我一定要更新我的路径时,我移动的文件
void compile_shader(GLuint* shaderId, GLenum shaderType, int shaderFilePath)
{
GLint isCompiled = 0;
/* Calls the Function that loads the Shader source code from a file */
const char* shaderSource = getShader(shaderFilePath);
*shaderId = glCreateShader(shaderType);
if(*shaderId == 0) {
printf("COULD NOT LOAD SHADER: %d!\n", shaderFilePath);
}
glShaderSource(*shaderId, 1, (const char**)&shaderSource, NULL);
glCompileShader(*shaderId);
glGetShaderiv(*shaderId, GL_COMPILE_STATUS, &isCompiled);
if(isCompiled == GL_FALSE) { /* Here You should provide more error details to the User*/
printf("Shader Compiler Error: %d\n", shaderFilePath);
glDeleteShader(*shaderId);
return;
}
}
1条答案
按热度按时间njthzxwz1#
问题解决了。我绝对是一个C新手,问题只不过是相对于源代码的相对路径,而不是相对于我运行代码的地方。我仍然很惊讶,像这样一个简单的错误,让我想考虑我的生活选择了,但我很高兴现在这个错误得到了解决。
我非常尊重我的纯C开发伙伴,用支持良好调试的语言编写代码显然是在轻松模式下编写代码。