OpenGL实例渲染,每个实例颜色和&抵消

时间:2013-10-04 00:17:29

标签: 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。

UPDATE2:

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

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

2 个答案:

答案 0 :(得分:2)

label属性的问题是,它是一个整数属性,但不要将其设置为整数属性。 Qt的setAttributeBuffer函数对整数属性一无所知,它们全都使用glVertexAttribPointer,它以任意格式获取顶点数据并将其转换为float以将其传递给in float属性,与着色器中的in int不匹配(因此该属性可能只保留一些随机默认值,或者获取一些未定义的值)。

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

GL_DOUBLE

代替glVertexAttribIPointer(cubeShaderProgram_.attributeLocation("cube_label"), 1, GL_INT, sizeof(CubeInfo), static_cast<const char*>(0)+offsetof(CubeInfo,labelId)); 来电,或使用cubeShaderProgram_.setAttributeBuffer属性。

答案 1 :(得分:0)

如果你想使用顶点着色器中指定的颜色,你至少应该写一个简单的片段着色器,如:

void main()
{
   gl_FragColor = color_out;
}

<强>更新

我认为你不能将cube_label传递给你的顶点着色器,或者你没有在第一个位置(在结构中)设置它们。后者更有可能,但您可以使用以下行替换您的switch-case以查看传递的实际值。

color_out = vec4(float(cube_label) / 4.0, 0, 0, 1.0); 

<强> UPDATE2

一旦我遇到与英特尔GPU(驱动程序)类似的问题。无论我尝试什么都无法传递整数值。但是,同样的着色器在NVIDIA上完美运行,因此在你的情况下我将int转换为float。