我正在尝试在我的对象(这是一个3D立方体)上放置纹理,但是由于无法获得正确的结果,我不确定该怎么做。另外,我正在为此使用SDL。
这是我初始化所有内容的地方
void OpenGLWindow::initGL()
{
.
.
.
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
shader = loadShaderProgram("simple.vert", "simple.frag");
glUseProgram(shader);
// ambient
glUniform3f(glGetUniformLocation(shader, "objectColor"), 1.0f, 0.5f, 0.31f);
glUniform3f(glGetUniformLocation(shader, "lightColor"), 1.0f, 1.0f, 1.0f);
glUniform3fv(glGetUniformLocation(shader, "lightPos"), 1, &lightPos[0]);
glUniform3f(glGetUniformLocation(shader, "viewPos"), 0.0f, 0.0f, 3.0f);
int width, height, nrChannels;
unsigned char *data = stbi_load("container.png", &width, &height, &nrChannels, 0);
if (data) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
}
else {
std::cout << "Failed to load texture" << std::endl;
}
stbi_image_free(data);
// Set our viewing and projection matrices, since these do not change over time
glm::mat4 projectionMat = glm::perspective(glm::radians(90.0f), 4.0f/3.0f, 0.1f, 10.0f);
int projectionMatrixLoc = glGetUniformLocation(shader, "projectionMatrix");
glUniformMatrix4fv(projectionMatrixLoc, 1, false, &projectionMat[0][0]);
glm::vec3 eyeLoc(0.0f, 0.0f, 2.0f);
glm::vec3 targetLoc(0.0f, 0.0f, 0.0f);
glm::vec3 upDir(0.0f, 1.0f, 0.0f);
glm::mat4 viewingMat = glm::lookAt(eyeLoc, targetLoc, upDir);
int viewingMatrixLoc = glGetUniformLocation(shader, "viewingMatrix");
glUniformMatrix4fv(viewingMatrixLoc, 1, false, &viewingMat[0][0]);
// Load the model that we want to use and buffer the vertex attributes
//geometry.loadFromOBJFile("sphere.obj");
geometry.loadFromOBJFile("cube.obj");
GLuint vertexbuffer;
glGenBuffers(1, &vertexbuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glBufferData(GL_ARRAY_BUFFER, 3*geometry.vertexCount()*sizeof(float), geometry.vertexData(), GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
GLuint texturebuffer;
glGenBuffers(1, &texturebuffer);
glBindBuffer(GL_ARRAY_BUFFER, texturebuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(geometry.textureCoordData()) * sizeof(glm::vec3), geometry.textureCoordData(), GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, texturebuffer);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);
glPrintError("Setup complete", true);
}
我正在读取一个.obj文件,该文件具有顶点,法线和纹理的坐标,而该文件已经使用了将每个坐标存储在适当矢量中的类。
例如std :: vector顶点; std :: vector textureCoords; std :: vector法线;
如何将纹理矢量中的值发送到着色器?
这是我的顶点着色器:
in vec3 position;
out vec3 FragPos;
out vec3 Normal;
out vec2 TexCoord;
uniform mat4 projectionMatrix;
uniform mat4 viewingMatrix;
uniform mat4 modelMatrix;
void main()
{
vec4 transformedPosition = projectionMatrix * viewingMatrix * modelMatrix * vec4(position, 1.0f);
gl_Position = transformedPosition;
FragPos = vec3(modelMatrix * vec4(position, 1.0));
Normal = mat3(transpose(inverse(modelMatrix))) * position;
}
片段着色器:
out vec4 outColor;
in vec3 Normal;
in vec3 FragPos;
uniform vec3 lightPos;
uniform vec3 objectColor;
uniform vec3 lightColor;
uniform vec3 viewPos;
void main()
{
float ambientStrength = 0.06;
vec3 ambient = ambientStrength * lightColor;
vec3 norm = normalize(Normal);
vec3 lightDir = normalize(lightPos - FragPos);
float diff = max(dot(norm, lightDir), 0.0);
vec3 diffuse = diff * lightColor;
float specularStrength = 0.1;
vec3 viewDir = normalize(viewPos - FragPos);
vec3 reflectDir = reflect(-lightDir, norm);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32);
vec3 specular = specularStrength * spec * lightColor;
vec3 result = (ambient + diffuse + specular) * objectColor;
outColor = vec4(result, 1.0);
}
我应该怎么做才能将纹理放在对象(3D立方体)上?
这是我到目前为止所要了解的:
纹理并非在所有面上都出现,并且在放大或缩小时,表面上会出现一些红色,绿色或蓝色的线条。
答案 0 :(得分:1)
由于您有3种类型的顶点坐标,因此需要3个Vertex Shader inputs:
in vec3 a_position;
in vec2 a_uv;
in vec3 a_normal;
对于每个属性,您分别通过glVertexAttribPointer
和glEnableVertexAttribArray
定义并启用了通用顶点属性数据数组。顶点属性的索引(这是glEnableVertexAttribArray
和glVertexAttribPointer
的第一个参数),可以通过glGetAttribLocation
获得。
例如
GLint uv_inx = glGetAttribLocation(shader, "a_uv");
glEnableVertexAttribArray(uv_inx);
glBindBuffer(GL_ARRAY_BUFFER, texturebuffer);
glVertexAttribPointer(uv_inx, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);
但是现代的方法是使用Layout Qualifiers在着色器中定义顶点属性索引,这使glGetAttribLocation
调用变得多余:
layout (location = 0) in vec3 a_position;
layout (location = 1) in vec2 a_uv;
layout (location = 2) in vec3 a_normal;
您必须将属性从顶点着色器传递到片段着色器。最终的顶点着色器和片段着色器的输入可能如下所示:
顶点着色器:
#version 400
layout (location = 0) in vec3 a_position;
layout (location = 1) in vec2 a_uv;
layout (location = 2) in vec3 a_normal;
out vec3 FragPos;
out vec3 Normal;
out vec2 TexCoord;
uniform mat4 projectionMatrix;
uniform mat4 viewingMatrix;
uniform mat4 modelMatrix;
void main()
{
vec4 transformedPosition = projectionMatrix * viewingMatrix * modelMatrix * vec4(a_position, 1.0f);
gl_Position = transformedPosition;
FragPos = vec3(modelMatrix * vec4(a_position, 1.0));
Normal = mat3(transpose(inverse(modelMatrix))) * a_normal;
TexCoord = a_uv;
}
片段着色器:
in vec3 Normal;
in vec3 FragPos;
in vec2 TexCoord;
要在片段着色器中加载和查找纹理,您需要统一的纹理采样器。参见Sampler。
您必须为采样器制服指定纹理单位的索引-参见glActiveTexture
。
对于您来说,这是GL_TEXTURE0
的 0 (默认)。
片段采样器中的纹理采样器统一:
uniform sampler2D u_texture;
使用c ++代码将纹理单位0设置为纹理采样器统一:
GLint tex_loc = glGetUniformLocation(shader, "u_texture");
glUniform1i(tex_loc, 0); // 0 because of GL_TEXTURE0
从GLSL 4.2版开始,Binding point限定符可以在着色器代码中完成此操作:
layout (binding = 0) uniform sampler2D u_texture;
片段着色器可能看起来像这样:
#version 420
out vec4 outColor;
in vec3 Normal;
in vec3 FragPos;
in vec2 TexCoord;
.....
layout (binding = 0) uniform sampler2D u_texture;
void main()
{
vec4 textureColor = texture(u_texture, TexCoord);
....
vec3 result = (ambient + diffuse + specular) * textureColor.rgb;
outColor = vec4(result, 1.0);
}
当然,您可以通过将它们乘以“调制”对象颜色和纹理corot:
vec3 result = (ambient + diffuse + specular) * objectColor.rgb * textureColor.rgb;