OpenGL 纹理映射不起作用
OpenGL Texture Mapping doesn't work
我必须使用 OpenGL API 和着色器对网格进行纹理化。
为此,我执行了以下步骤:
加载图片并创建纹理
img::ImageLoader imgLoader;
unsigned char* data = imgLoader.LoadTextureFromFile("../Texturen/brickwork.jpg", &width, &height, true);
glGenTextures(1, &texId);
glBindTexture(GL_TEXTURE_2D, texId);{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_BGR, GL_UNSIGNED_BYTE, data);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
创建顶点、法线和纹理坐标
std::vector<float> v, n, t;
// actual calculation is left out to make it more readable
obj = new GLBatch;
obj->Begin(GL_TRIANGLES, v.size()/3, t.size()/2);{
obj->CopyVertexData3f(v.data());
obj->CopyNormalDataf(n.data());
obj->CopyTexCoordData2f(t.data(), 0);
}obj->End();
加载着色器
shaders = gltLoadShaderPairWithAttributes("VertexShader.glsl", "FragmentShader.glsl", 2,
GLT_ATTRIBUTE_VERTEX, "vVertex",
GLT_ATTRIBUTE_NORMAL, "vNormal",
GLT_ATTRIBUTE_TEXTURE0, "vTexCoord");
gltCheckErrors(shaders);
(VertexShader.glsl)
#version 130
in vec4 vVertex;
in vec4 vNormal;
in vec2 vTexCoord;
uniform mat4 mvpMatrix;
uniform mat4 mvMatrix;
uniform mat3 normalMatrix;
/// Light position in Eye-Space
uniform vec4 light_pos_vs ;
/// Light diffuse color
uniform vec4 light_diffuse ;
uniform vec4 light_ambient ;
/// Light specular color
uniform vec4 light_specular ;
/// Specular power (shininess)
uniform float spec_power;
/// Material parameters
uniform vec4 mat_emissive;
uniform vec4 mat_ambient;
uniform vec4 mat_diffuse;
uniform vec4 mat_specular;
/// output
out vec4 color;
out vec2 texCoords;
void main()
{
texCoords = vTexCoord;
// Transform vertex from objekt to clip-space
gl_Position = mvpMatrix * vVertex ;
// Transform vertex from object to eye-space
vec4 vertex_vs = mvMatrix * vVertex;
vec3 ecPos = vertex_vs.xyz / vertex_vs.w;
// Calculate light direction
vec3 light_dir_vs = normalize(vec3(light_pos_vs.xyz));
// Transform normals from object into eye-space
vec3 normal_vs = normalize(normalMatrix * (vNormal).xyz) ;
// Viewing vector in eye-space
vec3 view_dir_vs = normalize(-ecPos );
// Halfway vektor for Phong-Blinn light modell
vec3 halfway_vs = normalize(view_dir_vs + light_dir_vs ) ;
// Diffuse
float NdotL = max(dot(normal_vs, light_dir_vs),0.0) ;
vec4 diffuse_color = NdotL * mat_diffuse * light_diffuse ;
// Specular
float NdotH = max(dot(normal_vs, halfway_vs),0.0) ;
vec4 specular_color = pow(NdotH ,spec_power) * mat_specular * light_specular ;
// Color output
color = mat_emissive + light_ambient*mat_ambient + diffuse_color + specular_color;
}
(FragmentShader.glsl)
#version 130
in vec2 texCoords;
in vec4 color;
uniform sampler2D textureMap;
out vec4 fragColor;
void main()
{
fragColor = texture(textureMap, texCoords);
fragColor *= color;
}
在显示函数中绘制所有内容
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glLineWidth(INDICATOR_WIDTH);
glBindTexture(GL_TEXTURE_2D, texId);
modelViewMatrix.LoadIdentity();
modelViewMatrix.Translate(0,0,-5);
modelViewMatrix.PushMatrix();{
M3DMatrix44f rot;
m3dQuatToRotationMatrix(rot,rotation);
modelViewMatrix.MultMatrix(rot);
// set shader
glUseProgram(shaders);
// pass matrices
glUniformMatrix4fv(glGetUniformLocation(shaders, "mvpMatrix"), 1, GL_FALSE, transformPipeline.GetModelViewProjectionMatrix());
glUniformMatrix4fv(glGetUniformLocation(shaders, "mvMatrix"), 1, GL_FALSE, transformPipeline.GetModelViewMatrix());
glUniformMatrix3fv(glGetUniformLocation(shaders, "normalMatrix"), 1, GL_FALSE, transformPipeline.GetNormalMatrix(true));
// pass light properties
glUniform4fv(glGetUniformLocation(shaders, "light_pos_vs"),1,light_pos);
glUniform4fv(glGetUniformLocation(shaders, "light_ambient"),1,light_ambient);
glUniform4fv(glGetUniformLocation(shaders, "light_diffuse"),1,light_diffuse);
glUniform4fv(glGetUniformLocation(shaders, "light_specular"),1,light_specular);
glUniform1f(glGetUniformLocation(shaders, "spec_power"),specular_power);
// pass material properties
glUniform4fv(glGetUniformLocation(shaders, "mat_emissive"),1,mat_emissive);
glUniform4fv(glGetUniformLocation(shaders, "mat_ambient"),1,mat_ambient);
glUniform4fv(glGetUniformLocation(shaders, "mat_diffuse"),1,mat_diffuse);
glUniform4fv(glGetUniformLocation(shaders, "mat_specular"),1,mat_specular);
drawObject();
}modelViewMatrix.PopMatrix();
gltCheckErrors(shaders);
glutSwapBuffers();
glutPostRedisplay();
完成所有这些步骤后,结果看起来不错,但没有纹理:(
这里实际发生的是,每个顶点都映射到我的纹理的同一个像素,这显然是灰色的。
我尝试了从 (0,0) 到 (1,1) 和 (0,0) 到 (width,height)
但什么都没有改变。
首先,绑定纹理时,您应该指定用于该纹理的纹理单元。
这可以通过 glActiveTexture
int textureUnit = 0; // <- put the number of the txture unit in here
glActiveTexture( GL_TEXTURE0 + textureUnit );
glGenTextures( 1, &texId );
glBindTexture( GL_TEXTURE_2D, texId );
纹理单元的最大数量可以通过glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS,...)
询问。
纹理单元的数量取决于实现,但必须至少为 80。
因为你只需要一个 0
就可以了。
纹理单元 0
是默认的,所以如果你从未改变它,你可以跳过这个。
接下来确保您使用了 glTexImage2D
以正确的方式,特别是检查格式是否适合您的数据。使用glGetError检查指定目标纹理是否成功。
当您使用着色器程序时,您必须 link 将纹理单元设置为统一纹理采样器。
int texMapLocation = glGetUniformLocation( shaders, "textureMap" );
...
glUseProgram( shaders );
...
glUniform1i( texMapLocation, textureUnit ); // <- you are missing this
改变
shaders = gltLoadShaderPairWithAttributes(
"VertexShader.glsl",
"FragmentShader.glsl",
2,
GLT_ATTRIBUTE_VERTEX, "vVertex",
GLT_ATTRIBUTE_NORMAL, "vNormal",
GLT_ATTRIBUTE_TEXTURE0, "vTexCoord");
到
shaders = gltLoadShaderPairWithAttributes(
"VertexShader.glsl",
"FragmentShader.glsl",
3, // < --------------------
GLT_ATTRIBUTE_VERTEX, "vVertex",
GLT_ATTRIBUTE_NORMAL, "vNormal",
GLT_ATTRIBUTE_TEXTURE0, "vTexCoord");
因为函数签名中的第三个参数是紧随其后且应链接到着色器的属性数。在这种情况下,有 3 个属性:GLT_ATTRIBUTE_VERTEX
、GLT_ATTRIBUTE_NORMAL
和 GLT_ATTRIBUTE_TEXTURE0
。
在原始代码中,只有 GLT_ATTRIBUTE_VERTEX
、GLT_ATTRIBUTE_NORMAL
链接在一起,因此没有纹理坐标被传递给着色器。
我必须使用 OpenGL API 和着色器对网格进行纹理化。
为此,我执行了以下步骤:
加载图片并创建纹理
img::ImageLoader imgLoader; unsigned char* data = imgLoader.LoadTextureFromFile("../Texturen/brickwork.jpg", &width, &height, true); glGenTextures(1, &texId); glBindTexture(GL_TEXTURE_2D, texId);{ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_BGR, GL_UNSIGNED_BYTE, data); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); }
创建顶点、法线和纹理坐标
std::vector<float> v, n, t; // actual calculation is left out to make it more readable obj = new GLBatch; obj->Begin(GL_TRIANGLES, v.size()/3, t.size()/2);{ obj->CopyVertexData3f(v.data()); obj->CopyNormalDataf(n.data()); obj->CopyTexCoordData2f(t.data(), 0); }obj->End();
加载着色器
shaders = gltLoadShaderPairWithAttributes("VertexShader.glsl", "FragmentShader.glsl", 2, GLT_ATTRIBUTE_VERTEX, "vVertex", GLT_ATTRIBUTE_NORMAL, "vNormal", GLT_ATTRIBUTE_TEXTURE0, "vTexCoord"); gltCheckErrors(shaders);
(VertexShader.glsl)
#version 130 in vec4 vVertex; in vec4 vNormal; in vec2 vTexCoord; uniform mat4 mvpMatrix; uniform mat4 mvMatrix; uniform mat3 normalMatrix; /// Light position in Eye-Space uniform vec4 light_pos_vs ; /// Light diffuse color uniform vec4 light_diffuse ; uniform vec4 light_ambient ; /// Light specular color uniform vec4 light_specular ; /// Specular power (shininess) uniform float spec_power; /// Material parameters uniform vec4 mat_emissive; uniform vec4 mat_ambient; uniform vec4 mat_diffuse; uniform vec4 mat_specular; /// output out vec4 color; out vec2 texCoords; void main() { texCoords = vTexCoord; // Transform vertex from objekt to clip-space gl_Position = mvpMatrix * vVertex ; // Transform vertex from object to eye-space vec4 vertex_vs = mvMatrix * vVertex; vec3 ecPos = vertex_vs.xyz / vertex_vs.w; // Calculate light direction vec3 light_dir_vs = normalize(vec3(light_pos_vs.xyz)); // Transform normals from object into eye-space vec3 normal_vs = normalize(normalMatrix * (vNormal).xyz) ; // Viewing vector in eye-space vec3 view_dir_vs = normalize(-ecPos ); // Halfway vektor for Phong-Blinn light modell vec3 halfway_vs = normalize(view_dir_vs + light_dir_vs ) ; // Diffuse float NdotL = max(dot(normal_vs, light_dir_vs),0.0) ; vec4 diffuse_color = NdotL * mat_diffuse * light_diffuse ; // Specular float NdotH = max(dot(normal_vs, halfway_vs),0.0) ; vec4 specular_color = pow(NdotH ,spec_power) * mat_specular * light_specular ; // Color output color = mat_emissive + light_ambient*mat_ambient + diffuse_color + specular_color; }
(FragmentShader.glsl)
#version 130 in vec2 texCoords; in vec4 color; uniform sampler2D textureMap; out vec4 fragColor; void main() { fragColor = texture(textureMap, texCoords); fragColor *= color; }
在显示函数中绘制所有内容
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glEnable(GL_DEPTH_TEST); glLineWidth(INDICATOR_WIDTH); glBindTexture(GL_TEXTURE_2D, texId); modelViewMatrix.LoadIdentity(); modelViewMatrix.Translate(0,0,-5); modelViewMatrix.PushMatrix();{ M3DMatrix44f rot; m3dQuatToRotationMatrix(rot,rotation); modelViewMatrix.MultMatrix(rot); // set shader glUseProgram(shaders); // pass matrices glUniformMatrix4fv(glGetUniformLocation(shaders, "mvpMatrix"), 1, GL_FALSE, transformPipeline.GetModelViewProjectionMatrix()); glUniformMatrix4fv(glGetUniformLocation(shaders, "mvMatrix"), 1, GL_FALSE, transformPipeline.GetModelViewMatrix()); glUniformMatrix3fv(glGetUniformLocation(shaders, "normalMatrix"), 1, GL_FALSE, transformPipeline.GetNormalMatrix(true)); // pass light properties glUniform4fv(glGetUniformLocation(shaders, "light_pos_vs"),1,light_pos); glUniform4fv(glGetUniformLocation(shaders, "light_ambient"),1,light_ambient); glUniform4fv(glGetUniformLocation(shaders, "light_diffuse"),1,light_diffuse); glUniform4fv(glGetUniformLocation(shaders, "light_specular"),1,light_specular); glUniform1f(glGetUniformLocation(shaders, "spec_power"),specular_power); // pass material properties glUniform4fv(glGetUniformLocation(shaders, "mat_emissive"),1,mat_emissive); glUniform4fv(glGetUniformLocation(shaders, "mat_ambient"),1,mat_ambient); glUniform4fv(glGetUniformLocation(shaders, "mat_diffuse"),1,mat_diffuse); glUniform4fv(glGetUniformLocation(shaders, "mat_specular"),1,mat_specular); drawObject(); }modelViewMatrix.PopMatrix(); gltCheckErrors(shaders); glutSwapBuffers(); glutPostRedisplay();
完成所有这些步骤后,结果看起来不错,但没有纹理:(
这里实际发生的是,每个顶点都映射到我的纹理的同一个像素,这显然是灰色的。
我尝试了从 (0,0) 到 (1,1) 和 (0,0) 到 (width,height) 但什么都没有改变。
首先,绑定纹理时,您应该指定用于该纹理的纹理单元。 这可以通过 glActiveTexture
int textureUnit = 0; // <- put the number of the txture unit in here
glActiveTexture( GL_TEXTURE0 + textureUnit );
glGenTextures( 1, &texId );
glBindTexture( GL_TEXTURE_2D, texId );
纹理单元的最大数量可以通过glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS,...)
询问。
纹理单元的数量取决于实现,但必须至少为 80。
因为你只需要一个 0
就可以了。
纹理单元 0
是默认的,所以如果你从未改变它,你可以跳过这个。
接下来确保您使用了 glTexImage2D 以正确的方式,特别是检查格式是否适合您的数据。使用glGetError检查指定目标纹理是否成功。
当您使用着色器程序时,您必须 link 将纹理单元设置为统一纹理采样器。
int texMapLocation = glGetUniformLocation( shaders, "textureMap" );
...
glUseProgram( shaders );
...
glUniform1i( texMapLocation, textureUnit ); // <- you are missing this
改变
shaders = gltLoadShaderPairWithAttributes(
"VertexShader.glsl",
"FragmentShader.glsl",
2,
GLT_ATTRIBUTE_VERTEX, "vVertex",
GLT_ATTRIBUTE_NORMAL, "vNormal",
GLT_ATTRIBUTE_TEXTURE0, "vTexCoord");
到
shaders = gltLoadShaderPairWithAttributes(
"VertexShader.glsl",
"FragmentShader.glsl",
3, // < --------------------
GLT_ATTRIBUTE_VERTEX, "vVertex",
GLT_ATTRIBUTE_NORMAL, "vNormal",
GLT_ATTRIBUTE_TEXTURE0, "vTexCoord");
因为函数签名中的第三个参数是紧随其后且应链接到着色器的属性数。在这种情况下,有 3 个属性:GLT_ATTRIBUTE_VERTEX
、GLT_ATTRIBUTE_NORMAL
和 GLT_ATTRIBUTE_TEXTURE0
。
在原始代码中,只有 GLT_ATTRIBUTE_VERTEX
、GLT_ATTRIBUTE_NORMAL
链接在一起,因此没有纹理坐标被传递给着色器。