OpenGL 纹理变形不正确
OpenGL texture warping is incorrect
我想让 OpenGL 程序可以呈现图像并扭曲呈现的图像。
虽然我使用 OpenGL 实现了图像渲染,但我不知道如何扭曲图像的 4 个顶点。
我想要的一个可变形的例子是 (Reference)
虽然我改变了位置值来扭曲图像,但结果是这样的。
不知道为什么会出现这种曲线效果。
这是我的源代码。请让我知道如何处理图像变形。
void imageRender(Shader initShader, Shader imgShader, char *path){
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
float positions = { 0.5f, 0.5f, 0.0f,
1.0f, -1.0f, 0.0f,
-1.0f, -1.0f, 0.0f,
-1.0f, 1.0f, 0.0f };
float vertices[] = {
// positions // colors // texture coords
position[0], position[1], position[2], 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // top right
position[3], position[4], position[5], 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // bottom right
position[6], position[7], position[8], 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom left
position[9], position[10],position[11], 1.0f, 1.0f, 0.0f, 0.0f, 1.0f // top left
};
unsigned int indices[] = {
0, 1, 3,
1, 2, 3
};
unsigned int VAO, VBO, EBO;
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
// position attribute
//glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
glEnableVertexAttribArray(1);
// color attribute
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(2);
//texture attribute
glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
glEnableVertexAttribArray(3);
FREE_IMAGE_FORMAT format = FreeImage_GetFileType(path, 0);
if (format == -1){
cerr << BOLDRED << "[ERROR] IMAGE_NOT_FOUND" << RESET << endl;
exit(1);
}
if (format == FIF_UNKNOWN){
cerr << BOLDRED << "[ERROR] UNKNOWN_IMAGE_FORMAT" << RESET << endl;
format = FreeImage_GetFIFFromFilename(path);
if (!FreeImage_FIFSupportsReading(format)){
cerr << BOLDRED << "[ERROR] IMAGE_FORMAT_NOT_READABLE" << RESET << endl;
exit(1);
}
}
FIBITMAP *bitmap = FreeImage_Load(format, path);
FIBITMAP *bitmap32;
int bitsPerPixel = FreeImage_GetBPP(bitmap);
bitmap32 = FreeImage_ConvertTo32Bits(bitmap);
int imageWidth = FreeImage_GetWidth(bitmap32);
int imageHeight = FreeImage_GetHeight(bitmap32);
GLubyte *textureData = FreeImage_GetBits(bitmap32);
GLuint texture1;
glGenTextures(1, &texture1);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture1);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, imageWidth, imageHeight, 0, GL_BGRA, GL_UNSIGNED_BYTE, textureData);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // set texture wrapping to GL_REPEAT (default wrapping method)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
initShader.use();
glBindVertexArray(VAO);
int initalTime = time(NULL);
while(1){
glBindVertexArray(VAO);
int timecal = time(NULL);
//glDrawElements(GL_TRIANGLE_STRIP, 6, GL_UNSIGNED_INT, 0);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glfwSwapBuffers(window);
glfwPollEvents();
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
if ((timecal - initalTime) > imageTime) // imageTime value is 10
break;
}
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glDeleteTextures(1, &texture1);// image
glDisable(GL_TEXTURE_2D);//image
FreeImage_Unload(bitmap32);
FreeImage_Unload(bitmap);
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glDeleteBuffers(1, &EBO);
}
}
着色器代码就是这样
//shader.vs
#version 330 core
layout(location = 1) in vec3 position;
layout(location = 2) in vec3 color;
layout(location = 3) in vec2 texcoord;
out vec3 Color;
out vec2 Texcoord;
void main()
{
gl_Position = vec4(position, 1.0);
Texcoord = texcoord;
}
//shader.fs
#version 330 core
in vec3 Color;
in vec2 Texcoord;
out vec4 outColor;
uniform sampler2D texture5;
void main()
{
outColor = texture2D(texture5, Texcoord);
}
纹理环绕没有错。您将纹理包裹到由点 (0.5, 1)、(1, -1)、(-1, 1) 和 (1, -1)、(-1, -1)、(-1, 1):
请注意,纹理分别包裹到每个三角形。如果要获得 3d 效果,则必须指定 3 维坐标,并且必须使用 Perspective projection。
我认为你需要一个投影变换。这是一个示例,其中的公式取自 this math.stackexchange question:
中已接受的答案
Matrix4x4 MatFromPoints(Vector2 BL, Vector2 BR, Vector2 TL, Vector2 TR)
{
Matrix4x4 m = new Matrix4x4(
new Vector4(BL.x, BL.y, 1, 0), //col 1
new Vector4(BR.x, BR.y, 1, 0), //col 2
new Vector4(TL.x, TL.y, 1, 0), //col 3
new Vector4(0, 0, 0, 1) //col 4
);
var mI = m.inverse;
var c = mI * new Vector4(TR.x, TR.y, 1, 0);
return new Matrix4x4(
new Vector4(BL.x * c.x, BL.y * c.x, c.x, 0),
new Vector4(BR.x * c.y, BR.y * c.y, c.y, 0),
new Vector4(TL.x * c.z, TL.y * c.z, c.z, 0),
new Vector4(0, 0, 0, 1)
);
}
并以此计算变换矩阵:
// (-1,-1) (1,-1) (-1,1) (.5,.5)
Matrix4x4 A = MatFromPoints(fromBL, fromBR, fromTL, fromTR);
// (0,0) (1,0) (0,1) (1,1)
Matrix4x4 B = MatFromPoints(toBL, toBR, toTL, toTR);
Matrix4x4 UvTransform = B * A.inverse;
设置UvTransform
为制服。在片段着色器中:
// pos is local vertex position
float4 uv = float4(pos.xy, 1, 0);
uv = mul(UvTransform, uv);
uv.xy = uv.xy / uv.z;
fixed4 outColor = tex2D(Texture, uv.xy);
你得到:
我想让 OpenGL 程序可以呈现图像并扭曲呈现的图像。
虽然我使用 OpenGL 实现了图像渲染,但我不知道如何扭曲图像的 4 个顶点。
我想要的一个可变形的例子是 (Reference)
虽然我改变了位置值来扭曲图像,但结果是这样的。
不知道为什么会出现这种曲线效果。
这是我的源代码。请让我知道如何处理图像变形。
void imageRender(Shader initShader, Shader imgShader, char *path){
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
float positions = { 0.5f, 0.5f, 0.0f,
1.0f, -1.0f, 0.0f,
-1.0f, -1.0f, 0.0f,
-1.0f, 1.0f, 0.0f };
float vertices[] = {
// positions // colors // texture coords
position[0], position[1], position[2], 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // top right
position[3], position[4], position[5], 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // bottom right
position[6], position[7], position[8], 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom left
position[9], position[10],position[11], 1.0f, 1.0f, 0.0f, 0.0f, 1.0f // top left
};
unsigned int indices[] = {
0, 1, 3,
1, 2, 3
};
unsigned int VAO, VBO, EBO;
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
// position attribute
//glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
glEnableVertexAttribArray(1);
// color attribute
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(2);
//texture attribute
glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
glEnableVertexAttribArray(3);
FREE_IMAGE_FORMAT format = FreeImage_GetFileType(path, 0);
if (format == -1){
cerr << BOLDRED << "[ERROR] IMAGE_NOT_FOUND" << RESET << endl;
exit(1);
}
if (format == FIF_UNKNOWN){
cerr << BOLDRED << "[ERROR] UNKNOWN_IMAGE_FORMAT" << RESET << endl;
format = FreeImage_GetFIFFromFilename(path);
if (!FreeImage_FIFSupportsReading(format)){
cerr << BOLDRED << "[ERROR] IMAGE_FORMAT_NOT_READABLE" << RESET << endl;
exit(1);
}
}
FIBITMAP *bitmap = FreeImage_Load(format, path);
FIBITMAP *bitmap32;
int bitsPerPixel = FreeImage_GetBPP(bitmap);
bitmap32 = FreeImage_ConvertTo32Bits(bitmap);
int imageWidth = FreeImage_GetWidth(bitmap32);
int imageHeight = FreeImage_GetHeight(bitmap32);
GLubyte *textureData = FreeImage_GetBits(bitmap32);
GLuint texture1;
glGenTextures(1, &texture1);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture1);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, imageWidth, imageHeight, 0, GL_BGRA, GL_UNSIGNED_BYTE, textureData);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // set texture wrapping to GL_REPEAT (default wrapping method)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
initShader.use();
glBindVertexArray(VAO);
int initalTime = time(NULL);
while(1){
glBindVertexArray(VAO);
int timecal = time(NULL);
//glDrawElements(GL_TRIANGLE_STRIP, 6, GL_UNSIGNED_INT, 0);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glfwSwapBuffers(window);
glfwPollEvents();
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
if ((timecal - initalTime) > imageTime) // imageTime value is 10
break;
}
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glDeleteTextures(1, &texture1);// image
glDisable(GL_TEXTURE_2D);//image
FreeImage_Unload(bitmap32);
FreeImage_Unload(bitmap);
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glDeleteBuffers(1, &EBO);
}
}
着色器代码就是这样
//shader.vs
#version 330 core
layout(location = 1) in vec3 position;
layout(location = 2) in vec3 color;
layout(location = 3) in vec2 texcoord;
out vec3 Color;
out vec2 Texcoord;
void main()
{
gl_Position = vec4(position, 1.0);
Texcoord = texcoord;
}
//shader.fs
#version 330 core
in vec3 Color;
in vec2 Texcoord;
out vec4 outColor;
uniform sampler2D texture5;
void main()
{
outColor = texture2D(texture5, Texcoord);
}
纹理环绕没有错。您将纹理包裹到由点 (0.5, 1)、(1, -1)、(-1, 1) 和 (1, -1)、(-1, -1)、(-1, 1):
请注意,纹理分别包裹到每个三角形。如果要获得 3d 效果,则必须指定 3 维坐标,并且必须使用 Perspective projection。
我认为你需要一个投影变换。这是一个示例,其中的公式取自 this math.stackexchange question:
中已接受的答案Matrix4x4 MatFromPoints(Vector2 BL, Vector2 BR, Vector2 TL, Vector2 TR)
{
Matrix4x4 m = new Matrix4x4(
new Vector4(BL.x, BL.y, 1, 0), //col 1
new Vector4(BR.x, BR.y, 1, 0), //col 2
new Vector4(TL.x, TL.y, 1, 0), //col 3
new Vector4(0, 0, 0, 1) //col 4
);
var mI = m.inverse;
var c = mI * new Vector4(TR.x, TR.y, 1, 0);
return new Matrix4x4(
new Vector4(BL.x * c.x, BL.y * c.x, c.x, 0),
new Vector4(BR.x * c.y, BR.y * c.y, c.y, 0),
new Vector4(TL.x * c.z, TL.y * c.z, c.z, 0),
new Vector4(0, 0, 0, 1)
);
}
并以此计算变换矩阵:
// (-1,-1) (1,-1) (-1,1) (.5,.5)
Matrix4x4 A = MatFromPoints(fromBL, fromBR, fromTL, fromTR);
// (0,0) (1,0) (0,1) (1,1)
Matrix4x4 B = MatFromPoints(toBL, toBR, toTL, toTR);
Matrix4x4 UvTransform = B * A.inverse;
设置UvTransform
为制服。在片段着色器中:
// pos is local vertex position
float4 uv = float4(pos.xy, 1, 0);
uv = mul(UvTransform, uv);
uv.xy = uv.xy / uv.z;
fixed4 outColor = tex2D(Texture, uv.xy);
你得到: