zoukankan      html  css  js  c++  java
  • Opengl绘制我们的小屋(二)第一人称漫游

    这章我们先讲第一人称漫游的实现.在openTK里,我们用函数Matrix4.LookAt(caram.Eye,caram.Target,Vector3.UnitY)来放置摄像机,其中三个参数分别与摄像机位置,摄像机朝向,摄像机向上的向量.与opengl里的glulookat其实是一样的.

    本来为了查找漫游的功能,在网上找了些,发现相关讲解都很少,更多只是写出了代码,花了一些时间查找相关概念与调试,其中把我的理解会说明上,有不对的地方欢迎大家指出.

    漫游最基本的功能,我们包括相关步进,前进,后退,左进,右进.还有就是视角旋转,包含水平方向旋转,以及垂直方向上的旋转.在讲下面之前,我们先来看下什么是球面坐标系.

    引用维基百科里的

    数学里,球坐标系英语Spherical coordinate system)是一种利用球坐标 (r, 	heta, phi) 表示一个点 p 在三维空间的位置的三维正交坐标系

    右图显示了球坐标的几何意义:原点与点 P 之间的径向距离 r ,原点到点 P 的连线与正 z-轴之间的天顶角 	heta ,以及原点到点 P 的连线,在 xy-平面的投影线,与正 x-轴之间的方位角 phi

    x=r sin	heta cosphiy=r sin	heta sinphiz=r cos	heta

    上面的这些大家都好理解,我们的漫游模型可以根据这个来,eye是摄像机位置,p摄像机朝向向量.但是我们的坐标应该是这样的.

    人眼球面坐标

    根据上面的我们来完成我们摄像机类,如下.

     1     type Camera() = 
     2         let mutable eye = Vector3.Zero
     3         let mutable eyeLength = 1.
     4         let mutable yangle = 0.
     5         let mutable xangle= Math.PI/2.
     6         member this.Eye 
     7             with get() = eye 
     8             and set value = eye <- value
     9         member this.EyeLength 
    10             with get() = eyeLength 
    11             and set value = 
    12                 if value < 0. then eyeLength <- 0.1
    13                 eyeLength <- value
    14         member this.YAngle 
    15             with get() = yangle
    16             and set value = 
    17                 if value > Math.PI then yangle <- 0.
    18                 //elif value < 0. then yangle <- Math.PI 
    19                 else yangle <- value
    20         member this.XAngle 
    21             with get() = xangle
    22             and set value = 
    23                 printfn "xangle:%f" value
    24                 if value > 2.* Math.PI then xangle <- 0.
    25                 elif value < 0. then xangle <- 2. * Math.PI
    26                 else xangle <- value
    27         member this.Target 
    28             with get() = 
    29                 //printfn "%f" this.XAngle 
    30                 let xyLength = Math.Cos(this.YAngle)
    31                 let x:float =float eye.X + eyeLength * xyLength * Math.Cos(this.XAngle)
    32                 let y:float =float eye.Y + eyeLength * Math.Sin(this.YAngle)
    33                 let z:float =float eye.Z + eyeLength * xyLength * Math.Sin(this.XAngle)
    34                 Vector3(float32 x,float32 y,float32 z)
    35         member this.Transelt (x,y,z) = 
    36             let sinX = Math.Sin(this.XAngle)
    37             let cosX = Math.Cos(this.XAngle)
    38             let x1 = float this.Eye.X + x * sinX + z * cosX
    39             let y1 = float this.Eye.Y + y
    40             let z1 = float this.Eye.Z + z * sinX - x * cosX
    41             printfn "angle:%f, sinx:%f, cosx:%f" this.XAngle sinX cosX
    42             printfn "x:%f, y:%f, z:%f" x1 y1 z1
    43             this.Eye <- new Vector3(float32 x1,float32 y1,float32 z1)
    44         member this.UpAndDown y =
    45             let ya = this.YAngle + y
    46             this.YAngle <- ya
    47         member this.RightAndLeft x =
    48             let xa = this.XAngle + x
    49             this.XAngle <- xa
    50         member this.Rotate (x,y) =
    51             let xa = this.XAngle + x
    52             let ya = this.YAngle + y
    53             this.YAngle <- ya
    54             this.XAngle <- xa
    View Code

    可以看到我们的Target,就是看的方向,根据球面坐标,我们可以通过xangle与yangle来求得。而xangle与yangle可以根据上面给出的UpAndDown,RightAndLeft,Rotate这三个方法来增加对应我们在水平与垂直方向上的旋转角度.其中Xangle默认是PI/2,就是90度,是因为默认我们是向前看,也就是向Z轴看.

    然后是左右,上下前进的代码,这部分逻辑代码在this.Transelt (x,y,z) ,x,y,z分别表示左右,上下,前后上的走的值,最开始我用的(x1,z1) = this.Eye.(X,Z) + (x,z)这样发现如果没有进行旋转,那么是对的,但是如果我旋转90度后来看,前后变成左右了,大家可以试着分析下相关原因,比如前进,我们增加的是z的值.但是我们旋转90度后,我们再来看,这是前进对应的是x轴的值,所以实际上,我们前后左右走,还与我们的左右旋转的角度xangle有关,实际我们应该是以方向向量为xangle方向在对应的x与z值的投影值.

    如果这个图还是不理解,可以看Opengl绘制我们的小屋(四)第三人称漫游第一张图有更详细的说明.

    下面我们进入我们主题,画一个室内景,下面是我在网上找的一个室内模型图,用手机照的,可能不是很清晰. 

    我们根据上面的模型来建模,相关立方体用上文提供的绘制方法,相关代码如下.

      1 #r "F:3D1.0BinariesOpenTKDebugOpenTK.dll"
      2 #r "F:3D1.0BinariesOpenTKDebugOpenTK.GLControl.dll"
      3 #r "F:3D1.0BinariesOpenTKDebugExamples.exe"
      4 #load "Shape.fsx"
      5 
      6 open System
      7 open System.Collections.Generic
      8 open System.Windows.Forms
      9 open System.Threading
     10 open System.Drawing
     11 open System.Drawing.Imaging
     12 open OpenTK
     13 open OpenTK.Graphics
     14 open OpenTK.Graphics.OpenGL
     15 open Shape
     16 
     17 type loopForm() as form=
     18     inherit Form()
     19     let caram = Shape.Camera()
     20     let offest = 0.1f
     21     let offestd = float offest
     22     let glControl = new OpenTK.GLControl()
     23 
     24     let cubeEnter = Shape.Cube(1.5f,0.2f,1.8f,3)
     25     let cubeParlor = Shape.Cube(4.9f,0.2f,6.3f,3)
     26     let cubeBalcony1 = Shape.Cube(4.9f,0.2f,1.9f,3)
     27     let cubeBalcony2 = Shape.Cube(1.6f,0.2f,2.1f,3)
     28     let cubeBalcony3 = Shape.Cube(1.8f,0.2f,3.0f,3)
     29     let cubeKitchen = Shape.Cube(4.5f,0.2f,1.8f,3)
     30     let cubeBathroom = Shape.Cube(2.1f,0.2f,2.1f,3)
     31     let cubeGallery = Shape.Cube(2.1f,0.2f,1.2f,3)
     32     let cubeMasterBedroom = Shape.Cube(3.6f,0.2f,3.9f,3)
     33     let cubeSecondbedroom = Shape.Cube(3.0f,0.2f,3.3f,3)
     34 
     35     let cubeWall1 = Shape.Cube(0.2f,3.f,8.1f,0)
     36     let cubeWall2 = Shape.Cube(4.5f,3.f,0.2f,0)
     37     let cubeWall3 = Shape.Cube(0.2f,3.f,1.8f,0)
     38     let cubeWall4 = Shape.Cube(0.2f,1.8f,1.8f,0)
     39     let cubeWall5 = Shape.Cube(3.0f,3.f,0.2f,0)
     40     let cubeWall6 = Shape.Cube(0.2f,3.f,3.7f,0)
     41     let cubeBathroom1 = Shape.Cube(2.1f,3.f,0.2f,0)
     42     let cubeBathroom2 = Shape.Cube(0.2f,3.f,2.1f,0)
     43     let cubeFence1 = Shape.Cube(0.05f,0.02f,1.9f,0)
     44     let cubeFence2 = Shape.Cube(2.3f,0.02f,0.05f,0)
     45     let cubeFence3 = Shape.Cube(0.05f,0.02f,2.1f,0)
     46     let cubeFence4 = Shape.Cube(3.4f,0.02f,0.05f,0)
     47     let cubeWall7 = Shape.Cube(2.1f,3.f,0.2f,4)
     48     let cubeWall8 = Shape.Cube(0.2f,3.f,3.0f,0)
     49     let cubePillar = Shape.Cube(0.2f,3.f,0.2f,4)
     50     let cubePillar2 = Shape.Cube(0.1f,1.1f,0.2f,4)
     51     let mutable oldMouseLocation = Vector2.Zero
     52     do
     53         caram.Transelt(1.,1.7,0.0)
     54         form.SuspendLayout()
     55         glControl.Location <- new Point(10,40)
     56         glControl.Size <- new Size(400,300)
     57         glControl.BackColor <- Color.Red
     58         glControl.Resize.Add(form.resize)
     59         glControl.Paint.Add(form.paint)
     60         glControl.KeyDown.Add(form.KeyDown)
     61         glControl.MouseMove.Add(form.MouseDownv)
     62         form.ClientSize <- new Size(450,350)
     63         form.Text <- "opengl"
     64         form.StartPosition <- FormStartPosition.Manual
     65         form.Location <- new Point(1200,600)
     66         form.Controls.Add(glControl)
     67         form.ResumeLayout(false)
     68         //#endregion 
     69     override v.OnLoad e =
     70         base.OnLoad e
     71         GL.ClearColor Color.MidnightBlue
     72         Application.Idle.Add(v.AIdle)
     73         GL.FrontFace FrontFaceDirection.Ccw
     74         GL.Enable( EnableCap.PointSmooth )
     75         //踢除正反面
     76         GL.Enable EnableCap.CullFace
     77         GL.CullFace CullFaceMode.Back
     78         //设置材料面填充模式
     79         GL.PolygonMode(MaterialFace.Front,PolygonMode.Fill)
     80         GL.PolygonMode(MaterialFace.Back,PolygonMode.Line)
     81 //#region
     82     member v.resize (e:EventArgs) =
     83         GL.Viewport(0,0,glControl.ClientSize.Width,glControl.ClientSize.Height)
     84         let aspect = float32 glControl.ClientSize.Width /float32 glControl.ClientSize.Height
     85         let mutable projection = Matrix4.CreatePerspectiveFieldOfView(MathHelper.PiOver2,aspect,0.1f,30.f)
     86         GL.MatrixMode MatrixMode.Projection
     87         GL.LoadMatrix(&projection)
     88     member v.paint (e:PaintEventArgs) =
     89         v.Render()
     90     member v.AIdle (e:EventArgs) =
     91         while (glControl.IsIdle) do
     92             v.Render()
     93     member v.MouseDownv(e:MouseEventArgs) =
     94         if e.Button = MouseButtons.Right then
     95             if oldMouseLocation = Vector2.Zero then
     96                 oldMouseLocation <- Vector2(float32 e.X,float32 e.Y)
     97             else
     98                 let nx = (float32 e.X - oldMouseLocation.X) * offest * 0.1f
     99                 let ny = (float32 e.Y - oldMouseLocation.Y) * offest * -0.1f
    100                 caram.Rotate(float nx,float ny)
    101         oldMouseLocation <- Vector2(float32 e.X,float32 e.Y)     
    102     member v.KeyDown(e:KeyEventArgs) =
    103         //let keys = e.KeyData
    104         match e.KeyCode with
    105         | Keys.E ->caram.Transelt(0.,0.,1.* offestd)
    106         | Keys.D ->caram.Transelt(0.,0.,-1.* offestd)
    107         | Keys.S ->caram.Transelt(1.* offestd,0.,0.0)
    108         | Keys.F ->caram.Transelt(-1.* offestd,0.,0.)
    109         | _ -> ()
    110     member x.UIValue
    111         with get (text:TextBox) = 
    112             let mutable value = 0.f
    113             if System.Single.TryParse(text.Text,&value) then
    114                 value <- value
    115             value
    116         and set (text:TextBox) (value:float32) = text.Text<- value.ToString()
    117 //#endregion        
    118     member v.Render =
    119         //Keyboard[OpenTK.Input.Key.F11]
    120         GL.Clear(ClearBufferMask.ColorBufferBit ||| ClearBufferMask.DepthBufferBit)
    121         //地面
    122         v.DrawCube(cubeEnter,Vector3.Zero)
    123         v.DrawCube(cubeParlor,0.f,0.f,1.8f)
    124         v.DrawCube(cubeBalcony1,0.f,0.f,8.1f)
    125         v.DrawCube(cubeBalcony2,2.3f,0.f,10.f)
    126         v.DrawCube(cubeBalcony3,3.9f,0.f,9.f)
    127         v.DrawCube(cubeKitchen,1.5f,0.f,0.f)
    128         v.DrawCube(cubeBathroom,3.9f,0.f,1.8f)
    129         v.DrawCube(cubeGallery,3.9f,0.f,3.9f)
    130         v.DrawCube(cubeMasterBedroom,3.9f,0.f,5.1f)
    131         v.DrawCube(cubeSecondbedroom,6.0f,0.f,1.8f)  
    132         //
    133         v.DrawCube(cubeWall1,Vector3.Zero)
    134         v.DrawCube(cubeWall2,Vector3(1.5f,0.f,0.f))
    135         v.DrawCube(cubeWall3,Vector3(1.5f,0.f,0.f))
    136         v.DrawCube(cubeWall4,Vector3(6.0f,0.f,0.f))
    137         v.DrawCube(cubeWall5,Vector3(6.0f,0.f,1.8f))
    138         v.DrawCube(cubeWall6,Vector3(9.0f,0.f,1.8f))
    139         v.DrawCube(cubeWall6,Vector3(7.5f,0.f,5.1f))
    140         v.DrawCube(cubeWall6,Vector3(3.9f,0.f,5.1f))        
    141         v.DrawCube(cubeWall7,Vector3(3.9f,0.f,9.0f))
    142         v.DrawCube(cubeWall8,Vector3(6.0f,0.f,9.0f))
    143         v.DrawCube(cubeBathroom1,Vector3(3.9f,0.f,1.8f))
    144         //v.DrawCube(cubeBathroom1,Vector3(3.9f,0.f,3.9f))
    145         v.DrawCube(cubeBathroom2,Vector3(3.9f,0.f,1.8f))
    146         v.DrawCube(cubeBathroom2,Vector3(6.0f,0.f,1.8f))
    147         v.DrawCube(cubeFence1,0.0f,1.f,8.1f)  
    148         v.DrawCube(cubeFence2,0.0f,1.f,10.f)  
    149         v.DrawCube(cubeFence3,2.3f,1.f,10.f)  
    150         v.DrawCube(cubeFence4,2.3f,1.f,12.1f)  
    151         v.DrawCube(cubePillar,Vector3(2.3f,0.f,12.f))
    152         v.DrawCube(cubePillar,Vector3(2.3f,0.f,9.9f))
    153         v.DrawCube(cubePillar2,Vector3(0.f,0.f,9.9f))
    154         //房顶
    155         GL.PushMatrix()
    156         GL.Translate(0.f,3.f,0.f)
    157         v.DrawCube(cubeEnter,Vector3.Zero)
    158         v.DrawCube(cubeParlor,0.f,0.f,1.8f)
    159         v.DrawCube(cubeBalcony1,0.f,0.f,8.1f)
    160         v.DrawCube(cubeBalcony2,2.3f,0.f,10.f)
    161         v.DrawCube(cubeBalcony3,3.9f,0.f,9.f)
    162         v.DrawCube(cubeKitchen,1.5f,0.f,0.f)
    163         v.DrawCube(cubeBathroom,3.9f,0.f,1.8f)
    164         v.DrawCube(cubeGallery,3.9f,0.f,3.9f)
    165         v.DrawCube(cubeMasterBedroom,3.9f,0.f,5.1f)
    166         v.DrawCube(cubeSecondbedroom,6.0f,0.f,1.8f)   
    167         GL.PopMatrix()             
    168         let mutable lookat = Matrix4.LookAt(caram.Eye,caram.Target,Vector3.UnitY)
    169         GL.MatrixMode(MatrixMode.Modelview)
    170         GL.LoadMatrix(&lookat)  
    171         glControl.SwapBuffers()
    172         ignore
    173     member v.DrawCube(cube:Shape.Cube,pos:Vector3) =
    174         v.DrawCube(cube,pos,cube.Index)
    175     member v.DrawCube(cube:Shape.Cube,x,y,z) =
    176         v.DrawCube(cube,new Vector3(x,y,z),cube.Index)
    177     member v.DrawCube(cube:Shape.Cube,x,y,z,ind) =
    178         v.DrawCube(cube,new Vector3(x,y,z),ind)
    179     member v.DrawCube(cube:Shape.Cube, pos:Vector3, ind:int) =
    180         GL.PushMatrix()
    181         cube.Index <- ind
    182         GL.Translate(pos)
    183         cube.Draw()
    184         GL.PopMatrix()
    185 let t = new loopForm()
    186 t.Show()
    View Code

    v.MouseDownv(e:MouseEventArgs)实际对应的鼠标移动,作用是检测鼠标右键按下后,鼠标移动向量,然后进行上下,左右的旋转.

    v.KeyDown(e:KeyEventArgs) 就是EDSF行走.对应前后左右.

    在Render里,就是我们绘制的模型代码,先画模型,然后设置相机.别的如投影矩阵,大家如果有兴趣,可以自己查找相关资料.

    let mutable lookat = Matrix4.LookAt(caram.Eye,caram.Target,Vector3.UnitY)
    GL.MatrixMode(MatrixMode.Modelview)
    GL.LoadMatrix(&lookat)

    效果图.我不否认这很丑,可能下一章节还要丑,下一章节如果没意外,会先讲灯光的应用,然后才是纹理.

    附件为相关代码以及可运行程序,操作方式和网游一样,鼠标右键按下,上下左右移动是视角.WASD行走,(代码里是EDSF,游戏里的快捷键习惯).

    后面我会介绍灯光与纹理贴图的相关应用.

    附件地址 http://files.cnblogs.com/zhouxin/%E9%99%84%E4%BB%B6.rar

  • 相关阅读:
    三大主流负载均衡软件对比(LVS+Nginx+HAproxy)
    nginx 提示the "ssl" directive is deprecated, use the "listen ... ssl" directive instead
    centos安装nginx并配置SSL证书
    hadoop创建目录文件失败
    The server time zone value 'EDT' is unrecognized or represents more than one time zone.
    脚本启动SpringBoot(jar)
    centos做免密登录
    数据库远程连接配置
    Bash 快捷键
    TCP三次握手四次断开
  • 原文地址:https://www.cnblogs.com/zhouxin/p/3418239.html
Copyright © 2011-2022 走看看