c++ - 使用每个实例颜色和偏移的 OpenGL 实例渲染

标签 c++ qt opengl glsl shader

您好,我正在尝试使用 glDrawArraysInstanced() 渲染大量轴对齐的立方体。每个固定大小的立方体只能在其中心位置和颜色上有所不同。此外,每个立方体只需要几种不同的颜色。所以我想潜在地渲染数百万个立方体,每个实例数据如下:

struct CubeInfo {
  Eigen::Vector3f center; // center of the cube (x,y,z)
  int labelId;  // label of the cube which affects its color
};

所以我正在使用以下顶点着色器:

#version 330

uniform mat4 mvp_matrix;

//regular vertex attributes
layout(location = 0) in vec3 vertex_position;

// Per Instance variables
layout(location = 1) in vec3 cube_center;
layout(location = 2) in int cube_label;

// color out to frag shader
out vec4 color_out;

void main(void) {
  // Add offset cube_center
  vec4 new_pos = vec4(vertex_position + cube_center, 1);
  // Calculate vertex position in screen space
  gl_Position = mvp_matrix * new_pos;

  // Set color_out based on label
  switch (cube_label) {
  case 1:
    color_out = vec4(0.5, 0.25, 0.5, 1);
    break;
  case 2:
    color_out = vec4(0.75, 0.0, 0.0, 1);
    break;
  case 3:
    color_out = vec4(0.0, 0.0, 0.5, 1);
    break;
  case 4:
    color_out = vec4(0.75, 1.0, 0.0, 1);
    break;
  default:
    color_out = vec4(0.5, 0.5, 0.5, 1); // Grey
    break;
  }
}

和相应的片段着色器:

#version 330

in vec4 color_out;
out vec4 fragColor;

void main()
{
    // Set fragment color from texture
    fragColor = color_out;
}

但是 color_out 始终采用默认灰度值,即使 cube_label 值在 1 到 4 之间。这是我的问题。我在上面的着色器中做错了什么吗**?**

我用 1-4 之间的随机 labelIds 初始化了 cubeInfo vbo。所以我期待看到一个丰富多彩的输出而不是以下内容: enter image description here

这是我的渲染代码,它使用了 Qt 的 QGLShaderProgramQGLBuffer包装器:

  // Enable back face culling
  glEnable(GL_CULL_FACE);
  cubeShaderProgram_.bind();

  // Set the vertexbuffer stuff (Simply 36 vertices for cube)
  cubeVertexBuffer_.bind();
  cubeShaderProgram_.setAttributeBuffer("vertex_position", GL_FLOAT, 0, 3, 0);
  cubeShaderProgram_.enableAttributeArray("vertex_position");
  cubeVertexBuffer_.release();

  // Set the per instance buffer stuff
  cubeInstanceBuffer_.bind();

  cubeShaderProgram_.setAttributeBuffer("cube_center", GL_FLOAT, offsetof(CubeInfo,center), 3, sizeof(CubeInfo));
  cubeShaderProgram_.enableAttributeArray("cube_center");
  int center_location = cubeShaderProgram_.attributeLocation("cube_center");
  glVertexAttribDivisor(center_location, 1);

  cubeShaderProgram_.setAttributeBuffer("cube_label", GL_INT, offsetof(CubeInfo,labelId), 1, sizeof(CubeInfo));
  cubeShaderProgram_.enableAttributeArray("cube_label");
  int label_location = cubeShaderProgram_.attributeLocation("cube_label");
  glVertexAttribDivisor(label_location, 1);

  cubeInstanceBuffer_.release();

  // Do Instanced Renering
  glDrawArraysInstanced(GL_TRIANGLES, 0, 36, displayed_num_cubes_ );

  cubeShaderProgram_.disableAttributeArray("vertex_position");
  cubeShaderProgram_.disableAttributeArray("cube_center");
  cubeShaderProgram_.disableAttributeArray("cube_label");

  cubeShaderProgram_.release();

除了我上面的主要问题(颜色问题),这是制作 Minecraft 的好方法吗?

更新 如果我将 CubeInfo.labelId 属性从 int 更改为 float,并且相应的顶点着色器变量 cube_label 也更改为 float ,它有效!!为什么会这样? This page说 GLSL 支持 int 类型。对我来说,我更喜欢 labelId/cube_label 是一些 int/short。

更新2:

即使我只是在渲染代码的以下行中更改为 GL_FLOAT 而不是 GL_INT,我也会得到正确的颜色。

cubeShaderProgram_.setAttributeBuffer("cube_label", GL_INT, offsetof(CubeInfo,labelId), 1, sizeof(CubeInfo));

最佳答案

标签属性的问题是,它是一个整数属性,但您没有将它设置为整数属性。 Qt 的 setAttributeBuffer 函数对整数属性一无所知,它们都使用 glVertexAttribPointer在引擎盖下,它以任意格式获取顶点数据并将其转换为 float 以将其传递给 in float 属性,该属性与 不匹配in int 从你的着色器(所以属性可能只是保持在一些随机的默认值,或者得到一些未定义的值)。

要将数据实际传递到真正的整数顶点属性(这与浮点属性完全不同,直到 GL 3+ 才引入),您需要函数 glVertexAttribIPointer(注意 I 和类似的 D 用于 in double 属性,仅使用 GL_DOUBLE 在这种情况下也不起作用).但令人遗憾的是,Qt 还不是真正适合 GL 3+,似乎没有包装器。所以你要么必须手动使用:

glVertexAttribIPointer(cubeShaderProgram_.attributeLocation("cube_label"), 
                       1, GL_INT, sizeof(CubeInfo), 
                       static_cast<const char*>(0)+offsetof(CubeInfo,labelId));

而不是 cubeShaderProgram_.setAttributeBuffer 调用,或者使用 in float 属性。

关于c++ - 使用每个实例颜色和偏移的 OpenGL 实例渲染,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19171188/

相关文章:

c++ - Qt5 延迟加载 opengl32.dll 失败

View 空间中的 openGL 立方体贴图反射是错误的

c++ - 纹理数组,创建纹理

C++ 预处理器指令

c++ - QPlugin路径和初始化

qt - 在 Qt 中通过 Windows GDI 绘制

c++ - 从每列具有不同数量值的文件中读取值,C++

C++ 使用 "-"操作数和 list.back()

java - C++保存和导入外部可执行结果而不写入磁盘

c++ - 使用字符串替换函数用初始化变量替换字符串的一部分?