zoukankan      html  css  js  c++  java
  • OpenGL 用三角形模拟生成球面

    在看OpenGL红皮书,看到生成球体这节,讲了很多,总感觉不如自己动手写一些代码来的实在,用OpenGL中三角形模拟球形生成.主要要点,模型视图变换,多边形表面环绕一致性,矩阵堆栈.先贴上代码.

    虽然是用F#写的,但是处理全是过程式的,很好理解.

      1 #r "F:3D1.0BinariesOpenTKDebugOpenTK.dll"
      2 #r "F:3D1.0BinariesOpenTKDebugOpenTK.GLControl.dll"
      3 
      4 open System
      5 open System.Collections.Generic
      6 open System.Windows.Forms
      7 open System.Threading
      8 open System.Drawing
      9 open System.Drawing.Imaging
     10 open OpenTK
     11 open OpenTK.Graphics
     12 open OpenTK.Graphics.OpenGL
     13 
     14 type loopForm() as form=
     15     inherit Form()
     16     let mutable x = 5.f
     17     let mutable y = 5.f
     18     let mutable z = 5.f
     19     let offest = 1.f
     20     let glControl = new OpenTK.GLControl()
     21     let textX= new TextBox()
     22     let textY= new TextBox()
     23     let textZ= new TextBox()
     24     let textLR = new TextBox()
     25     let textUD= new TextBox()
     26     let textInfo = new TextBox()
     27     let labelX= new Label()
     28     let labelY= new Label()
     29     let labelZ= new Label()
     30     let labelLR = new Label()
     31     let labelUD= new Label()
     32     let mutable first = 0
     33     let mutable buffer = 0
     34     let list = 0
     35     let scale = 3.f
     36     do
     37         form.SuspendLayout()
     38         glControl.Location <- new Point(10,40)
     39         glControl.Size <- new Size(400,300)
     40         glControl.BackColor <- Color.Red
     41         glControl.Resize.Add(form.resize)
     42         glControl.Paint.Add(form.paint)
     43         form.MouseWheel.Add(form.MouseDown)
     44         form.ClientSize <- new Size(600,400)
     45         form.Text <- "opengl"
     46         form.StartPosition <- FormStartPosition.Manual
     47         form.Location <- new Point(1200,600)
     48         form.Controls.Add(glControl)
     49         form.ResumeLayout(false)
     50         labelX.Location <- new Point(420,40)
     51         labelY.Location <- new Point(420,70)
     52         labelZ.Location <- new Point(420,100)
     53         labelLR.Location <- new Point(420,130)
     54         labelUD.Location <- new Point(420,160)
     55         labelX.Text <- "X:"
     56         labelY.Text <- "Y:"
     57         labelZ.Text <- "Z:"
     58         labelLR.Text  <- "水平:"
     59         labelUD.Text <-"上下:"
     60         textX.Location <- new Point(460,40)
     61         textY.Location <- new Point(460,70)
     62         textZ.Location <- new Point(460,100)
     63         textLR.Location <- new Point(460,130)
     64         textUD.Location <- new Point(460,160)
     65         textInfo.Location <- new Point(420,190)
     66         textInfo.Width <- 140
     67         form.Controls.Add(textX)
     68         form.Controls.Add(textY)
     69         form.Controls.Add(textZ)
     70         form.Controls.Add(textLR)
     71         form.Controls.Add(textUD)
     72         form.Controls.Add(labelX)
     73         form.Controls.Add(labelY)
     74         form.Controls.Add(labelZ)
     75         form.Controls.Add(labelLR)
     76         form.Controls.Add(labelUD)
     77         form.Controls.Add(textInfo)
     78         //#endregion 
     79     override v.OnLoad e =
     80         base.OnLoad e
     81         GL.ClearColor Color.MidnightBlue
     82         Application.Idle.Add(v.AIdle)
     83         v.ShowUI        
     84         textX.TextChanged.Add(form.TextChange)
     85         textY.TextChanged.Add(form.TextChange)
     86         textZ.TextChanged.Add(form.TextChange)
     87         textLR.TextChanged.Add(form.TextChange)
     88         textUD.TextChanged.Add(form.TextChange)
     89         //踢除正反面
     90         //GL.Enable EnableCap.CullFace
     91         //GL.CullFace CullFaceMode.Back
     92         //指定正反面
     93         GL.FrontFace FrontFaceDirection.Ccw
     94         //设置材料面填充模式
     95         GL.PolygonMode(MaterialFace.Front,PolygonMode.Fill)
     96         GL.PolygonMode(MaterialFace.Back,PolygonMode.Line)
     97         //启用数组功能.
     98         GL.EnableClientState(ArrayCap.VertexArray)
     99         //GL.EnableClientState(ArrayCap.ColorArray)
    100         GL.EnableClientState(ArrayCap.IndexArray)
    101 //#region ""
    102     member v.resize (e:EventArgs) =
    103         GL.Viewport(0,0,glControl.ClientSize.Width,glControl.ClientSize.Height)
    104         let aspect = float32 glControl.ClientSize.Width /float32 glControl.ClientSize.Height
    105         let mutable projection = Matrix4.CreatePerspectiveFieldOfView(MathHelper.PiOver4,aspect,0.1f,64.f)
    106         GL.MatrixMode MatrixMode.Projection
    107         GL.LoadMatrix(&projection)
    108     member v.paint (e:PaintEventArgs) =
    109         v.Render()
    110     member v.AIdle (e:EventArgs) =
    111         while (glControl.IsIdle) do
    112             v.Render()
    113     member v.TextChange (e:EventArgs) =
    114         x <- v.UIValue(textX)
    115         y <- v.UIValue(textY)
    116         z <- v.UIValue(textZ)
    117     member v.MouseDown(e:MouseEventArgs) =
    118         match v.ActiveControl with
    119         | :? TextBox as t1 -> 
    120             let mutable t = v.UIValue(t1)
    121             t <- t + float32 e.Delta * offest * 0.01f
    122             t1.Text <- t.ToString()
    123         | _ -> 
    124             v.Text <- v.ActiveControl.Text
    125             let state =float32 e.Delta * offest * 0.01f
    126             x<- x+state
    127             y<- y + state
    128             z <- z + state
    129         v.ShowUI
    130     member x.UIValue
    131         with get (text:TextBox) = 
    132             let mutable value = 0.f
    133             if System.Single.TryParse(text.Text,&value) then
    134                 value <- value
    135             value
    136         and set (text:TextBox) (value:float32) = text.Text<- value.ToString()
    137     member v.ShowUI =
    138         textX.Text <- x.ToString()
    139         textY.Text <- y.ToString()
    140         textZ.Text <- z.ToString()
    141         textLR.Text <- v.UIValue(textLR).ToString()
    142         textUD.Text <- v.UIValue(textUD).ToString()
    143     member v.Normal (c:Vector3) =
    144         c.Normalize() 
    145         c * scale
    146     member v.Subdivide (v1:Vector3,v2:Vector3,v3:Vector3) =
    147         let vs = Array.create 6 Vector3.Zero
    148         vs.[0] <- v1
    149         vs.[1] <- v.Normal( Vector3.Lerp(v1,v2,0.5f))
    150         vs.[2] <- v.Normal( Vector3.Lerp(v3,v1,0.5f))
    151         vs.[3] <- v2
    152         vs.[4] <- v.Normal( Vector3.Lerp(v2,v3,0.5f))
    153         vs.[5] <- v3
    154         let is = Array.create 12 0
    155         is.[0] <- 0
    156         is.[1] <- 1
    157         is.[2] <- 2
    158         is.[3] <- 2
    159         is.[4] <- 1
    160         is.[5] <- 4
    161         is.[6] <- 4
    162         is.[7] <- 1
    163         is.[8] <- 3
    164         is.[9] <- 2
    165         is.[10] <-4
    166         is.[11] <- 5
    167         (vs,is)
    168 //#endregion     
    169     member v.CreatePane (angle:float32,x,y,z) =
    170         GL.PushMatrix()
    171         GL.Color3(Color.Green)
    172         GL.Rotate(angle,x,y,z)
    173         let mutable vv = [|Vector3.UnitY*scale;Vector3.UnitZ*scale;Vector3.UnitX*scale|]
    174         let mutable iv = [|0;1;2|]
    175         //let show array = printfn "%A" array
    176         let mutable t =int (v.UIValue(textInfo))
    177         if t > 6 then
    178             t <- 6
    179         elif t < 0 then
    180             t <- 0                
    181         for j in 0 .. t do
    182             let mutable av = Array.create 0 Vector3.Zero
    183             let mutable ev = Array.create 0 0
    184             for i in 0 .. 3 .. iv.Length - 1 do
    185                 let (vvv,iiv) = v.Subdivide(vv.[iv.[i]],vv.[iv.[i+1]],vv.[iv.[i+2]])
    186                 let length = av.Length
    187                 av <- Array.append av vvv
    188                 let map = iiv |> Array.map (fun p -> p + length)
    189                 ev <- Array.append ev map
    190             vv <- av
    191             iv <- ev 
    192             //show vv
    193             //show iv
    194         GL.VertexPointer(3,VertexPointerType.Float,0,vv)      
    195         GL.DrawElements(BeginMode.Triangles,iv.Length,DrawElementsType.UnsignedInt,iv)
    196         GL.PopMatrix()    
    197     member v.Render =
    198         let mutable lookat = Matrix4.LookAt(new Vector3(x,y,z),Vector3.Zero,Vector3.UnitY)
    199         GL.MatrixMode(MatrixMode.Modelview)
    200         GL.LoadMatrix(&lookat)        
    201         GL.Rotate(v.UIValue(textLR),0.f,1.f,0.f)
    202         GL.Rotate(v.UIValue(textUD),1.f,0.f,0.f)
    203         GL.Clear(ClearBufferMask.ColorBufferBit ||| ClearBufferMask.DepthBufferBit)
    204         GL.Color3(Color.Green)
    205         v.CreatePane(0.f,0.f,1.f,0.f)
    206         v.CreatePane(90.f,0.f,1.f,0.f)
    207         //v.CreatePane(180.f,0.f,1.f,0.f)
    208         glControl.SwapBuffers()
    209         ignore
    210 let t = new loopForm()
    211 t.Show()   
    View Code

    首先我们设定逆时针方向为正方向,分别设定正面为画布填充,反面为线填充,这样我们就能很容易知道我们生成的三角形倒底是不是正确生成的我们要的面向.

    然后分别取用顶点数组和顶点数组索引功能.毕竟后面的点多,一个一个去组装没这个脑力,还没性能.

    如何用三角开来模拟生成球面,方法肯定很多种,这里我们可以想象下,在坐标轴的原点就是球的原点,半径为1,被X,Y,Z轴分成八个部分,我们找到正右上的那边,与X,Y,Z轴的交点分别为x1(1,0,0),y1(0,1,0),z1(0,0,1).

    然后我们把x1,y1,z1连起来画一个三角形.注意这里就有顺序了,想像一下,三个点的位置,要画正面是用逆时针方向,一算,x1,y1,z1这个方向就是,但是通常为了形象些,我们从y1上开始画,然后是前z1,然后是右x1.如代码是这样

    let mutable vv = [|Vector3.UnitY*scale;Vector3.UnitZ*scale;Vector3.UnitX*scale|]
         let mutable iv = [|0;1;2|]

    然后就是细分这三角形,过程就是这样,一个三角形分成四个.在for j in 0 .. t 这里,t越多,分的就越多,t是0,分一次成四个,t是1,四个再分别分成四个,就是16个.最后总的三角形就是4的t+1次方.

    细分算法,大致如下,已知球面上二点,a1,a2,求在这球二点中间点ax.

    已知球心在中间,得知,三个向量有如下关系,向量ax = (向量a2-向量a1)*0.5 + 向量a1.这样可以算到向量a1,那点ax就是向量a1*半径.

    当一个三角形分成几个三角形,也就是三个顶点变成六个顶点,那么生成生成三角形的索引也要重新更新.具体过程用图来说明.

    image

    分的越细,球面越光滑,这样只生成了八分之一的球面,后面的如何画了,前面讲了矩阵堆栈的用法,刚好可以用在这样能在我方便生成另外几个面,v.CreatePane(90.f,0.f,1.f,0.f)这个是我们绕Y轴90度后,生成另外的一个面,为了不破坏全局坐标,我们可以在转之前调用PushMatrix记住当前矩阵,画完后再用PopMatrix回到当前矩阵.

    看一下程序运行后的效果图.界面上的X,Y,Z指向人眼的位置,左右与上下指旋转方向.最下面指细分的程度,值越大,细分的越厉害.

    效果图

    大家可以把顶点索引变下顺序,然后再来看下效果,也可以把余下的六面全部补起.

  • 相关阅读:
    [转] How to import a large data set using XPO efficiently within a transaction
    [原] XAF 如何启用ListView Top N records 提升用户使用体验
    [XAF] How to improve the application's performance
    [XAF] Simplifying integration of custom controls bound to data from XAF application database
    解决Hyper-v Server更换网卡后上传速度变得非常慢的问题
    在SqlServer中通过SQL语句实现树状查询
    spring boot jpa定义返回类型问题
    linux-1
    HTML5——8form表格
    HTML5——7iframe框架
  • 原文地址:https://www.cnblogs.com/zhouxin/p/3384239.html
Copyright © 2011-2022 走看看