我一直在尝试让动态游戏对象将制服作为制服块传递给片段着色器,为了简单起见,在一些样板代码中显示了一个制服。代码编译,顶点和片段着色器也正确编译,但没有显示任何内容,这意味着我没有正确传递制服。
#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;
}
我尝试过使用这样的统一块:
struct Swordsman
{
float health;
float attackStrength;
};
layout (std140) uniform uSwordsmanBlock
{
Swordsman swordsman[MAX_NUM_SWORDSMAN];
int num;
};
并索引到
uSwordsmanBlock.swordsman[i]
,但它会导致编译错误。我也尝试过 GLint uNumSwordsman = glGetUniformLocation(shaderProgram_id, "uSwordsmanBlock.num"); assert(uNumSwordsman != GL_INVALID_INDEX);
,ChatGPT 告诉我这“不是问题”并且我的代码“工作正常”。
您似乎签署了
std140
布局,但没有意识到它对数组意味着什么:(OpenGL 4.5秒7.6.2.2“标准统一块布局”)
如果成员是标量或向量数组,则基本对齐和数组 stride 设置为匹配单个数组元素的基本对齐方式,根据 符合规则 (1)、(2) 和 (3),并向上舍入到 vec4 的基本对齐方式。这 数组末尾可能有填充;以下成员的基本偏移量 数组向上舍入到基本对齐的下一个倍数。
换句话说,每个
Swordsman
必须按16字节对齐。抄袭这个答案:
struct alignas(16) Swordsman
{
float health;
float attackStrength;
};
或者,更简单的是,将 UBO 布局切换到
std430
布局,即
与 std140 类似,只是对标量和向量元素的数组和结构的对齐和步幅进行了一些优化(除了 vec3 元素,它们与 std140 保持不变)。具体来说,它们不再四舍五入为 16 字节的倍数。因此
的数组将与float
的 C++ 数组匹配。float