glm::rotate 导致纹理凸起
glm::rotate leads to bulging of texture
我正在实现一个能够旋转和缩放图像的小型图像查看器 in/out。我通过使用 OpenGL 和 GLM 进行自学来故意这样做。到目前为止一切正常,唯一出现的问题是当我旋转图像时图像严重倾斜。当图像的宽度和高度差异很大时,尤其会发生这种情况。旋转 90 度后,纹理似乎会倾斜直到适合,这会导致图像失真。我对这里的轮换方式理解完全错误吗?据我了解,它只是多边形坐标与旋转矩阵的乘法。但是后来我不明白为什么会导致这种纹理凸起。
我试着玩弄透视,甚至用 glm::lookAt()
设置了一个虚构的相机,但到目前为止没有成功。
顶点着色器的实现:
const GLchar* vertexSource = R"glsl(
#version 150 core
in vec2 position;
in vec3 color;
in vec2 texcoord;
out vec3 Color;
out vec2 Texcoord;
uniform mat4 model;
void main()
{
Color = color;
Texcoord = texcoord;
gl_Position = model * vec4(position, 0.0, 1.0);
}
)glsl";
实施轮换:
//...
model = glm::mat4(1.0f);
//Get the transformation into the shader
uniTrans = glGetUniformLocation(shaderProgram, "model");
//...
else if(windowEvent.key.code == sf::Keyboard::Left){
degree = 5;
model = glm::rotate(model, glm::radians(degree), glm::vec3(0.0f, 0.0f, 1.0f));
glUniformMatrix4fv(uniTrans, 1, GL_FALSE, glm::value_ptr(model));
}
else if(windowEvent.key.code == sf::Keyboard::Right){
degree = -5;
model = glm::rotate(model, glm::radians(degree), glm::vec3(0.0f, 0.0f, 1.0f));
glUniformMatrix4fv(uniTrans, 1, GL_FALSE, glm::value_ptr(model));
}
//...
顶点数组的实现(这些因素使纹理不会填满整个window。它们的生成方式是边界始终为 200 像素):
//...
GLfloat vertices[] = {
//Position //Color //Texcoords
facX*(-1.0f), facY*( 1.0f), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, //top-left
facX*( 1.0f), facY*( 1.0f), 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, //top-right
facX*( 1.0f), facY*(-1.0f), 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, //bottom-right
facX*(-1.0f), facY*(-1.0f), 1.0f, 1.0f, 1.0f, 0.0f, 1.0f //bottom-left
};
//...
设置纹理:
GLuint tex;
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.getX(), image.getY(), 0, GL_BGRA, GL_UNSIGNED_BYTE, (const GLvoid*)data);
//Defining how to proceed if the texture is smaller than the space
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
//Specify Border Color
float color[] = {1.0f, 0.0f, 0.0f, 1.0f};
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, color);
//Set up filter for up and downscaling of the texture (linear smooth, nearest would give pixelised result)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
为了更直观地描述出现的问题,当我将宽度 != 高度的图像旋转 90 度时,"new" 高度将是旧宽度。但是,正在发生的事情是高度保持不变,这当然会导致图像凸出。
有人知道我做错了什么吗?
This occurs especially when the width and height of the image are strongly different
您必须使用正交投影矩阵,它考虑了视口的纵横比。
投影矩阵将所有顶点数据从视图坐标转换为剪辑坐标。剪辑坐标转换为标准化设备坐标 (NDC) (Perspective divide)。
归一化的设备坐标在 (-1, -1, -1)
到 (1, 1, 1)
范围内,形成一个完美的立方体体积。
使用正交投影,眼睛 space 坐标线性映射到 NDC。
如果视口是矩形的,则必须通过映射坐标来考虑这一点。
向顶点着色器添加投影矩阵:
const GLchar* vertexSource = R"glsl(
#version 150 core
in vec2 position;
in vec3 color;
in vec2 texcoord;
out vec3 Color;
out vec2 Texcoord;
uniform mat4 projection;
uniform mat4 model;
void main()
{
Color = color;
Texcoord = texcoord;
gl_Position = projection * model * vec4(position, 0.0, 1.0);
}
通过ortho()
设置一个正交投影矩阵,"scales"根据纵横比设置的几何体,并将矩阵设置为uniform:
uniProjection = glGetUniformLocation(shaderProgram, "projection");
int widht = ...; // width of the viewport (window)
int height = ...; // height of the viewport (window)
float aspect = (float)width / height;
glm::mat4 project = glm::ortho(-aspect, aspect, -1.0f, 1.0f, -1.0f, 1.0f);
glUniformMatrix4fv(uniProjection, 1, GL_FALSE, glm::value_ptr(project ));
注意,如果你想画一个矩形,那么你必须通过顶点坐标来形成这个矩形。
正交投影矩阵的目的是保证一个正方形投影到视口上时也是正方形。
我正在实现一个能够旋转和缩放图像的小型图像查看器 in/out。我通过使用 OpenGL 和 GLM 进行自学来故意这样做。到目前为止一切正常,唯一出现的问题是当我旋转图像时图像严重倾斜。当图像的宽度和高度差异很大时,尤其会发生这种情况。旋转 90 度后,纹理似乎会倾斜直到适合,这会导致图像失真。我对这里的轮换方式理解完全错误吗?据我了解,它只是多边形坐标与旋转矩阵的乘法。但是后来我不明白为什么会导致这种纹理凸起。
我试着玩弄透视,甚至用 glm::lookAt()
设置了一个虚构的相机,但到目前为止没有成功。
顶点着色器的实现:
const GLchar* vertexSource = R"glsl(
#version 150 core
in vec2 position;
in vec3 color;
in vec2 texcoord;
out vec3 Color;
out vec2 Texcoord;
uniform mat4 model;
void main()
{
Color = color;
Texcoord = texcoord;
gl_Position = model * vec4(position, 0.0, 1.0);
}
)glsl";
实施轮换:
//...
model = glm::mat4(1.0f);
//Get the transformation into the shader
uniTrans = glGetUniformLocation(shaderProgram, "model");
//...
else if(windowEvent.key.code == sf::Keyboard::Left){
degree = 5;
model = glm::rotate(model, glm::radians(degree), glm::vec3(0.0f, 0.0f, 1.0f));
glUniformMatrix4fv(uniTrans, 1, GL_FALSE, glm::value_ptr(model));
}
else if(windowEvent.key.code == sf::Keyboard::Right){
degree = -5;
model = glm::rotate(model, glm::radians(degree), glm::vec3(0.0f, 0.0f, 1.0f));
glUniformMatrix4fv(uniTrans, 1, GL_FALSE, glm::value_ptr(model));
}
//...
顶点数组的实现(这些因素使纹理不会填满整个window。它们的生成方式是边界始终为 200 像素):
//...
GLfloat vertices[] = {
//Position //Color //Texcoords
facX*(-1.0f), facY*( 1.0f), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, //top-left
facX*( 1.0f), facY*( 1.0f), 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, //top-right
facX*( 1.0f), facY*(-1.0f), 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, //bottom-right
facX*(-1.0f), facY*(-1.0f), 1.0f, 1.0f, 1.0f, 0.0f, 1.0f //bottom-left
};
//...
设置纹理:
GLuint tex;
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.getX(), image.getY(), 0, GL_BGRA, GL_UNSIGNED_BYTE, (const GLvoid*)data);
//Defining how to proceed if the texture is smaller than the space
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
//Specify Border Color
float color[] = {1.0f, 0.0f, 0.0f, 1.0f};
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, color);
//Set up filter for up and downscaling of the texture (linear smooth, nearest would give pixelised result)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
为了更直观地描述出现的问题,当我将宽度 != 高度的图像旋转 90 度时,"new" 高度将是旧宽度。但是,正在发生的事情是高度保持不变,这当然会导致图像凸出。 有人知道我做错了什么吗?
This occurs especially when the width and height of the image are strongly different
您必须使用正交投影矩阵,它考虑了视口的纵横比。
投影矩阵将所有顶点数据从视图坐标转换为剪辑坐标。剪辑坐标转换为标准化设备坐标 (NDC) (Perspective divide)。
归一化的设备坐标在 (-1, -1, -1)
到 (1, 1, 1)
范围内,形成一个完美的立方体体积。
使用正交投影,眼睛 space 坐标线性映射到 NDC。
如果视口是矩形的,则必须通过映射坐标来考虑这一点。
向顶点着色器添加投影矩阵:
const GLchar* vertexSource = R"glsl(
#version 150 core
in vec2 position;
in vec3 color;
in vec2 texcoord;
out vec3 Color;
out vec2 Texcoord;
uniform mat4 projection;
uniform mat4 model;
void main()
{
Color = color;
Texcoord = texcoord;
gl_Position = projection * model * vec4(position, 0.0, 1.0);
}
通过ortho()
设置一个正交投影矩阵,"scales"根据纵横比设置的几何体,并将矩阵设置为uniform:
uniProjection = glGetUniformLocation(shaderProgram, "projection");
int widht = ...; // width of the viewport (window)
int height = ...; // height of the viewport (window)
float aspect = (float)width / height;
glm::mat4 project = glm::ortho(-aspect, aspect, -1.0f, 1.0f, -1.0f, 1.0f);
glUniformMatrix4fv(uniProjection, 1, GL_FALSE, glm::value_ptr(project ));
注意,如果你想画一个矩形,那么你必须通过顶点坐标来形成这个矩形。
正交投影矩阵的目的是保证一个正方形投影到视口上时也是正方形。