Opengl繪制我們的小屋(四)第三人稱漫游


本節內容是在第一人稱漫游上完成的,請先了解上文中第一人稱漫游的實現.

這一節講下第三人稱漫游是如何實現,第三人稱,簡單來說,就是在你后面會跟着一台攝像機順着你拍攝。

先看一下失敗的嘗試。這個方法是把人定在攝像機方向的前面,結合前面第一人稱漫游的實現,如果只是前后左右移動,人和攝像機是一起的,這樣是不用改動,關鍵是原來以攝像機為原點旋轉,而這個我們要以人為原點來旋轉,先來看下水平左右的的旋轉實現,如下圖:

 

根據上面關系,我們主要代碼如下,大致過程如下,人左右旋轉,然后得到攝像機的新位置,攝像機再調整方向,根據攝像機的方向與人的距離設定人的位置。

 1 type ThreeCamera() = 
 2         let camera = new Camera()
 3         let mutable toEye = 1.f
 4         member this.Eye with get() = camera.Eye 
 5         member this.Target with get() = camera.Target
 6         member this.Location 
 7             with get() = 
 8                 let mutable tv = camera.Target-camera.Eye
 9                 tv.Normalize()
10                 camera.Eye + tv * toEye
11         member this.ToEye with get() = toEye and set value = toEye <- value
12         member this.Transelt (x,y,z) = 
13             camera.Transelt(x,y,z)          
14         //左右對中心轉     
15         member this.RightAndLeft x =            
16             let origin = this.Location
17             let oe = camera.Eye - origin
18             let length = oe.Length
19             let oex = Vector2(oe.X,oe.Z)
20             let oez = Vector2(-oe.Z,oe.X)
21             let sinLR =length *  float32 (Math.Sin(x))
22             let cosLR =length *  float32 (Math.Cos(x))  
23         //得到攝像機新位置
24             let newEye = oex * cosLR + oez * sinLR + Vector2(origin.X,origin.Z)
25             camera.Eye <- Vector3(newEye.X,camera.Eye.Y,newEye.Y)
26         //重新調整攝像機的方向
27         camera.XAngle <- camera.XAngle + x
View Code

左右旋轉在正常的速度下,能得到正常的效果,后面我試着改變人與攝像機的長度,或者快速左右旋轉,都會造成人的位置移動,想了一久都沒想到是什么原因,如果有知道可能原因,麻煩告知一下.謝謝了.

此路不通后,我想了一種思路,說起來很簡單,第一人稱是以攝像機為球心,攝像機的方向為球面坐標系.如果以第三人稱來看,人應該是球心,攝像機所在位置可以看做是球面,只需要換算一下球心與球面的算法就可以,如下所示.

 1     type Camera() = 
 2         let mutable origin = Vector3.Zero
 3         let mutable length = 1.
 4         let mutable yangle = 0.
 5         let mutable xangle= Math.PI/2.
 6         let mutable bThree = true
 7         do
 8             if not bThree then xangle <- Math.PI/2. else xangle <- 1.5*Math.PI            
 9         member this.IsThree 
10             with get() = bThree 
11             and set value = 
12                 //if value then this.Origin <- this.Target
13                 xangle <- xangle + Math.PI
14                 bThree <- value
15         member this.Eye 
16             with get() = 
17                 let mutable eye = this.Origin
18                 if bThree then eye <- this.Direction
19                 eye
20         member this.People 
21             with get() = 
22                 let mutable people = this.Origin
23                 if not bThree then people <- this.Direction
24                 people
25         member this.Target 
26              with get() = 
27                 let mutable target = this.Direction
28                 if bThree then target <- this.Origin
29                 target
30         member this.Origin 
31             with get() = origin 
32             and set value = origin <- value
33         member this.Length 
34             with get() = length 
35             and set value = 
36                 if value < 0. then length <- 0.1
37                 length <- value
38         member this.YAngle 
39             with get() = yangle
40             and set value = 
41                 if value > Math.PI/2. then yangle <- Math.PI/2.
42                 elif value < -Math.PI/2. then yangle <- -Math.PI/2.
43                 else yangle <- value
44         member this.XAngle 
45             with get() = xangle
46             and set value = 
47                 if value > 2.* Math.PI then xangle <- value - 2.* Math.PI
48                 elif value < 0. then xangle <- value + 2. * Math.PI
49                 else xangle <- value       
50         member this.PeopleAngle 
51             with get()=
52                 let mutable angle = this.XAngle + Math.PI/2.
53                 angle
54         member this.Direction 
55             with get() = 
56                 let mutable len = 1.
57                 if bThree then len <- length
58                 let xyLength = Math.Cos(this.YAngle) * len
59                 let x:float =float origin.X + xyLength * Math.Cos(this.XAngle)
60                 let y:float =float origin.Y + len * Math.Sin(this.YAngle)
61                 let z:float =float origin.Z + xyLength * Math.Sin(this.XAngle)
62                 Vector3(float32 x,float32 y,float32 z)
63         member this.Transelt (x,y,z) = 
64             let sinX = Math.Sin(this.XAngle)
65             let cosX = Math.Cos(this.XAngle)
66             let mutable xstep = x * sinX + z * cosX 
67             let mutable zstep = z * sinX - x * cosX
68             if bThree then 
69                 xstep <- -xstep
70                 zstep <- -zstep
71             let x1 = float origin.X + xstep
72             let y1 = float origin.Y + y
73             let z1 = float origin.Z + zstep 
74             printfn "angle:%f, sinx:%f, cosx:%f" this.XAngle sinX cosX
75             printfn "x:%f, y:%f, z:%f" x1 y1 z1
76             origin <- new Vector3(float32 x1,float32 y1,float32 z1)
77         member this.Rotate (x,y) =
78             let xa = this.XAngle + x
79             let mutable ystep = y
80             if bThree then ystep <- -y
81             let ya =this.YAngle + ystep
82             this.YAngle <- ya
83             this.XAngle <- xa
View Code

xangle與yangle分別是指人或者攝像機當前的偏移量,上文中講第一人稱有講。IsThree表示是在第三人稱漫游情況下,這里面會計算球心Origin與球面Direction,在第一人稱時,攝像機位置Eye是origin,攝像機方向Target是Direction,因為攝像機是方向向量,所以length此時固定為1來算,此時改變此值沒什么意義,而在第三人稱時,人是Origin,而攝像機Eye是Direction,此時length表示人與攝像機的距離,會造成視角內人物放大與放小的效果。

這段代碼可以很好的工作,並且很容易就實現第一人稱與第三人稱的切換,需要注意的是,以第三人稱漫游時,上下旋轉和前后左右走動與第一人稱是相反的,大家可以自己想像一下,在第三人稱時,人向上,對應攝像機的在球面是向下動的,同理,前后左右走動也是一樣,只有左右旋轉時,第一人稱與第三人稱方向一致。

效果圖,燈光還沒設置完整,里面有點暗。

原來的附件在我的筆記本上HD5650可以運行,我發現在我老婆的電腦上,用的是650TI,會出現相關內存不能為讀的問題,經查找,發現問題是在設置頂點數據//GL.VertexPointer(3,VertexPointerType.Float,0,IntPtr.Zero)這句代碼有問題,現改為GL.InterleavedArrays(InterleavedArrayFormat.V3f,0,IntPtr.Zero),也可以運行,具體原因不知,有那么清楚,可以幫忙說明下。

下面給出實現第一人稱與第三人稱切換版的附件。

新增加快捷鍵V切換一三人稱漫游,小鍵盤上的+與—分別是增加與縮小人與攝像機的距離。

一三人稱小室切換版。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM