一、目的
1、攝像機(jī)應(yīng)用,正交投影畫(huà)六角星;
二、程序運(yùn)行結(jié)果
三、攝像機(jī)的設(shè)置
?? 吳亞峰《OpenGL ES 3.x游戲開(kāi)發(fā)》(上卷)內(nèi)容
?? 從日常生活的經(jīng)驗(yàn)中可以很容易地了解到,隨著攝像機(jī)位置、姿態(tài)的不同,就算是對(duì)同一個(gè)場(chǎng)景進(jìn)行拍攝,得到的畫(huà)面也是迥然不同的。
?? 攝像機(jī)的設(shè)置需要給出 3 方面的信息,包括攝像機(jī)的位置、觀察的方向以及 up 方向,具體情況如圖5-1 所示。

- 攝像機(jī)的位置很容易理解,用其在 3D 空間中的坐標(biāo)來(lái)表示。
- 攝像機(jī)觀察的方向可以理解為攝像機(jī)鏡頭的指向,用一個(gè)觀察目標(biāo)點(diǎn)來(lái)表示(通過(guò)攝像機(jī)位置與觀察目標(biāo)點(diǎn)可以確定一個(gè)向量,此向量即代表了攝像機(jī)觀察的方向)。
- 攝像機(jī)的 up 方向可以理解為攝像機(jī)頂端的指向,用一個(gè)向量來(lái)表示。
??可以看出,攝像機(jī)的位置、朝向、 up 方向可以有很多不同的組合。
??程序通過(guò)調(diào)用pyrr.matrix44.create_look_at()方法來(lái)完成對(duì)攝像機(jī)的設(shè)置
mvMatrix = pyrr.matrix44.create_look_at(cameraPos, cameraFront, cameraUp,None)
四、兩種投影方式
??在圖元裝配之后的光柵化階段前,首先需要把虛擬 3D 世界中的物體投影到二維平面上。 OpenGL中常用的投影模式有兩種,分別為正交投影與透視投影
1、 正交投影
??OpenGL中,根據(jù)應(yīng)用程序中?供的投影矩陣,管線會(huì)確定一個(gè)可視空間區(qū)域,稱為
視景體。視景體是由 6 個(gè)平面確定的,這 6 個(gè)平面分別為:上平面(up)、下平面(down)、左平面(left)、右平面(right)、遠(yuǎn)平面(far)、近平面(near)。
??場(chǎng)景中處于視景體內(nèi)的物體會(huì)被投影到近平面上(視景體外面的物體將被裁剪掉),然后再將近平面上投影出的內(nèi)容映射到屏幕上的視口中。對(duì)于正交投影而言,視景體及近平面的情況如圖 5-3所示。

??從圖 5-3 中可以看出,由于正交投影是平行投影的一種,其投影線(物體的頂點(diǎn)與近平面上投影點(diǎn)的連線)是平行的。故其視景體為長(zhǎng)方體,投影到近平面上的圖形不會(huì)產(chǎn)生真實(shí)世界中“近大遠(yuǎn)小”的效果,圖 5-4 更清楚地說(shuō)明了這個(gè)問(wèn)題

