OpenGL 用三角形模拟生成球面
2013-10-23 15:52
405 查看
在看OpenGL红皮书,看到生成球体这节,讲了很多,总感觉不如自己动手写一些代码来的实在,用OpenGL中三角形模拟球形生成.主要要点,模型视图变换,多边形表面环绕一致性,矩阵堆栈.先贴上代码.
虽然是用F#写的,但是处理全是过程式的,很好理解.
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*半径.
当一个三角形分成几个三角形,也就是三个顶点变成六个顶点,那么生成生成三角形的索引也要重新更新.具体过程用图来说明.
分的越细,球面越光滑,这样只生成了八分之一的球面,后面的如何画了,前面讲了矩阵堆栈的用法,刚好可以用在这样能在我方便生成另外几个面,v.CreatePane(90.f,0.f,1.f,0.f)这个是我们绕Y轴90度后,生成另外的一个面,为了不破坏全局坐标,我们可以在转之前调用PushMatrix记住当前矩阵,画完后再用PopMatrix回到当前矩阵.
看一下程序运行后的效果图.界面上的X,Y,Z指向人眼的位置,左右与上下指旋转方向.最下面指细分的程度,值越大,细分的越厉害.
大家可以把顶点索引变下顺序,然后再来看下效果,也可以把余下的六面全部补起.
虽然是用F#写的,但是处理全是过程式的,很好理解.
#r "F:\3D\1.0\Binaries\OpenTK\Debug\OpenTK.dll" #r "F:\3D\1.0\Binaries\OpenTK\Debug\OpenTK.GLControl.dll" open System open System.Collections.Generic open System.Windows.Forms open System.Threading open System.Drawing open System.Drawing.Imaging open OpenTK open OpenTK.Graphics open OpenTK.Graphics.OpenGL type loopForm() as form= inherit Form() let mutable x = 5.f let mutable y = 5.f let mutable z = 5.f let offest = 1.f let glControl = new OpenTK.GLControl() let textX= new TextBox() let textY= new TextBox() let textZ= new TextBox() let textLR = new TextBox() let textUD= new TextBox() let textInfo = new TextBox() let labelX= new Label() let labelY= new Label() let labelZ= new Label() let labelLR = new Label() let labelUD= new Label() let mutable first = 0 let mutable buffer = 0 let list = 0 let scale = 3.f do form.SuspendLayout() glControl.Location <- new Point(10,40) glControl.Size <- new Size(400,300) glControl.BackColor <- Color.Red glControl.Resize.Add(form.resize) glControl.Paint.Add(form.paint) form.MouseWheel.Add(form.MouseDown) form.ClientSize <- new Size(600,400) form.Text <- "opengl" form.StartPosition <- FormStartPosition.Manual form.Location <- new Point(1200,600) form.Controls.Add(glControl) form.ResumeLayout(false) labelX.Location <- new Point(420,40) labelY.Location <- new Point(420,70) labelZ.Location <- new Point(420,100) labelLR.Location <- new Point(420,130) labelUD.Location <- new Point(420,160) labelX.Text <- "X:" labelY.Text <- "Y:" labelZ.Text <- "Z:" labelLR.Text <- "水平:" labelUD.Text <-"上下:" textX.Location <- new Point(460,40) textY.Location <- new Point(460,70) textZ.Location <- new Point(460,100) textLR.Location <- new Point(460,130) textUD.Location <- new Point(460,160) textInfo.Location <- new Point(420,190) textInfo.Width <- 140 form.Controls.Add(textX) form.Controls.Add(textY) form.Controls.Add(textZ) form.Controls.Add(textLR) form.Controls.Add(textUD) form.Controls.Add(labelX) form.Controls.Add(labelY) form.Controls.Add(labelZ) form.Controls.Add(labelLR) form.Controls.Add(labelUD) form.Controls.Add(textInfo) //#endregion override v.OnLoad e = base.OnLoad e GL.ClearColor Color.MidnightBlue Application.Idle.Add(v.AIdle) v.ShowUI textX.TextChanged.Add(form.TextChange) textY.TextChanged.Add(form.TextChange) textZ.TextChanged.Add(form.TextChange) textLR.TextChanged.Add(form.TextChange) textUD.TextChanged.Add(form.TextChange) //踢除正反面 //GL.Enable EnableCap.CullFace //GL.CullFace CullFaceMode.Back //指定正反面 GL.FrontFace FrontFaceDirection.Ccw //设置材料面填充模式 GL.PolygonMode(MaterialFace.Front,PolygonMode.Fill) GL.PolygonMode(MaterialFace.Back,PolygonMode.Line) //启用数组功能. GL.EnableClientState(ArrayCap.VertexArray) //GL.EnableClientState(ArrayCap.ColorArray) GL.EnableClientState(ArrayCap.IndexArray) //#region "" member v.resize (e:EventArgs) = GL.Viewport(0,0,glControl.ClientSize.Width,glControl.ClientSize.Height) let aspect = float32 glControl.ClientSize.Width /float32 glControl.ClientSize.Height let mutable projection = Matrix4.CreatePerspectiveFieldOfView(MathHelper.PiOver4,aspect,0.1f,64.f) GL.MatrixMode MatrixMode.Projection GL.LoadMatrix(&projection) member v.paint (e:PaintEventArgs) = v.Render() member v.AIdle (e:EventArgs) = while (glControl.IsIdle) do v.Render() member v.TextChange (e:EventArgs) = x <- v.UIValue(textX) y <- v.UIValue(textY) z <- v.UIValue(textZ) member v.MouseDown(e:MouseEventArgs) = match v.ActiveControl with | :? TextBox as t1 -> let mutable t = v.UIValue(t1) t <- t + float32 e.Delta * offest * 0.01f t1.Text <- t.ToString() | _ -> v.Text <- v.ActiveControl.Text let state =float32 e.Delta * offest * 0.01f x<- x+state y<- y + state z <- z + state v.ShowUI member x.UIValue with get (text:TextBox) = let mutable value = 0.f if System.Single.TryParse(text.Text,&value) then value <- value value and set (text:TextBox) (value:float32) = text.Text<- value.ToString() member v.ShowUI = textX.Text <- x.ToString() textY.Text <- y.ToString() textZ.Text <- z.ToString() textLR.Text <- v.UIValue(textLR).ToString() textUD.Text <- v.UIValue(textUD).ToString() member v.Normal (c:Vector3) = c.Normalize() c * scale member v.Subdivide (v1:Vector3,v2:Vector3,v3:Vector3) = let vs = Array.create 6 Vector3.Zero vs.[0] <- v1 vs.[1] <- v.Normal( Vector3.Lerp(v1,v2,0.5f)) vs.[2] <- v.Normal( Vector3.Lerp(v3,v1,0.5f)) vs.[3] <- v2 vs.[4] <- v.Normal( Vector3.Lerp(v2,v3,0.5f)) vs.[5] <- v3 let is = Array.create 12 0 is.[0] <- 0 is.[1] <- 1 is.[2] <- 2 is.[3] <- 2 is.[4] <- 1 is.[5] <- 4 is.[6] <- 4 is.[7] <- 1 is.[8] <- 3 is.[9] <- 2 is.[10] <-4 is.[11] <- 5 (vs,is) //#endregion member v.CreatePane (angle:float32,x,y,z) = GL.PushMatrix() GL.Color3(Color.Green) GL.Rotate(angle,x,y,z) let mutable vv = [|Vector3.UnitY*scale;Vector3.UnitZ*scale;Vector3.UnitX*scale|] let mutable iv = [|0;1;2|] //let show array = printfn "%A" array let mutable t =int (v.UIValue(textInfo)) if t > 6 then t <- 6 elif t < 0 then t <- 0 for j in 0 .. t do let mutable av = Array.create 0 Vector3.Zero let mutable ev = Array.create 0 0 for i in 0 .. 3 .. iv.Length - 1 do let (vvv,iiv) = v.Subdivide(vv.[iv.[i]],vv.[iv.[i+1]],vv.[iv.[i+2]]) let length = av.Length av <- Array.append av vvv let map = iiv |> Array.map (fun p -> p + length) ev <- Array.append ev map vv <- av iv <- ev //show vv //show iv GL.VertexPointer(3,VertexPointerType.Float,0,vv) GL.DrawElements(BeginMode.Triangles,iv.Length,DrawElementsType.UnsignedInt,iv) GL.PopMatrix() member v.Render = let mutable lookat = Matrix4.LookAt(new Vector3(x,y,z),Vector3.Zero,Vector3.UnitY) GL.MatrixMode(MatrixMode.Modelview) GL.LoadMatrix(&lookat) GL.Rotate(v.UIValue(textLR),0.f,1.f,0.f) GL.Rotate(v.UIValue(textUD),1.f,0.f,0.f) GL.Clear(ClearBufferMask.ColorBufferBit ||| ClearBufferMask.DepthBufferBit) GL.Color3(Color.Green) v.CreatePane(0.f,0.f,1.f,0.f) v.CreatePane(90.f,0.f,1.f,0.f) //v.CreatePane(180.f,0.f,1.f,0.f) glControl.SwapBuffers() ignore let t = new loopForm() 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*半径.
当一个三角形分成几个三角形,也就是三个顶点变成六个顶点,那么生成生成三角形的索引也要重新更新.具体过程用图来说明.
分的越细,球面越光滑,这样只生成了八分之一的球面,后面的如何画了,前面讲了矩阵堆栈的用法,刚好可以用在这样能在我方便生成另外几个面,v.CreatePane(90.f,0.f,1.f,0.f)这个是我们绕Y轴90度后,生成另外的一个面,为了不破坏全局坐标,我们可以在转之前调用PushMatrix记住当前矩阵,画完后再用PopMatrix回到当前矩阵.
看一下程序运行后的效果图.界面上的X,Y,Z指向人眼的位置,左右与上下指旋转方向.最下面指细分的程度,值越大,细分的越厉害.
大家可以把顶点索引变下顺序,然后再来看下效果,也可以把余下的六面全部补起.
相关文章推荐
- 德罗内三角形剖分生成以及opengl显示
- android opengl 画三角形
- [OpenGL]创建一个三角形
- JavaScript模拟生成二维数组及多维数组
- qt opengl lesson3 给三角形和正方形上色
- OpenGL 绘制一个三角形带(Triangle Strip)
- css样式生成三角形或圆形
- OpenGL画四个三角形组成四面体,并进行旋转
- 基于Qt的OpenGL编程(3.x以上GLSL可编程管线版)---(二)你好,三角形_QOpenGLExtraFunctions版
- NEHE的OPENGL中文教程 第34课 从高度图生成地形
- 简析OpenGL对光线的软件模拟
- 为django平台生成模拟用户,建立用户组,并将用户加入组
- [OpenGL]纹理坐标的自动生成glTexGen
- Android OpenGL入门示例:绘制三角形和正方形 (附完整源码)
- OpenGL编程指南-环境搭建,渲染三角形
- 使用Python模拟伪随机数生成原理
- OpenGL之自动纹理坐标生成
- OpenGL程序:绘制正方形和三角形
- [openGL][初识]画绿色三角形
- opengl生成线框山地