OpenGL 用三角形模拟生成球面
在看OpenGL红皮书,看到生成球体这节,讲了很多,总感觉不如自己动手写一些代码来的实在,用OpenGL中三角形模拟球形生成.主要要点,模型视图变换,多边形表面环绕一致性,矩阵堆栈.先贴上代码.
虽然是用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 = .f
let mutable y = .f
let mutable z = .f
let offest = .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 =
let mutable buffer =
let list =
let scale = .f
do
form.SuspendLayout()
glControl.Location <- new Point(,)
glControl.Size <- new Size(,)
glControl.BackColor <- Color.Red
glControl.Resize.Add(form.resize)
glControl.Paint.Add(form.paint)
form.MouseWheel.Add(form.MouseDown)
form.ClientSize <- new Size(,)
form.Text <- "opengl"
form.StartPosition <- FormStartPosition.Manual
form.Location <- new Point(,)
form.Controls.Add(glControl)
form.ResumeLayout(false)
labelX.Location <- new Point(,)
labelY.Location <- new Point(,)
labelZ.Location <- new Point(,)
labelLR.Location <- new Point(,)
labelUD.Location <- new Point(,)
labelX.Text <- "X:"
labelY.Text <- "Y:"
labelZ.Text <- "Z:"
labelLR.Text <- "水平:"
labelUD.Text <-"上下:"
textX.Location <- new Point(,)
textY.Location <- new Point(,)
textZ.Location <- new Point(,)
textLR.Location <- new Point(,)
textUD.Location <- new Point(,)
textInfo.Location <- new Point(,)
textInfo.Width <-
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(,,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,.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 = .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 Vector3.Zero
vs.[] <- v1
vs.[] <- v.Normal( Vector3.Lerp(v1,v2,0.5f))
vs.[] <- v.Normal( Vector3.Lerp(v3,v1,0.5f))
vs.[] <- v2
vs.[] <- v.Normal( Vector3.Lerp(v2,v3,0.5f))
vs.[] <- v3
let is = Array.create
is.[] <-
is.[] <-
is.[] <-
is.[] <-
is.[] <-
is.[] <-
is.[] <-
is.[] <-
is.[] <-
is.[] <-
is.[] <-
is.[] <-
(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 = [|;;|]
//let show array = printfn "%A" array
let mutable t =int (v.UIValue(textInfo))
if t > then
t <-
elif t < then
t <-
for j in .. t do
let mutable av = Array.create Vector3.Zero
let mutable ev = Array.create
for i in .. .. iv.Length - do
let (vvv,iiv) = v.Subdivide(vv.[iv.[i]],vv.[iv.[i+]],vv.[iv.[i+]])
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(,VertexPointerType.Float,,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),.f,.f,.f)
GL.Rotate(v.UIValue(textUD),.f,.f,.f)
GL.Clear(ClearBufferMask.ColorBufferBit ||| ClearBufferMask.DepthBufferBit)
GL.Color3(Color.Green)
v.CreatePane(.f,.f,.f,.f)
v.CreatePane(.f,.f,.f,.f)
//v.CreatePane(180.f,0.f,1.f,0.f)
glControl.SwapBuffers()
ignore
let t = new loopForm()
t.Show()
首先我们设定逆时针方向为正方向,分别设定正面为画布填充,反面为线填充,这样我们就能很容易知道我们生成的三角形倒底是不是正确生成的我们要的面向.
然后分别取用顶点数组和顶点数组索引功能.毕竟后面的点多,一个一个去组装没这个脑力,还没性能.
如何用三角开来模拟生成球面,方法肯定很多种,这里我们可以想象下,在坐标轴的原点就是球的原点,半径为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 用三角形模拟生成球面的更多相关文章
- linux平台模拟生成CAN设备
前言 使用socketCan的过程中有时候没有can接口设备,但是需要测试一下can接口程序是否有问题, 此时需要系统模拟生成can设备,本文介绍linux平台模拟生成CAN设备的方法. 实现步骤 1 ...
- linux 模拟生成 CAN 设备
/************************************************************************************** * linux 模拟生成 ...
- Perl+OpenGL 重绘inkscape生成的svg矢量图
Perl+OpenGL 重绘inkscape生成的svg矢量图 还不够完善,先挖个坑,后面慢慢填 Code: [全选] [展开/收缩] [Download] (Untitled.pl) =info A ...
- pandas 模拟生成数据集的快速方法
快速生成一个DataFrame的方法: #模拟生成数据集的方法 import pandas as pd import numpy as np boolean=[True,False] gender=[ ...
- OpenGL(3)-三角形
写在前面 从这节开始,会接触到很多基本概念,原书我也是读了很多遍,一遍一遍去理解其中的意思,以及他们之间的关系. 概念 顶点数组对象:VAO 顶点缓冲对象:VBO 索引缓冲对象:EBO|IBO Ope ...
- opengl绘制三角形
顶点数组对象:Vertex Array Object,VAO 顶点缓冲对象:Vertex Buffer Object,VBO 索引缓冲对象:Element Buffer Object,EBO或Inde ...
- 1.opengl绘制三角形
顶点数组对象:Vertex Array Object,VAO,用于存储顶点状态配置信息,每当界面刷新时,则通过VAO进行绘制. 顶点缓冲对象:Vertex Buffer Object,VBO,通过VB ...
- (4)用opengl读入off文件生成可执行文件把模型显示出来(未完待续)
·找了好几个程序,好像都达不到我的要求,去教程里看看吧! 在往上抛出了这问题,好几天才有人回答,我已经找到程序了 正好的他的分析对我分解程序很有用 这是一个难度比较高的 首先你要分析.off文件结构, ...
- 【OpenGL】三角形
步骤 初始化顶点数组对象VAO 分配顶点缓冲对象VBO 将顶点数据载入缓冲对象中 glBufferData() 链接顶点属性 glVertexAttribPointer(指定了顶点着色器的变量与我们存 ...
随机推荐
- [svc]nginx优化
nginx的25条优化
- .net4.5使用async和await异步编程实例
关于异步编程的简单理解: 在.NET4.5中新增了异步编程的新特性async和await,使得异步编程更为简单.通过特性可以将这项复杂的工作交给编译器来完成了.之前传统的方式来实现异步编程较为复杂,这 ...
- 编译libevent源代码(Windows)
学习笔记,只是记录本次成功用libevent源代码进行编译.环境为MinGW+VS2008+Msys. 0.下载libevent库 http://libevent.org/ 下载stable稳定版的库 ...
- lua的模块加载require
加载指定的模块.首先函数会在 package.loaded 这个表中查看是否已经加载 了 modname 这个模块.如果是,那么 require 会返回保存在 package.loaded[modna ...
- 【架构】MVC模式
架构模式 如何设计一个程序的结构,这是一门专门的学问,叫做"架构模式"(architectural pattern),属于编程的方法论. MVC模式就是架构模式的一种,它不仅适用于 ...
- SAP NetWeaver BW 7.3介绍
(摘自SAP 官方 EIM300 SAP NetWeaver BW 7.3 特色功能.前景展望与路线图)
- FIDDLER的使用方法及技巧总结(连载一)FIDDLER快速入门及使用场景
FIDDLER的使用方法及技巧总结 一.FIDDLER快速入门及使用场景 Fiddler的官方网站:http://www.fiddler2.com Fiddler的官方帮助:http://docs.t ...
- C#对DataTable里数据筛选排序的方法
在日常开发过程中,有一个DataTable集合,里面有很多字段,现在要求针对某一列进行排序,如果该列为数字的话,进行ASC即可实现,但是该字段类型为string,此时排序就有点不正确了 protect ...
- Django项目关闭debug模式后,静态文件无法加载的解决办法
开启内置服务器,由于项目中local_settings.py文件中的DEBUG=True,进行开发和调试一直没什么问题. 但是现在需要编写404,500等出错页面,在debug模式下出了错都会出现报错 ...
- Docker、Dockerfile、Docker镜像、容器这些都是什么鸟?
老生常谈,再再再……普及一下: Docker:最早是dotCloud公司出品的一套容器管理工具,但后来Docker慢慢火起来了,连公司名字都从dotCloud改成Docker. Dockerfile: ...