【问题标题】:OpenGL HeightMap with vertex shader and QGLShaderProgram带有顶点着色器和 QGLShaderProgram 的 OpenGL 高度图
【发布时间】:2013-11-07 10:30:07
【问题描述】:

我想根据高度渲染地形并应用颜色。
我正在写一个 Qt 项目,所以使用 QGlShaderProgram。

我的地形网格是从 (0,0,0) 到 (1000,0,1000) 并且每 100 个长度单位放置一个顶点。我想使用统一数组将数据传输到着色器。

我仍然无法将数据发送到着色器。

从 C++/Qt 调用:

QGLShaderProgram  mShader;
QVector< GLfloat> mHeightMap (10*10, some_data);
GLfloat           mXStepSize = 100;
GLfloat           mZStepSize = 100;
// ..
mShader.link();
mShader.bind();
mShader.setUniformValueArray( "heights",
                               &(mHeightMap[0]),       // one line after another
                               mHeightMap.size(), 1 );
mShader.setUniformValue( "x_res", (GLint) mXStepSize);
mShader.setUniformValue( "z_res", (GLint) mZStepSize);

着色器来源:

uniform sampler2D heights;
uniform int       x_res;
uniform int       z_res;
void main(void)
{
       vec4 tmp         = gl_Vertex;
       vec4 h;
       float x_coord    = gl_Vertex[0] * 0.001;
       float z_coord    = gl_Vertex[2] * 0.001;

       // interprete as 2D:
       int element      = int( (x_coord + float(x_res)*z_coord) );

       h                = texture2D( heights, vec2(x_coord, z_coord));
       gl_FrontColor    = gl_Color;
       gl_FrontColor[1] = h[ element];     // set color by height
       tmp.y            = h[ element];     // write height to grid
       gl_Position      = gl_ModelViewProjectionMatrix * tmp;
}

我的错误在哪里?
我应该如何将数据加载到着色器然后在那里访问它?

【问题讨论】:

  • 可能使用 mHeightMap.constData() 而不是 &(mHeightMap[0])
  • 使用 mHeightMap.constData(),因为向量实际上更长,我传递 &(mHeigtMap[data_start])
  • 你可以使用&(mHeightMap.constData()[data_start]),这样更安全
  • 答案已编辑,应该更清楚

标签: c++ qt opengl


【解决方案1】:

您想将其作为纹理传递,您必须首先使用 glTexImage2D 将数组映射 (mHeightMap) 转换为 opengl 纹理。 看看这个,它可能就是你要找的东西:https://gamedev.stackexchange.com/questions/45188/how-can-i-pass-an-array-of-floats-to-the-fragment-shader-using-textures

编辑:您可能想对其进行一些调整,但这就是想法:

//Create texture: 
glint texture;
glActiveTexture(GL_TEXTURE0);
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);  
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);  
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);  
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);  
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);  
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Width, Height, 0, GL_RGBA,
GL_UNSIGNED_BYTE, &(mHeightMap.constData()[data_start]));

//pass it to shader
glint uniformId = glGetUniformid(shader, "height");
glActiveTexture(GL_TEXTURE0);   
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texture);  
glUniform1i(uniformId, 0); // 0 is the texture number

【讨论】:

  • 感谢您的详细回答,但仍然存在一些问题:1)我手头只有 OpenGL 3(所以没有 glUniform1i)2)我正在插入一个浮点数组,但是这样获取数组着色器中的 vec4(如果理解正确)
  • 是否可以使用 QGlShaderProgram 做到这一点?
  • 这段代码是用opengl 3.1完成的,所以glUniform1i应该在GL3中,我不知道Qt所以我不知道QGlShaderProgram。 glTexImage2D 用于纹理加载,我认为它不能以 vec4 结尾。
  • 我想通了 - 请参阅(我的)答案
【解决方案2】:

(代码现在似乎可以工作了)

在 izissise 的帮助下,我想出了大部分。我使用 GL_TEXTURE_RECTANGLE 而不是 GL_TEXTURE_2D。
它仍然只使用红色通道(这可能会被优化)。

这是我的初始化

QGLShaderProgram    mShader;
QVector< GLfloat> mHeightMap (width * height * state_count, 
                              some_data);
mShader.link();

// init texture
glActiveTexture(GL_TEXTURE0);
glGenTextures(1, &mShaderTexture);
glBindTexture(GL_TEXTURE_RECTANGLE, mShaderTexture);


向着色器发送数据(可以根据需要多次重复):

mShader.bind();
// ..
glTexImage2D(GL_TEXTURE_RECTANGLE, 0, GL_RED,
             width, depth, 0,
             GL_RED, GL_FLOAT,
             &(mHeightMap.constData()[mHeightMapPos])); // set portion of vector as array to texture / sampler
glActiveTexture(GL_TEXTURE0);
glEnable(GL_TEXTURE_RECTANGLE);
glBindTexture(GL_TEXTURE_RECTANGLE, mShaderTexture);
mShader.setUniformValue( "max_height",  (GLfloat) (250.0) );
mShader.setUniformValue( "x_steps",     (GLint) width);
mShader.setUniformValue( "z_steps",     (GLint) height);

// ..
mShader.release();


以及着色器源

uniform int     x_steps;
uniform int     z_steps;
uniform sampler2DRect heights;
uniform float   max_height;

void main(void)
{
    vec4 tmp         = gl_Vertex;
    vec4 h;

    float x_coord    = gl_Vertex[0] * 0.001 * float(x_steps-1);
    float z_coord    = gl_Vertex[2] * 0.001 * float(z_steps-1);
    h                = texture2DRect( heights, ivec2(int(x_coord), int(z_coord)) );
    tmp.y            = max_height * (h.r);

    gl_FrontColor    = gl_Color;
    gl_FrontColor[1] = h.r;

    gl_Position      = gl_ModelViewProjectionMatrix * tmp;
}

【讨论】:

  • 太棒了!!,顺便说一句,那些行:glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);不是必须的,更多的是为了有更好的纹理渲染,但既然你拥有的并不是真正的纹理,我认为你可以把它们拿出来
  • 另外我不明白你的代码示例中的 sampler2DRect 高度是如何均匀的;绑定到正确的纹理。有什么线索吗?
  • @izissise:我删除了这 4 行;对于 binding:我不确定,但我认为只有 1 个纹理,所以没问题。尽管如此,高度并没有正确地传输到着色器,或者我在阅读它们时错过了一些东西 - 一旦我得到它,我会更新代码。
  • 我做了一些其他测试,但我忘记了纹理的插值 - 它应该像上面写的那样工作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-01
  • 1970-01-01
  • 2016-09-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多