我正在使用OpenTK,它是.NET的包装器。使用的OpenGL版本是由NVIDIA实现的4.5。我使用的是Windows 10 Pro。
我的问题很简单。我想通过名称来解决顶点属性,而不是在着色器源中对它们的位置进行硬编码。
我有一个名为 basicTexturedVert.glsl 的顶点着色器
#version 450 core
in vec4 position;
in vec2 normal;
uniform mat4 modelMatrix;
uniform mat4 viewMatrix;
uniform mat4 projectionMatrix;
out vec2 vs_uv;
void main(void)
{
vs_uv = normal;
gl_Position = projectionMatrix * viewMatrix * modelMatrix * position;
}
现在要这样做,通常我必须在程序中使用属性的名称进行GL.GetAttribLocation,它将返回它的位置。好吧,我尝试了所有内容,但它只返回in vec4 position
而不是in vec2 normal
的位置。我的意思是:
GL.GetAttribLocation("position")
始终返回正确的位置,但normal
的相同内容会返回-1
。normal
的名称有关,也许它是OpenGL的保留字,所以我把它改为像abcdef
这样的随机词仍然给出了相同的结果。normal
之前移动position
,结果仍然相同。position
提供正确的位置。我想也许vec2
(这是两者之间唯一的区分)不是一种可接受的类型,我在线查看,该死的很好被接受。正如你所看到的,在尝试这个之前我尝试了很多东西。我读到您可以以编程方式将属性绑定到名称并指定要选择的位置。这就是我在下面的代码中所做的。
首先,我创建我的Shader对象:
var basicTexturedVertexShader = new Shader("Basic Textured Vertex Shader",
ShaderType.VertexShader,
File.ReadAllText(@"Components\Shaders\Vertex\basicTexturedVert.glsl"),
new[] { "position", "normal" }
);
var basicTexturedFragmentShader = new Shader("Basic Textured Fragment Shader",
ShaderType.FragmentShader,
File.ReadAllText(@"Components\Shaders\Fragment\basicTexturedFrag.glsl")
);
如您所见,每个着色器都被分配:
- 一个名称,以便我可以理解我正在处理哪个着色器(在调试期间)
- 着色器的类型(VertexShader
或FragmentShader
)
- 着色器源代码
- 并且可选地包含着色器属性名称的数组,例如在程序链接期间将分配给位置的第一个new[] { "position", "normal" }
然后我创建一个程序并将它们链接到它:
_texturedProgram = new ShaderProgram(basicTexturedVertexShader, basicTexturedFragmentShader);
_texturedProgram.Link();
现在位于_texturedProgram.Link
:
int location = 0; // This is a location index that starts from 0 then goes up
foreach (var shader in _shaders) {
DebugUtil.Info($"Attaching shader {shader.Name} of handle {shader.Handle} of type {shader.Type} to program {_handle}");
GL.AttachShader(_handle, shader.Handle);
// If the shader we attached has attribute names with it
// It means we need to give them a location
if (shader.AttributeNames != null)
{
foreach (var shaderAttributeName in shader.AttributeNames)
{
_attributeLocation[shaderAttributeName] = location;
GL.BindAttribLocation(_handle, location, shaderAttributeName);
// We check if anything wrong happened and output it
ErrorCode error;
bool errorHappened = false;
while ((error = GL.GetError()) != ErrorCode.NoError) {
DebugUtil.Warning($"Problem during binding attrib location of {shaderAttributeName} of {shader.Name} to {location} in program {_handle}. Error: {error}");
errorHappened = true;
}
if (!errorHappened) {
DebugUtil.Info($"Shader attribute \"{shaderAttributeName}\" of {shader.Name} of program {Handle} SHOULD HAVE BEEN bound to location {location}");
}
location++;
}
}
}
// We link the program
GL.LinkProgram(_handle);
// Make sure the linking happened with no problem
var info = GL.GetProgramInfoLog(_handle);
if (!string.IsNullOrWhiteSpace(info)) {
DebugUtil.Warning($"Info log during linking of shaders to program {_handle}: {info}");
}
else {
DebugUtil.Info($"Program {_handle} linked successfully");
}
// We compare the locations we think have been assigned to the vertex attributes
// to the one that are actually stored in OpenGL
foreach (var attribute in _attributeLocation) {
DebugUtil.Info($"[Program:{_handle}] According to OpenGL, {attribute.Key} is located in {GL.GetAttribLocation(_handle, attribute.Key)} when it is supposed to be in {attribute.Value}");
}
// We clean up :)
foreach (var shader in _shaders) {
GL.DetachShader(_handle, shader.Handle);
GL.DeleteShader(shader.Handle);
}
// No need for the shaders anymore
_shaders.Clear();
这是控制台输出:
让我们说position
的默认位置是0
,这只是巧合。我们将location
起始索引设置为5
。
如您所见,我的代码适用于position
但不适用于normal
...
答案 0 :(得分:0)
看来,因为normal
顶点属性导致后续阶段(=片段着色器)没有用,所以OpenGL通过去除未使用的变量来优化着色器程序。
感谢@ Ripi2指出这一点。