这个系列我想用来运用opengl红皮书的前八章节的内容,来打造一个室内小屋.

这一章主要是定义几个基本的结构.并给出球体与立方体的画法,先让我们来定义一些基本的结构.一个是包含点,法向量,纹理贴图向量,二是矩形与圆形的父类,包含一些基本公有的处理.

     type T2N3V3 =
struct
val mutable TexCoord : Vector2
val mutable Normal : Vector3
val mutable Position : Vector3
new(v,n,p) = {TexCoord = v;Normal = n;Position = p}
end
[<AbstractClass>]
type Shape() =
let mutable bCreate = false
let mutable vi =
let mutable ei =
let mutable count =
member this.vboID with get() = vi and set value = vi <- value
member this.eboID with get() = ei and set value = ei <- value
member this.TriangelCount with get() = count and set value = count <- value
member this.IsCreate with get() = bCreate and set value = bCreate <- value
abstract Draw : unit -> unit
abstract Init : unit -> unit
member this.InitQ : unit -> unit =fun () -> ()
然后是球体的画法,相关具体过程如上篇,先贴上代码,我会对其中一些做些说明.
     type Sphere(radius:float32,level:int) =
inherit Shape()
let mutable rad,lev = radius,level
let RightLevel =
if lev < then lev <-
elif lev > then lev <-
override this.Draw() =
if this.IsCreate<>true then this.Init()
GL.BindBuffer(BufferTarget.ArrayBuffer,this.vboID)
GL.BindBuffer(BufferTarget.ElementArrayBuffer,this.eboID)
GL.InterleavedArrays(InterleavedArrayFormat.T2fN3fV3f,,IntPtr.Zero)
GL.DrawElements(BeginMode.Triangles,this.TriangelCount,DrawElementsType.UnsignedInt,IntPtr.Zero)
override this.Init() =
let alls = Array.create (new T2N3V3())
alls.[] <- new T2N3V3(new Vector2( 0.0f, 0.0f ), Vector3.UnitX, Vector3.UnitX * rad )
alls.[] <- new T2N3V3(new Vector2( 0.0f, 0.0f ), Vector3.UnitY, Vector3.UnitY * rad )
alls.[] <- new T2N3V3(new Vector2( 0.0f, 0.0f ), Vector3.UnitZ, Vector3.UnitZ * rad )
alls.[] <- new T2N3V3(new Vector2( 0.0f, 0.0f ), -Vector3.UnitX, -Vector3.UnitX * rad )
alls.[] <- new T2N3V3(new Vector2( 0.0f, 0.0f ), -Vector3.UnitY, -Vector3.UnitY * rad )
alls.[] <- new T2N3V3(new Vector2( 0.0f, 0.0f ), -Vector3.UnitZ, -Vector3.UnitZ * rad )
let is = [|
;;
;;
;;
;;
;;
;;
;;
;;
|]
let (vvv:T2N3V3 []),(iv: int[]) = this.Sub (alls,is)
let mutable vID,eID = ,
//let mutable tv,vv,pv = vvv |> Array.map (fun v -> v.TexCoord,v.Normal,v.Position) |> Array.unzip3
GL.GenBuffers(,&vID)
GL.BindBuffer(BufferTarget.ArrayBuffer,vID)
GL.BufferData(BufferTarget.ArrayBuffer,IntPtr ( * * vvv.Length),vvv,BufferUsageHint.StaticDraw) GL.GenBuffers(,&eID)
GL.BindBuffer(BufferTarget.ElementArrayBuffer,eID)
GL.BufferData(BufferTarget.ElementArrayBuffer,IntPtr ( * iv.Length),iv,BufferUsageHint.StaticDraw) this.vboID <- vID
this.eboID <- eID
this.TriangelCount <- iv.Length
this.IsCreate <- true
()
member v.GetMidValue (first:T2N3V3,second:T2N3V3) =
let midN = Vector3.Lerp(first.Position,second.Position,0.5f) |> Vector3.Normalize
let midP = midN *(float32 rad)
let midT = Vector2.Lerp(first.TexCoord,second.TexCoord,0.5f) |> Vector2.Normalize
let result = new T2N3V3(midT,midN,midP)
result
member v.Subdivide (v1:T2N3V3,v2:T2N3V3,v3:T2N3V3) =
let vs = Array.create (new T2N3V3())
vs.[] <- v1
vs.[] <- v.GetMidValue(v1,v2)
vs.[] <- v.GetMidValue(v3,v1)
vs.[] <- v2
vs.[] <- v.GetMidValue(v2,v3)
vs.[] <- v3
let is = Array.create
is.[] <-
is.[] <-
is.[] <-
is.[] <-
is.[] <-
is.[] <-
is.[] <-
is.[] <-
is.[] <-
is.[] <-
is.[] <-
is.[] <-
(vs,is)
member this.Sub(alls:T2N3V3 [],is:int []) =
//let mutable tv,vv,pv = alls |> Array.map (fun v -> v.TexCoord,v.Normal,v.Position) |> Array.unzip3
let mutable allv = alls
let mutable iv = is
let show array = printfn "%A" array
for j in .. lev do
let mutable av = Array.create (new T2N3V3())
let mutable ev = Array.create
printfn "%i" allv.Length
printfn "%i" iv.Length
for i in .. .. iv.Length - do
let (vvv,iiv) = this.Subdivide(allv.[iv.[i]],allv.[iv.[i+]],allv.[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
allv <- av
iv <- ev
allv |> Array.map (fun p -> p.Position) |> show
show iv
allv,iv
初始化需要的二个参数,分别代表球的大小(radius),与画的细分程度(level).其中相关如何绘制球体代码在上文有讲,相当于有是把一个分别位于x,y,z各(+radius,-radius)这六个点,组成的一个八个三角形,索引点的位置如Init里的is代表的3(每个三角形)*8(8个面).对其中每个三角形一变4,level表示4的level加一次方.

GL.InterleavedArrays(InterleavedArrayFormat.T2fN3fV3f,0,IntPtr.Zero)其中的T2fN3fV3f对应于我们的数据结构T2N3V3,这个函数分别相当于指定GL.TexCoordPointer,GL.NormalPointer,GL.VertexPointer(还会打开相应状态),会自动给我们处理好,我们也可以只指定顶点,如下GL.VertexPointer(3,VertexPointerType.Float,4*8,IntPtr (4*8-4*5)),这些数据之间的间隔对应与我们前面写入的GL.BufferData(BufferTarget.ArrayBuffer,IntPtr (4 * 8 * vvv.Length),vvv,BufferUsageHint.StaticDraw)其中vvv是T2N3V3的结构.

基本的GL.BindBuffer的对应的三个处理就不细说了,在Draw里,BindBuffer是指定我们当前格式数据在存储位置,然后分别调用InterleavedArrays设定各顶点的状态,然后是调用DrawElements对应上面的GL.BindBuffer(BufferTarget.ElementArrayBuffer,this.eboID)处理.

然后是立方体的绘制,其中立方体的绘制用的方法看起来会容易理解.如下

     type Cube(width:float32,height:float32,length:float32,index:int) =
inherit Shape()
let mutable id = index
let xl,yl,zl =width/.f,height/.f,length/.f
let mutable color = Color.White
let v8 = [|
new Vector3(xl,yl,zl)
new Vector3(-xl,yl,zl)
new Vector3(-xl,-yl,zl)
new Vector3(xl,-yl,zl)
new Vector3(xl,yl,-zl)
new Vector3(-xl,yl,-zl)
new Vector3(-xl,-yl,-zl)
new Vector3(xl,-yl,-zl)
|]
new(x,y,z) =
let rnd = System.Random().Next()
printfn "%i" rnd
Cube(x,y,z,-)
override this.Draw() =
if this.IsCreate<>true then this.Init()
GL.EnableClientState(ArrayCap.VertexArray)
GL.EnableClientState(ArrayCap.NormalArray)
GL.BindBuffer(BufferTarget.ArrayBuffer,this.vboID)
GL.VertexPointer(,VertexPointerType.Float,,IntPtr.Zero)
GL.PushMatrix()
if id >= && id < then
GL.Translate(v8.[id])
GL.Color3(this.Color:Color)
GL.Normal3(Vector3.UnitZ)
GL.DrawElements(BeginMode.Triangles,,DrawElementsType.UnsignedInt,[|;;;;;|])
//GL.Color3(Color.Black)
GL.Normal3(Vector3.UnitY)
GL.DrawElements(BeginMode.Triangles,,DrawElementsType.UnsignedInt,[|;;;;;|])
//GL.Color3(Color.Red)
GL.Normal3(Vector3.UnitX)
GL.DrawElements(BeginMode.Triangles,,DrawElementsType.UnsignedInt,[|;;;;;|])
//GL.Color3(Color.Green)
GL.Normal3(-Vector3.UnitY)
GL.DrawElements(BeginMode.Triangles,,DrawElementsType.UnsignedInt,[|;;;;;|])
//GL.Color3(Color.Blue)
GL.Normal3(-Vector3.UnitX)
GL.DrawElements(BeginMode.Triangles,,DrawElementsType.UnsignedInt,[|;;;;;|])
//GL.Color3(Color.DodgerBlue)
GL.Normal3(-Vector3.UnitZ)
GL.DrawElements(BeginMode.Triangles,,DrawElementsType.UnsignedInt,[|;;;;;|])
GL.PopMatrix()
override this.Init() =
let mutable vID =
GL.GenBuffers(,&vID)
GL.BindBuffer(BufferTarget.ArrayBuffer,vID)
GL.BufferData(BufferTarget.ArrayBuffer,IntPtr ( * * v8.Length),v8,BufferUsageHint.StaticDraw)
this.vboID <- vID
this.IsCreate <- true
let rnd = System.Random(this.GetHashCode())
this.Color <- Color.FromArgb(rnd.Next(,),rnd.Next(,),rnd.Next(,))
()
member this.Index with get() = id and set value = id <-value
member this.Color with get() = color and set value = color <- value

上图中的V8分别对应其中的0-7个顶点,GL.DrawElements后面的0;1;2;0;2;3分别是以三角形的画法来画一个正方形.

立方体的画法主要是确定宽,高,长,我们这样定义,我们站在原点上,面向Z+轴,我们的手展开来表示X轴(对应宽度),而我们的身高表示Y轴(对应高度),和我们面向距离的长远来表示Z轴,(对应长度).绘制也是8个面,和上面一样,也是在缓存中记录顶点,但是不一样的是,顶点索引是在绘制时没有用到顶点索引缓存,主要考虑后面有法向量的处理,还有现在没有加上的纹理贴图的处理.

在这里,我们要特别注意,顶点顺序问题,在opengl,默认正面是逆时针,而我们可以看0;1;2;0;2;3对应图上的顺序.然后大家可能会发现,画立方体的后面5;4;7;5;7;6,这个顺序好像不对,是顺时针的.大家可以想象下,我们在门外看门的逆时针画法与我们在门内看门外顺时针的画法是一样的.所以如果我们要画后面4,5,6,7我们以为的是逆时针是不对的,我们要想象我们在那边来看,然后再画,应该是5,4,7,6这个方向.其中纹理贴图后面会说,和这处理也有类似.

在上面,我们看到我们都没对顶点的颜色来定义,这里没必要,因为后面我们肯定要用到灯光,用到灯光的话,设置的颜色都没用,我们会用到灯光颜色与材质的颜色.纹理贴图也有没对应处理,这里在后面我会根据讲到再来改写相关处理.

下一节,主要是讲第一人称漫游的相关处理.


Opengl绘制我们的小屋(一)球体,立方体绘制的更多相关文章

  1. Opengl绘制我们的小屋(二)第一人称漫游

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

  2. Opengl绘制我们的小屋(三)纹理绘制

    本准备先说光照相关实现,但是发现对那个模型实在看不下去了,于是先绘制纹理. 先看下基本纹理贴上去的显示效果.具体模型图请看上篇文章的实现,这篇只讲纹理实现. 我们常见的纹理绘制差不多如下,先写一个纹理 ...

  3. Opengl绘制我们的小屋(四)第三人称漫游

    本节内容是在第一人称漫游上完成的,请先了解上文中第一人称漫游的实现. 这一节讲下第三人称漫游是如何实现,第三人称,简单来说,就是在你后面会跟着一台摄像机顺着你拍摄. 先看一下失败的尝试.这个方法是把人 ...

  4. OpenGL绘制自由落体小球

    OpenGL绘制自由落体小球 一.    程序运行的软硬件环境 本次设计在window10系统下进行,运用C++进行编写,在CodeBlocks环境下使用OpenGL进行设计. 所需环境配置分为2部分 ...

  5. OpenGL绘制简单场景,实现旋转缩放平移和灯光效果

    本项目实现了用OpenGL绘制一个简单场景,包括正方体.球体和网格,实现了物体的旋转.缩放.平移和灯光效果.附有项目完整代码.有具体凝视.适合刚開始学习的人熟悉opengl使用. 开发情况 开发环境V ...

  6. [Modern OpenGL系列(三)]用OpenGL绘制一个三角形

    本文已同步发表在CSDN:http://blog.csdn.net/wenxin2011/article/details/51347008 在上一篇文章中已经介绍了OpenGL窗口的创建.本文接着说如 ...

  7. opengl绘制正弦曲线

    利用opengl绘制正弦曲线 ,见代码: #include <windows.h> //#include <GLUT/glut.h> #include <GL/glut. ...

  8. OpenGl 绘制一个立方体

    OpenGl 绘制一个立方体 为了绘制六个正方形,我们为每个正方形指定四个顶点,最终我们需要指定6*4=24个顶点.但是我们知道,一个立方体其实总共只有八个顶点,要指定24次,就意味着每个顶点其实重复 ...

  9. OPENGL绘制文字

    OPENGL没有提供直接绘制文字的功能,需要借助于操作系统. 用OPENGL绘制文字比较常见的方法是利用显示列表.创建一系列显示列表,每个字符对应一个列表编号.例如,'A'对应列表编号1000+'A' ...

随机推荐

  1. 【Unity】10.3 创建类人动画角色

    分类:Unity.C#.VS2015 创建日期:2016-05-02 一.简介 Mecanim 动画系统 (Mecanim Animation System) 特别适合使用类人骨架动画.由于类人骨架非 ...

  2. Java 里如何实现线程间通信

    正常情况下,每个子线程完成各自的任务就可以结束了.不过有的时候,我们希望多个线程协同工作来完成某个任务,这时就涉及到了线程间通信了. 本文涉及到的知识点:thread.join(), object.w ...

  3. haproxy 配置https 同时技持443 80端口

    确定haproxy支持https [root@c01 sbin]# ldd haproxy |grep ssl libssl.so.10 => /usr/lib64/libssl.so.10 ( ...

  4. mydqldump 备份数单库 然后还原数据的时候报:ERROR 1881 (HY000) at line 52: Operation not allowed when innodb_forced_recovery > 0.

    修改my.cnf innodb_force_recovery = 1 修改为: innodb_force_recovery = 0

  5. nginx 并发数问题思考:worker_connections,worker_processes与 max clients

    我相信,很多人都跟我一样,看书都不会太细致也不太认真思考,感觉书中讲的东西都应该是对的,最近读书时我发现以前认为理所当然的东西事实上压根都没有弄明白,最终的结果是,书是别人的,书中的知识也是别人的. ...

  6. vim学习笔记(10):vim命令大全

    进入vim的命令: vim filename :打开或新建文件,并将光标置于第一行首 vim +n filename :打开文件,并将光标置于第n行首 vim + filename :打开文件,并将光 ...

  7. u3d中的坐标系

    任何子级游戏对象 (Child GameObject) 的检视器 (Inspector) 中的变换 (Transform) 值都会相对于父级 (Parent) 的变换 (Transform) 值而显示 ...

  8. CentOS下使用crontab+mysqldump实现定时自动备份数据库

    一 : 为什么要进行数据库的备份? 最主要的原因:尽可能地减少损失,包括时间上.精神上和金钱上的损失.很多人都不注意备份数据,以致在发生问题后丢失大量的重要数据.要知道,在地球上网是很危险的,即使做好 ...

  9. sql2008修改数据库文件名称

    例如我们有数据库a,需修改成b,包括文件名称也修改 1.备份数据a 选择数据库->右键->任务->备份,备份出a.bak 2.右键->任务->还原->数据库,跳出“ ...

  10. visual studio 2005提示脚本错误 /VC/VCWizards/2052/Common.js

    今天在做OCX添加接口的时候,莫名其妙的遇到visual studio 2005提示脚本错误,/VC/VCWizards/2052/Common.js. 网上找了很多资料,多数介绍修改注册表“vs20 ...