五、源代碼
"""
程序名稱:GL_orthoM.py
編程: dalong10
功能: 正交投影的實(shí)現(xiàn)
參考資料: 《OpenGL ES 3.x游戲開(kāi)發(fā)》(上卷)吳亞峰
"""
import myGL_Funcs #Common OpenGL utilities,see myGL_Funcs.py
import glfw
from OpenGL.GL import *
import numpy
import numpy as np
import pyrr
from PIL import Image
StarVS = """
# version 330
layout(location = 0) in vec3 a_position; //頂點(diǎn)位置
layout(location = 1) in vec3 a_color; //頂點(diǎn)顏色
uniform mat4 rotation; //總變換矩陣
out vec3 v_color; //用于傳遞給片元著色器的變量
void main()
{
gl_Position = rotation * vec4(a_position, 1.0); //根據(jù)總變換矩陣計(jì)算此次繪制此頂點(diǎn)位置
v_color = a_color; //將接收的顏色傳遞給片元著色器
}
"""
StarFS = """
# version 330
in vec3 v_color; //接收從頂點(diǎn)著色器過(guò)來(lái)的參數(shù)
out vec4 out_color; //輸出到的片元顏色
void main()
{
out_color = vec4(v_color, 1.0f); //給此片元顏色值
}
"""
class SixPointedStar:
def initVertexData(self,R,r,z): # 初始化頂點(diǎn)數(shù)據(jù)的initVertexData方法
self.vertexs = np.array([], np.float32) # 位置FloatArray(numPoint * 3)
self.colorArray = np.array([], np.float32) # 顏色FloatArray(numPoint * 4)
# 把矩形平鋪在一個(gè)平面上
PI = np.pi
tempAngle=int(360/6)
count=0
for angle in range(0,360,tempAngle): # 循環(huán)生成構(gòu)成六角形各三角形的頂點(diǎn)坐標(biāo)
x1=0.0 #第一個(gè)三角形,三個(gè)點(diǎn)
y1=0.0
z1=z
x2=R*np.cos(PI*angle/180)
y2=R*np.sin(PI*angle/180)
z2=z
x3=r*np.cos(PI*(angle+tempAngle/2)/180)
y3=r*np.sin(PI*(angle+tempAngle/2)/180)
z3=z
x4=0
y4=0
z4=z
x5=r*np.cos(PI*(angle+tempAngle/2)/180)
y5=r*np.sin(PI*(angle+tempAngle/2)/180)
z5=z
x6=R*np.cos(PI*(angle+tempAngle)/180)
y6=R*np.sin(PI*(angle+tempAngle)/180)
z6=z
self.vertexs=np.hstack((self.vertexs, np.array([x1,y1,z1], np.float32) )) #每個(gè)頂點(diǎn)xyz三個(gè)坐標(biāo),6個(gè)頂點(diǎn)
self.vertexs=np.hstack((self.vertexs, np.array([1,1,1], np.float32) )) #中心點(diǎn)為白色
self.vertexs=np.hstack((self.vertexs, np.array([x2,y2,z2], np.float32) ))
self.vertexs=np.hstack((self.vertexs, np.array([0.45,0.75,0.75], np.float32) )) #邊上的點(diǎn)為淡藍(lán)色
self.vertexs=np.hstack((self.vertexs, np.array([x3,y3,z3], np.float32) ))
self.vertexs=np.hstack((self.vertexs, np.array([0.45,0.75,0.75], np.float32) )) #邊上的點(diǎn)為淡藍(lán)色
self.vertexs=np.hstack((self.vertexs, np.array([x4,y4,z4], np.float32) ))
self.vertexs=np.hstack((self.vertexs, np.array([1,1,1], np.float32) )) #中心點(diǎn)為白色
self.vertexs=np.hstack((self.vertexs, np.array([x5,y5,z5], np.float32) ))
self.vertexs=np.hstack((self.vertexs, np.array([0.45,0.75,0.75], np.float32) )) #邊上的點(diǎn)為淡藍(lán)色
self.vertexs=np.hstack((self.vertexs, np.array([x6,y6,z6], np.float32) ))
self.vertexs=np.hstack((self.vertexs, np.array([0.45,0.75,0.75], np.float32) )) #邊上的點(diǎn)為淡藍(lán)色
def __init__(self,R,r,z):
self.R= R
self.r= r
self.z = z
self.initVertexData(R,r,z)
# load shaders
self.program = myGL_Funcs.loadShaders(StarVS, StarFS)
#print('ok1')
glUseProgram(self.program)
self.vertIndex = glGetAttribLocation(self.program, b"a_position")
self.colorIndex = glGetAttribLocation(self.program, b"a_color")
# set up vertex array object (VAO)
self.vao = glGenVertexArrays(1)
glBindVertexArray(self.vao)
# Step2: 創(chuàng)建并綁定VBO 對(duì)象 傳送數(shù)據(jù)
#self.vertexs= vertices
vertexData = numpy.array(self.vertexs, numpy.float32)
self.vertexBuffer = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, self.vertexBuffer)
glBufferData(GL_ARRAY_BUFFER, 4*len(vertexData), vertexData, GL_STATIC_DRAW)
# enable arrays
# 頂點(diǎn)位置屬性
glEnableVertexAttribArray(self.vertIndex)
glVertexAttribPointer(self.vertIndex, 3, GL_FLOAT, GL_FALSE, vertexData.itemsize * 6, ctypes.c_void_p(0))
# 頂點(diǎn)顏色屬性
glEnableVertexAttribArray(self.colorIndex)
glVertexAttribPointer(self.colorIndex, 3, GL_FLOAT, GL_FALSE, vertexData.itemsize * 6, ctypes.c_void_p(12))
# unbind VAO
glBindVertexArray(0)
glBindBuffer(GL_ARRAY_BUFFER, 0)
def render(self, model):
# use shader
glUseProgram(self.program)
# set modelview matrix
glUniformMatrix4fv(glGetUniformLocation(self.program, 'rotation'),
1, GL_FALSE, model)
# bind VAO
glBindVertexArray(self.vao)
# draw
#print(len(self.vertexs))
glDrawArrays(GL_TRIANGLES,0,len(self.vertexs) )
# unbind VAO
glBindVertexArray(0)
# glfw callback functions
def window_resize(window, width, height):
glViewport(0, 0, width, height)
if __name__ == '__main__':
import sys
import glfw
import OpenGL.GL as gl
cameraPos=np.array([2.0, 0.0, 3]) # 眼睛的位置(默認(rèn)z軸的正方向)
cameraFront=np.array([0.0, 0.0, 0.0]) # 瞄準(zhǔn)方向的參考點(diǎn)(默認(rèn)在坐標(biāo)原點(diǎn))
cameraUp=np.array([0.0, 1.0, 0.0]) # 定義對(duì)觀察者而言的上方(默認(rèn)y軸的正方向)
# Initialize the library
if not glfw.init():
sys.exit()
# Create a windowed mode window and its OpenGL context
window = glfw.create_window(400, 300, "My OpenGL window", None, None)
if not window:
glfw.terminate()
sys.exit()
# 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)
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([1, 1, 1]))
cube1 = pyrr.matrix44.create_from_translation(pyrr.Vector3([-0.2, 0, 0]))
board= [None]*6 #創(chuàng)建對(duì)象數(shù)組
for i in range(6):
board[i]=SixPointedStar(0.2,0.5,-0.3*i)
# the main application loop
while not glfw.window_should_close(window):
width, height = glfw.get_framebuffer_size(window)
ratio = width / float(height)
currentFrame = 1.0*glfw.get_time()
glfw.poll_events()
gl.glViewport(0, 0, width, height)
gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)
gl.glMatrixMode(gl.GL_PROJECTION)
gl.glLoadIdentity()
gl.glOrtho(-ratio, ratio, -1, 1, 1, -1)
gl.glMatrixMode(gl.GL_MODELVIEW)
gl.glLoadIdentity()
gl.glClearColor(0.0,0.0,4.0,0.0)
pMatrix = pyrr.matrix44.create_orthogonal_projection_matrix(-1, 1,-1,1, 1, 10.0,None)
# modelview matrix
mvMatrix = pyrr.matrix44.create_look_at(cameraPos, cameraFront, cameraUp,None)
for i in range(6):
model1 = pyrr.matrix44.multiply(scale1, cube1)
model2 = pyrr.matrix44.multiply(pMatrix,model1)
model3 = pyrr.matrix44.multiply(mvMatrix,model2)
board[i].render( model3)
glfw.swap_buffers(window)
# terminate glfw, free up allocated resources
glfw.terminate()
六、參考資料
1、大龍10的簡(jiǎn)書(shū):http://www.itdecent.cn/p/49dec482a291
2、吳亞峰《OpenGL ES 3.x游戲開(kāi)發(fā)》(上卷)