动态游戏对象Uniform Block未正确传递Uniform问题排查
问题:Uniform Block无法正确传递动态数据到片段着色器
我尝试通过Uniform Block将动态游戏对象的Uniform传递至片段着色器,代码及顶点、片段着色器均编译正常,但画面无任何显示,说明Uniform未正确传递。
#include <SDL2/SDL.h> #include <GL/glew.h> #include <glm/glm.hpp> #include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/type_ptr.hpp> #include <iostream> // Compile // g++ test.cpp -lSDL2 -lGLEW -lGL -lglut // point type for vertices of drawing plane typedef struct { GLfloat vec2[2]; } point_t; // Drawing plane const point_t drawing_plane_vertices[4] = { {-1.0, -1.0 }, { 1.0, -1.0 }, { 1.0, 1.0 }, {-1.0, 1.0 }, }; typedef struct { float health; float attackStrength; } Swordsman_t; const GLuint MAX_NUM_SWORDSMAN = 100; // Vertex shader source const char* vertexShaderSource = R"( #version 430 core layout (location = 0) in vec2 position; out vec2 texCoord; void main() { gl_Position = vec4(position.x, position.y, 0.0f, 1.0f); } )"; // Fragment shader source const char* fragmentShaderSource = R"( #version 430 core #define MAX_NUM_SWORDSMAN 100 struct Swordsman { float health; float attackStrength; }; layout (std140) uniform uSwordsmanBlock { Swordsman swordsman[MAX_NUM_SWORDSMAN]; int num; } uSwordsmanBlock_t; uniform vec2 uresolution; uniform float iTime; vec2 fragCoord = gl_FragCoord.xy; out vec4 fragColor; void main(void) { vec2 uv = fragCoord / uresolution * 2.0 - 1.0; uv.x *= (uresolution.x / uresolution.y); if (uSwordsmanBlock_t.num == 4) { // first problem this line isn't triggered. fragColor = vec4(1.0, 0.0, 0.0, 1.0); } else { // nothing, just black vec4 color = vec4(0.0); color.r = uSwordsmanBlock_t.swordsman[0].attackStrength; color.g = uSwordsmanBlock_t.swordsman[1].attackStrength; color.b = uSwordsmanBlock_t.swordsman[2].attackStrength; color.a = uSwordsmanBlock_t.swordsman[3].attackStrength; fragColor = vec4(color); } } )"; int main() { // Initialize SDL assert(SDL_Init(SDL_INIT_VIDEO) >= 0); // Set OpenGL context attributes SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 6); SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); // Full screen desktop display mode SDL_DisplayMode fullscreen_desktopm; assert(SDL_GetDesktopDisplayMode(0, &fullscreen_desktopm) == 0); // Create SDL window SDL_Window* sdl_window = SDL_CreateWindow("OpenGL Circle Example", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, fullscreen_desktopm.w, fullscreen_desktopm.h, SDL_WINDOW_OPENGL); assert(sdl_window); SDL_SetWindowFullscreen(sdl_window, SDL_WINDOW_FULLSCREEN_DESKTOP); // Create OpenGL context SDL_GLContext gl_context = SDL_GL_CreateContext(sdl_window); assert(gl_context); // Initialize GLEW assert(glewInit() == GLEW_OK); // Compile and link shaders GLuint vertexShader_id = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vertexShader_id, 1, &vertexShaderSource, nullptr); glCompileShader(vertexShader_id); GLuint fragmentShader_id = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fragmentShader_id, 1, &fragmentShaderSource, nullptr); glCompileShader(fragmentShader_id); GLuint shaderProgram_id = glCreateProgram(); glAttachShader(shaderProgram_id, vertexShader_id); glAttachShader(shaderProgram_id, fragmentShader_id); glLinkProgram(shaderProgram_id); // Check shader compilation and linking errors GLint success; GLchar infoLog[512]; glGetShaderiv(vertexShader_id, GL_COMPILE_STATUS, &success); if (!success) { glGetShaderInfoLog(vertexShader_id, 512, nullptr, infoLog); std::cerr << "Vertex shader compilation failed: " << infoLog << std::endl; return -1; } glGetShaderiv(fragmentShader_id, GL_COMPILE_STATUS, &success); if (!success) { glGetShaderInfoLog(fragmentShader_id, 512, nullptr, infoLog); std::cerr << "Fragment shader compilation failed: " << infoLog << std::endl; return -1; } glGetProgramiv(shaderProgram_id, GL_LINK_STATUS, &success); if (!success) { glGetProgramInfoLog(shaderProgram_id, 512, nullptr, infoLog); std::cerr << "Shader program linking failed: " << infoLog << std::endl; return -1; } // Illustrating dynamic drawing using uniform block // This would would be done with dynamic allocation... int numSwordsman = 4; // Example Swordsman struct objects Swordsman_t sm1 = {50.0, 0.0f}; Swordsman_t sm2 = {25.0, 1.0f}; Swordsman_t sm3 = {100.0, 0.0f}; Swordsman_t sm4 = {15.0, 1.0f}; Swordsman_t Swordsmen[numSwordsman] = {sm1, sm2, sm3, sm4}; GLuint uSwordsmanBlock = glGetUniformBlockIndex(shaderProgram_id, "uSwordsmanBlock"); assert(uSwordsmanBlock != GL_INVALID_INDEX); GLuint swordsmanuniformblock_id = 0; glUniformBlockBinding(shaderProgram_id, uSwordsmanBlock, swordsmanuniformblock_id); // Size of swords man block for use with subdata bind GLint blocksize = numSwordsman * sizeof(Swordsman_t); GLuint ubo_swordsman_id; glGenBuffers(1, &ubo_swordsman_id); glBindBuffer(GL_UNIFORM_BUFFER, ubo_swordsman_id); glBufferData(GL_UNIFORM_BUFFER, blocksize, nullptr, GL_DYNAMIC_DRAW); glBindBufferBase(GL_UNIFORM_BUFFER, uSwordsmanBlock, ubo_swordsman_id); glDeleteShader(vertexShader_id); glDeleteShader(fragmentShader_id); // Vertex Buffer Object (VBO) and Vertex Array Object (VAO) setup GLuint vbo_id, vao_id; glGenVertexArrays(1, &vao_id); glBindVertexArray(vao_id); glGenBuffers(1, &vbo_id); glBindBuffer(GL_ARRAY_BUFFER, vbo_id); glBufferData(GL_ARRAY_BUFFER, sizeof(drawing_plane_vertices), drawing_plane_vertices, GL_STATIC_DRAW); // Position attribute glEnableVertexAttribArray(0); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (void*)0); // Unbind vao_id glBindVertexArray(0); // Main loop bool quit = false; SDL_Event event; GLint resolutionLoc = glGetUniformLocation(shaderProgram_id, "uresolution"); GLint itimeLoc = glGetUniformLocation(shaderProgram_id, "iTime"); float outerlcount = 0; while (!quit) { Uint64 tickstartc = SDL_GetPerformanceCounter(); while (SDL_PollEvent(&event)) { if (event.type == SDL_QUIT) { quit = true; break; } else if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_ESCAPE) { quit = true; break; } } // Clear the buffer glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); // Use the shader program glUseProgram(shaderProgram_id); glUniform2f(resolutionLoc, static_cast<float>(fullscreen_desktopm.w), static_cast<float>(fullscreen_desktopm.h)); glUniform1f(itimeLoc, outerlcount); // dynamic uniforms GLint blockindex = glGetUniformLocation(shaderProgram_id, "uSwordsmanBlock"); glUniformBlockBinding(shaderProgram_id, blockindex, swordsmanuniformblock_id); glBindBuffer(GL_ARRAY_BUFFER, ubo_swordsman_id); // bound to correct buffer for this next operation. glBufferSubData(GL_UNIFORM_BUFFER, 0, numSwordsman * sizeof(Swordsman_t), Swordsmen); glUniform1i(glGetUniformLocation(shaderProgram_id, "uSwordsmanBlock.num"), numSwordsman); glBindBuffer(GL_ARRAY_BUFFER, 0); // Drawing plane vertices glBindVertexArray(vao_id); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); // Swap the front and back buffers SDL_GL_SwapWindow(sdl_window); // Unbind vao_id and shader program // glBindBufferBase(GL_UNIFORM_BUFFER, 0); glBindVertexArray(0); glUseProgram(0); Uint64 tendc = SDL_GetPerformanceCounter(); float t_elapsedms = (tendc - tickstartc) / static_cast<float>(SDL_GetPerformanceCounter()) * 1000.0f; SDL_Delay(floor(5.0f - t_elapsedms)); outerlcount += 0.1; } // Cleanup glDeleteVertexArrays(1, &vao_id); glDeleteBuffers(1, &vbo_id); SDL_GL_DeleteContext(gl_context); SDL_DestroyWindow(sdl_window); SDL_Quit(); return 0; }
尝试过的解决方法
- 曾使用以下GLSL代码定义Uniform Block:
struct Swordsman { float health; float attackStrength; }; layout (std140) uniform uSwordsmanBlock { Swordsman swordsman[MAX_NUM_SWORDSMAN]; int num; };
尝试通过uSwordsmanBlock.swordsman[i]访问时,会导致编译错误。
- 也尝试过通过
glGetUniformLocation获取uSwordsmanBlock.num的位置:
GLint uNumSwordsman = glGetUniformLocation(shaderProgram_id, "uSwordsmanBlock.num"); assert(uNumSwordsman != GL_INVALID_INDEX);
但问题仍未解决。
内容的提问来源于stack exchange,提问作者26F
相关产品推荐
相关产品推荐

