一、目的
1、画一组镜像变换的正方体;
二、程序运行结果
三、镜像变换
镜像变换,就是反射成像的概念,它是缩放变换的一个特例,当缩放因子
k
<
0
k < 0
k<0时会导致镜像变换。执行镜像变换后的效果如程序运行结果图所示:
上面图中,第一象限为原图,第二象限为关于y轴的镜像,即点 (x,y,z)镜像后点(-x,y,z),因此所求矩阵为:
R
e
f
l
e
c
t
y
=
[
−
1
0
0
0
0
1
0
0
0
0
1
0
0
0
0
1
]
Reflect_{y}= \begin{bmatrix} -1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1\\ \end{bmatrix}
Reflecty=⎣⎢⎢⎡−1000010000100001⎦⎥⎥⎤
可以看出这个矩阵,就是上面的缩放矩阵,当缩放因子为(-1.0,1.0,1.0)时的矩阵。
上图中,第三象限为以xy轴同时反射形成,缩放因子为(-1.0,-1.0,1.0);第四象限为以x轴进行反射,缩放因子为(1.0, -1.0, 1.0)。
四、模型变换部分说明
模型变换部分涉及到了平移、缩放、旋转和镜像变换,在实际中多半是这些变换的组合,一般地执行变换顺序为缩放–>旋转—>平移。在实行模型变换时,要注意变换的顺序和代码中书写的顺序相反。同时对于缩放和旋转变换,要注意不动点不在原点时的处理方法。对于绕任意方向的旋转,需要推导一个新的旋转矩阵。
五、源代码
"""
程序名称:GL_Reflect01.py
编程: dalong10
功能: 镜像变换的实现
参考资料: https://blog.youkuaiyun.com/wangdingqiaoit/article/details/51531002
"""
import glfw
from OpenGL.GL import *
from OpenGL.GL.shaders import compileProgram, compileShader
import numpy as np
import pyrr
from PIL import Image
vertex_src = """
# version 330
layout(location = 0) in vec3 a_position;
layout(location = 1) in vec3 a_color;
layout(location = 2) in vec2 a_texture;
uniform mat4 rotation;
out vec3 v_color;
out vec2 v_texture;
void main()
{
gl_Position = rotation * vec4(a_position, 1.0);
v_color = a_color;
v_texture = a_texture;
//v_texture = 1 - a_texture; // Flips the texture vertically and horizontally
//v_texture = vec2(a_texture.s, 1 - a_texture.t); // Flips the texture vertically
}
"""
fragment_src = """
# version 330
in vec3 v_color;
in vec2 v_texture;
out vec4 out_color;
uniform sampler2D s_texture;
void main()
{
out_color = texture(s_texture, v_texture); // * vec4(v_color, 1.0f);
}
"""
# glfw callback functions
def window_resize(window, width, height):
glViewport(0, 0, width, height)
# initializing glfw library
if not glfw.init():
raise Exception("glfw can not be initialized!")
# creating the window
window = glfw.create_window(400, 400, "My OpenGL window", None, None)
# check if window was created
if not window:
glfw.terminate()
raise Exception("glfw window can not be created!")
# set window's position
glfw.set_window_pos(window, 100, 100)
# set the callback function for window resize
glfw.set_window_size_callback(window, window_resize)
# make the context current
glfw.make_context_current(window)
vertices = [-0.5, -0.5, 0.5, 1.0, 0.0, 0.0, 0.0, 0.0,
0.5, -0.5, 0.5, 0.0, 1.0, 0.0, 1.0, 0.0,
0.5, 0.5, 0.5, 0.0, 0.0, 1.0, 1.0, 1.0,
-0.5, 0.5, 0.5, 1.0, 1.0, 1.0, 0.0, 1.0,
-0.5, -0.5, -0.5, 1.0, 0.0, 0.0, 0.0, 0.0,
0.5, -0.5, -0.5, 0.0, 1.0, 0.0, 1.0, 0.0,
0.5, 0.5, -0.5, 0.0, 0.0, 1.0, 1.0, 1.0,
-0.5, 0.5, -0.5, 1.0, 1.0, 1.0, 0.0, 1.0,
0.5, -0.5, -0.5, 1.0, 0.0, 0.0, 0.0, 0.0,
0.5, 0.5, -0.5, 0.0, 1.0, 0.0, 1.0, 0.0,
0.5, 0.5, 0.5, 0.0, 0.0, 1.0, 1.0, 1.0,
0.5, -0.5, 0.5, 1.0, 1.0, 1.0, 0.0, 1.0,
-0.5, 0.5, -0.5, 1.0, 0.0, 0.0, 0.0, 0.0,
-0.5, -0.5, -0.5, 0.0, 1.0, 0.0, 1.0, 0.0,
-0.5, -0.5, 0.5, 0.0, 0.0, 1.0, 1.0, 1.0,
-0.5, 0.5, 0.5, 1.0, 1.0, 1.0, 0.0, 1.0,
-0.5, -0.5, -0.5, 1.0, 0.0, 0.0, 0.0, 0.0,
0.5, -0.5, -0.5, 0.0, 1.0, 0.0, 1.0, 0.0,
0.5, -0.5, 0.5, 0.0, 0.0, 1.0, 1.0, 1.0,
-0.5, -0.5, 0.5, 1.0, 1.0, 1.0, 0.0, 1.0,
0.5, 0.5, -0.5, 1.0, 0.0, 0.0, 0.0, 0.0,
-0.5, 0.5, -0.5, 0.0, 1.0, 0.0, 1.0, 0.0,
-0.5, 0.5, 0.5, 0.0, 0.0, 1.0, 1.0, 1.0,
0.5, 0.5, 0.5, 1.0, 1.0, 1.0, 0.0, 1.0]
indices = [0, 1, 2, 2, 3, 0,
4, 5, 6, 6, 7, 4,
8, 9, 10, 10, 11, 8,
12, 13, 14, 14, 15, 12,
16, 17, 18, 18, 19, 16,
20, 21, 22, 22, 23, 20]
vertices = np.array(vertices, dtype=np.float32)
indices = np.array(indices, dtype=np.uint32)
shader = compileProgram(compileShader(vertex_src, GL_VERTEX_SHADER), compileShader(fragment_src, GL_FRAGMENT_SHADER))
# Step2: 创建并绑定VBO 对象 传送数据
VBO = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, VBO)
glBufferData(GL_ARRAY_BUFFER, vertices.nbytes, vertices, GL_STATIC_DRAW)
# Step3: 创建并绑定EBO 对象 传送数据
EBO = glGenBuffers(1)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO)
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.nbytes, indices, GL_STATIC_DRAW)
# Step4: 指定解析方式 并启用顶点属性
# 顶点位置属性
glEnableVertexAttribArray(0)
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, vertices.itemsize * 8, ctypes.c_void_p(0))
# 顶点颜色属性
glEnableVertexAttribArray(1)
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, vertices.itemsize * 8, ctypes.c_void_p(12))
# 顶点纹理属性
glEnableVertexAttribArray(2)
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, vertices.itemsize * 8, ctypes.c_void_p(24))
texture = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, texture)
# Set the texture wrapping parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)
# Set texture filtering parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
# load image
image = Image.open("wall.png")
image = image.transpose(Image.FLIP_TOP_BOTTOM)
img_data = image.convert("RGBA").tobytes()
# img_data = np.array(image.getdata(), np.uint8) # second way of getting the raw image data
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width, image.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, img_data)
glUseProgram(shader)
glClearColor(0, 0.1, 0.1, 1)
glEnable(GL_DEPTH_TEST)
glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
scale1 = pyrr.matrix44.create_from_scale(pyrr.Vector3([0.5, 0.5, 0.5]))
cube1 = pyrr.matrix44.create_from_translation(pyrr.Vector3([0.25, 0.25, 0]))
cube2 = pyrr.matrix44.create_from_translation(pyrr.Vector3([-0.25, 0.25, 0]))
cube3 = pyrr.matrix44.create_from_translation(pyrr.Vector3([-0.25, -0.25, 0]))
cube4 = pyrr.matrix44.create_from_translation(pyrr.Vector3([0.25, -0.25, 0]))
rotation_loc = glGetUniformLocation(shader, "rotation")
# the main application loop
while not glfw.window_should_close(window):
glfw.poll_events()
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
# 绘制第一个矩形
model = pyrr.matrix44.multiply(scale1, cube1)
glUniformMatrix4fv(rotation_loc, 1, GL_FALSE, model)
glDrawElements(GL_TRIANGLES, len(indices), GL_UNSIGNED_INT, None)
# 绘制第二个矩形
model = pyrr.matrix44.multiply(scale1, cube2)
scale2 = pyrr.matrix44.create_from_scale(pyrr.Vector3([-1, 1, 1]))
glUniformMatrix4fv(rotation_loc, 1, GL_FALSE, pyrr.matrix44.multiply(scale2, model))
glDrawElements(GL_TRIANGLES, len(indices), GL_UNSIGNED_INT, None)
# 绘制第三个矩形
model = pyrr.matrix44.multiply(scale1, cube3)
scale2 = pyrr.matrix44.create_from_scale(pyrr.Vector3([-1, -1, 1]))
glUniformMatrix4fv(rotation_loc, 1, GL_FALSE, pyrr.matrix44.multiply(scale2, model))
glDrawElements(GL_TRIANGLES, len(indices), GL_UNSIGNED_INT, None)
# 绘制第四个矩形
model = pyrr.matrix44.multiply(scale1, cube4)
scale2 = pyrr.matrix44.create_from_scale(pyrr.Vector3([1, -1, 1]))
glUniformMatrix4fv(rotation_loc, 1, GL_FALSE, pyrr.matrix44.multiply(scale2, model))
glDrawElements(GL_TRIANGLES, len(indices), GL_UNSIGNED_INT, None)
glfw.swap_buffers(window)
# terminate glfw, free up allocated resources
glfw.terminate()
六、参考资料
1、大龙10的简书:https://www.jianshu.com/p/49dec482a291
2、The fool的博客:https://blog.youkuaiyun.com/wangdingqiaoit/article/details/51531002