zoukankan      html  css  js  c++  java
  • 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切换一三人称漫游,小键盘上的+与—分别是增加与缩小人与摄像机的距离。

    一三人称小室切换版。

  • 相关阅读:
    [译]CasperJS,基于PhantomJS的工具包
    [译]JavaScript:typeof的用途
    [译]JavaScript写的一个quine程序
    [译]Ruby中的解构赋值
    [译]DOM:元素ID就是全局变量
    [译]ECMAScript 6中的集合类型,第一部分:Set
    [译]JavaScript:Array.prototype和[]的性能差异
    [译]Web Inspector开始支持CSS区域
    [译]JavaScript:反科里化"this"
    [译]JavaScript:用什么来缩进
  • 原文地址:https://www.cnblogs.com/zhouxin/p/3430558.html
Copyright © 2011-2022 走看看