OpenGL - 一次将所有数据传递到着色器时遇到问题
OpenGL - trouble passing ALL data into shader at once
我正在尝试使用 opengl 3.3 在四边形(2 个三角形)上显示纹理
在四边形上绘制纹理效果很好;然而,当我有一个纹理(精灵图集)但使用 2 个四边形(对象)来显示图集的不同部分时。在绘制循环中,它们最终会在各自的翻译位置切换回来和第四个(一个消失而不是再次出现,等等)。
我绘制它的方式不是每个四边形(或对象)的标准 DrawElements 但我将所有四边形、uv、平移等打包,将它们作为一个大块发送到着色器(如 "in"变量):顶点着色器:
#version 330 core
// Input vertex data, different for all executions of this shader.
in vec3 vertexPosition_modelspace;
in vec3 vertexColor;
in vec2 vertexUV;
in vec3 translation;
in vec4 rotation;
in vec3 scale;
// Output data ; will be interpolated for each fragment.
out vec2 UV;
// Output data ; will be interpolated for each fragment.
out vec3 fragmentColor;
// Values that stay constant for the whole mesh.
uniform mat4 MVP;
...
void main(){
mat4 Model = mat4(1.0);
mat4 t = translationMatrix(translation);
mat4 s = scaleMatrix(scale);
mat4 r = rotationMatrix(vec3(rotation), rotation[3]);
Model *= t * r * s;
gl_Position = MVP * Model * vec4 (vertexPosition_modelspace,1); //* MVP;
// The color of each vertex will be interpolated
// to produce the color of each fragment
fragmentColor = vertexColor;
// UV of the vertex. No special space for this one.
UV = vertexUV;
}
顶点着色器是否像我认为的那样在处理大量数据时工作 - 它绘制每个段作为统一单独传递,因为它看起来不像它?我的思路对吗?
为了完整起见,这是我的片段着色器:
#version 330 core
// Interpolated values from the vertex shaders
in vec3 fragmentColor;
// Interpolated values from the vertex shaders
in vec2 UV;
// Ouput data
out vec4 color;
// Values that stay constant for the whole mesh.
uniform sampler2D myTextureSampler;
void main()
{
// Output color = color of the texture at the specified UV
color = texture2D( myTextureSampler, UV ).rgba;
}
有人请求提供更多信息,因此我将介绍如何将这些数据绑定到顶点着色器。以下代码只是我用于翻译的代码。我有更多关于颜色、旋转、比例、紫外线等的信息:
gl.BindBuffer(gl.ARRAY_BUFFER, tvbo)
gl.BufferData(gl.ARRAY_BUFFER, len(data.Translations)*4, gl.Ptr(data.Translations), gl.DYNAMIC_DRAW)
tAttrib := uint32(gl.GetAttribLocation(program, gl.Str("translation\x00")))
gl.EnableVertexAttribArray(tAttrib)
gl.VertexAttribPointer(tAttrib, 3, gl.FLOAT, false, 0, nil)
...
gl.DrawElements(gl.TRIANGLES, int32(len(elements)), gl.UNSIGNED_INT, nil)
你刚刚单身sampler2D
- 这意味着您只有一个纹理供您使用
- 不管你绑定了多少。
- 如果您确实需要将数据作为单块传递
- 然后你应该为你得到的每个纹理添加采样器
- 不确定你有多少objects/textures
- 但是你受限于 gfx hw 对纹理单元的这种数据传递方式的限制
- 您还需要在数据中添加另一个值,告诉您哪个图元使用哪个纹理单元
- 然后在片段内部 select 正确的纹理采样器 ...
您应该添加如下内容:
// vertex
in int usedtexture;
out int txr;
void main()
{
txr=usedtexture;
}
// fragment
uniform sampler2D myTextureSampler0;
uniform sampler2D myTextureSampler1;
uniform sampler2D myTextureSampler2;
uniform sampler2D myTextureSampler3;
in vec2 UV;
in int txr;
out vec4 color;
void main
{
if (txr==0) color = texture2D( myTextureSampler0, UV ).rgba;
else if (txr==1) color = texture2D( myTextureSampler1, UV ).rgba;
else if (txr==2) color = texture2D( myTextureSampler2, UV ).rgba;
else if (txr==3) color = texture2D( myTextureSampler3, UV ).rgba;
else color=vec4(0.0,0.0,0.0,0.0);
}
这种传递方式不好,原因如下:
- 使用的纹理数量限于 HW 纹理单元限制
- 如果您的渲染需要额外的纹理,例如 normal/shininess/light 贴图
- 然后你需要每个对象类型超过 1 个纹理,你的限制突然除以 2,3,4...
- 片段内需要
if/switch
个语句,这会大大降低运行速度
- 是的,你可以少做早午餐,但是你需要一直访问所有纹理,无缘无故地增加 gfx 的热应力...
这种传球适合
- 单个图像中的所有纹理(如您提到的纹理图集)
- 这种方式可以更快,并且对于对象类型(或材质)数量较少但对象数量较多的场景是合理的...
由于我需要更多关于此事的意见,我 link 将此页面编辑到 reddit,有人能够帮助我做出回应!无论如何,reddit link 在这里:
https://www.reddit.com/r/opengl/comments/3gyvlt/opengl_passing_all_scene_data_into_shader_each/
在将所有顶点作为一个数据结构传递给顶点着色器后看到两个单独的 textures/quads 的问题是因为我的元素索引已关闭。我需要为我的 2 个三角形(四边形)对象确定每组顶点的正确索引。只需要做这样的事情:
vertexInfo.Elements = append(vertexInfo.Elements, uint32(idx*4), uint32(idx*4+1), uint32(idx*4+2), uint32(idx*4), uint32(idx*4+2), uint32(idx*4+3))
我正在尝试使用 opengl 3.3 在四边形(2 个三角形)上显示纹理
在四边形上绘制纹理效果很好;然而,当我有一个纹理(精灵图集)但使用 2 个四边形(对象)来显示图集的不同部分时。在绘制循环中,它们最终会在各自的翻译位置切换回来和第四个(一个消失而不是再次出现,等等)。
我绘制它的方式不是每个四边形(或对象)的标准 DrawElements 但我将所有四边形、uv、平移等打包,将它们作为一个大块发送到着色器(如 "in"变量):顶点着色器:
#version 330 core
// Input vertex data, different for all executions of this shader.
in vec3 vertexPosition_modelspace;
in vec3 vertexColor;
in vec2 vertexUV;
in vec3 translation;
in vec4 rotation;
in vec3 scale;
// Output data ; will be interpolated for each fragment.
out vec2 UV;
// Output data ; will be interpolated for each fragment.
out vec3 fragmentColor;
// Values that stay constant for the whole mesh.
uniform mat4 MVP;
...
void main(){
mat4 Model = mat4(1.0);
mat4 t = translationMatrix(translation);
mat4 s = scaleMatrix(scale);
mat4 r = rotationMatrix(vec3(rotation), rotation[3]);
Model *= t * r * s;
gl_Position = MVP * Model * vec4 (vertexPosition_modelspace,1); //* MVP;
// The color of each vertex will be interpolated
// to produce the color of each fragment
fragmentColor = vertexColor;
// UV of the vertex. No special space for this one.
UV = vertexUV;
}
顶点着色器是否像我认为的那样在处理大量数据时工作 - 它绘制每个段作为统一单独传递,因为它看起来不像它?我的思路对吗?
为了完整起见,这是我的片段着色器:
#version 330 core
// Interpolated values from the vertex shaders
in vec3 fragmentColor;
// Interpolated values from the vertex shaders
in vec2 UV;
// Ouput data
out vec4 color;
// Values that stay constant for the whole mesh.
uniform sampler2D myTextureSampler;
void main()
{
// Output color = color of the texture at the specified UV
color = texture2D( myTextureSampler, UV ).rgba;
}
有人请求提供更多信息,因此我将介绍如何将这些数据绑定到顶点着色器。以下代码只是我用于翻译的代码。我有更多关于颜色、旋转、比例、紫外线等的信息:
gl.BindBuffer(gl.ARRAY_BUFFER, tvbo)
gl.BufferData(gl.ARRAY_BUFFER, len(data.Translations)*4, gl.Ptr(data.Translations), gl.DYNAMIC_DRAW)
tAttrib := uint32(gl.GetAttribLocation(program, gl.Str("translation\x00")))
gl.EnableVertexAttribArray(tAttrib)
gl.VertexAttribPointer(tAttrib, 3, gl.FLOAT, false, 0, nil)
...
gl.DrawElements(gl.TRIANGLES, int32(len(elements)), gl.UNSIGNED_INT, nil)
你刚刚单身sampler2D
- 这意味着您只有一个纹理供您使用
- 不管你绑定了多少。
- 如果您确实需要将数据作为单块传递
- 然后你应该为你得到的每个纹理添加采样器
- 不确定你有多少objects/textures
- 但是你受限于 gfx hw 对纹理单元的这种数据传递方式的限制
- 您还需要在数据中添加另一个值,告诉您哪个图元使用哪个纹理单元
- 然后在片段内部 select 正确的纹理采样器 ...
您应该添加如下内容:
// vertex
in int usedtexture;
out int txr;
void main()
{
txr=usedtexture;
}
// fragment
uniform sampler2D myTextureSampler0;
uniform sampler2D myTextureSampler1;
uniform sampler2D myTextureSampler2;
uniform sampler2D myTextureSampler3;
in vec2 UV;
in int txr;
out vec4 color;
void main
{
if (txr==0) color = texture2D( myTextureSampler0, UV ).rgba;
else if (txr==1) color = texture2D( myTextureSampler1, UV ).rgba;
else if (txr==2) color = texture2D( myTextureSampler2, UV ).rgba;
else if (txr==3) color = texture2D( myTextureSampler3, UV ).rgba;
else color=vec4(0.0,0.0,0.0,0.0);
}
这种传递方式不好,原因如下:
- 使用的纹理数量限于 HW 纹理单元限制
- 如果您的渲染需要额外的纹理,例如 normal/shininess/light 贴图
- 然后你需要每个对象类型超过 1 个纹理,你的限制突然除以 2,3,4...
- 片段内需要
if/switch
个语句,这会大大降低运行速度 - 是的,你可以少做早午餐,但是你需要一直访问所有纹理,无缘无故地增加 gfx 的热应力...
这种传球适合
- 单个图像中的所有纹理(如您提到的纹理图集)
- 这种方式可以更快,并且对于对象类型(或材质)数量较少但对象数量较多的场景是合理的...
由于我需要更多关于此事的意见,我 link 将此页面编辑到 reddit,有人能够帮助我做出回应!无论如何,reddit link 在这里:
https://www.reddit.com/r/opengl/comments/3gyvlt/opengl_passing_all_scene_data_into_shader_each/
在将所有顶点作为一个数据结构传递给顶点着色器后看到两个单独的 textures/quads 的问题是因为我的元素索引已关闭。我需要为我的 2 个三角形(四边形)对象确定每组顶点的正确索引。只需要做这样的事情:
vertexInfo.Elements = append(vertexInfo.Elements, uint32(idx*4), uint32(idx*4+1), uint32(idx*4+2), uint32(idx*4), uint32(idx*4+2), uint32(idx*4+3))