Opengl繪制我們的小屋(三)紋理繪制


本准備先說光照相關實現,但是發現對那個模型實在看不下去了,於是先繪制紋理。

先看下基本紋理貼上去的顯示效果。具體模型圖請看上篇文章的實現,這篇只講紋理實現。

我們常見的紋理繪制差不多如下,先寫一個紋理坐標,然后是一個頂點坐標,GL.TexCoord2(1.0f,1.0f);GL.Vectex(1.f,1.f,1.f)。先說一下紋理坐標與頂點坐標的對應處理關系,為了好理解,我們只說二維紋理。先看下圖。

我們設置一張16*8的紋理,如上圖,我們設置GL.TexCoord2(1.0f,1.0f)就是在(16,8)位置,超出1的部分,會復制超出部分,如上圖設置GL.TexCoord(2.0,2.0)就會在圖上一共顯示四張圖,同理我們只要紋理的右下部分四分之一,那坐標應該分別是(1,0.5),(0.5,0.5),(0.5,0)(1,0).

在上個模型中,我們可以看到我們有很多的模型需要紋理貼圖,如果采用一般的方法,需要在每個立方體的面上去計算我們相應的紋理坐標,這樣花費時間太大,這樣我們采用opengl里提供的自動生成紋理。首先要指定以什么樣的模式(既什么樣的算法)來生成紋理坐標。可以指定幾種紋理坐標生成模式:GL_OBJECT_LINEAR, GL_EYE_LINEAR, GL_SPHERE_MAP等。

在這里我們只需要采用最容易理解的紋理生成模式。GL_OBJECT_LINEAR,在這種模式下,指定四個參數,p0,p1,p2,p3,對應頂點(x0,y0,z0,w0),生成的紋理坐標為p0*x0+p1*y0+p2*z0+p3*w0。

我們再來看我們的需求

1。要對立方體的各面自動生成紋理。

2。我們貼地面的,要像磚是一塊一塊的,而貼牆時,只需要貼一張。如最上圖所繪,左下角與右上角分別對應的紋理坐標在貼磚是一塊一塊的應該是((0,0),(n,m))《m>0,n>0》,而貼牆時應該對應((0,0),(1,1))。

借用上篇的圖。

第一點,根據我們的p0*x0+p1*y0+p2*z0+p3*w0算法來看,比如貼地面時,也就是垂直於Y軸時,用到的是圖上的(4,5,1,0)這個面。

 想象一下對應關系,紋理的S軸坐標對應是1-0這條線,T軸坐標對應的是1-5這條線,那么對應s軸大致如下[x;0.;0.;0],T軸坐標大致如下[0;0.;y;0].各面按照這樣得到對應的參數。相關代碼如下。

 1         member this.GenTexture(vector:Vector3,ball) = 
 2             GL.Enable(EnableCap.TextureGenS)
 3             GL.Enable(EnableCap.TextureGenT)
 4             GL.TexGen(TextureCoordName.S,TextureGenParameter.TextureGenMode,int TextureGenMode.ObjectLinear)
 5             GL.TexGen(TextureCoordName.T,TextureGenParameter.TextureGenMode,int TextureGenMode.ObjectLinear)
 6             let mutable xa = [|1.f;0.f;0.f;0.f|]
 7             let mutable xy = [|0.f;1.f;0.f;0.f|]
 8             let mutable x,y,z=1.f,1.f,0.f
 9             if ball then z <-0.5f
10             if vector = Vector3.UnitY || vector = -Vector3.UnitY then 
11                 if ball then
12                     x<-1.0f/Vector3.Subtract(v8.[0],v8.[1]).Length
13                     y<-1.0f/Vector3.Subtract(v8.[0],v8.[4]).Length
14                 xa <- [|x;0.f;0.f;z|]
15                 xy <- [|0.f;0.f;y;z|]
16             if vector = Vector3.UnitZ || vector = -Vector3.UnitZ then 
17                 if ball then
18                     x<-1.0f/Vector3.Subtract(v8.[0],v8.[1]).Length
19                     y<-1.0f/Vector3.Subtract(v8.[0],v8.[3]).Length
20                 xa <- [|x;0.f;0.f;z|]
21                 xy <- [|0.f;y;0.f;z|]
22             if vector = Vector3.UnitX || vector = -Vector3.UnitX then 
23                 if ball then                
24                     x<-1.0f/Vector3.Subtract(v8.[0],v8.[4]).Length
25                     y<-1.0f/Vector3.Subtract(v8.[0],v8.[3]).Length
26                 xa <- [|0.f;0.f;x;z|]
27                 xy <- [|0.f;y;0.f;z|]
28             GL.TexGen(TextureCoordName.S,TextureGenParameter.ObjectPlane,xa)
29             GL.TexGen(TextureCoordName.T,TextureGenParameter.ObjectPlane,xy)
View Code

其中ball參數表示貼牆這種一面只帖一張紋理。在ball時,我們可以看到我們的p0,p1,p2,p3,p3=0.5,這是因為我的矩形的畫法所導致的(前看上篇所敘),比如我要生成寬為8的立方體,其中我畫頂點是x=-4,x=4這種畫法,如果不加0.5,那么我的帖圖就會是左下到右上是(-0,5,-0,5),(0.5,0.5)這種。

在opengl是狀態機模式,記的每畫一面打開相應的狀態后,在畫完后,需要關掉,不然會影響下一部分的貼圖。繪制部分的代碼如下。

 1         member this.DrawTexTure(ts:int*int*bool,vector:Vector3,indexs:int []) =
 2             let ind,txtId,ball = ts
 3             if txtId <> 0  then 
 4                 GL.BindTexture(TextureTarget.Texture2D,txtId)
 5                 this.GenTexture(vector,ball)
 6             GL.Normal3(vector)
 7             GL.DrawElements(BeginMode.Triangles,6,DrawElementsType.UnsignedInt,indexs)
 8             GL.Disable(EnableCap.TextureGenS)
 9             GL.Disable(EnableCap.TextureGenT)
10             GL.Disable(EnableCap.TextureGenR)
11             GL.Disable(EnableCap.TextureGenQ)
View Code

最后附上源碼與可執行文件。操作方式和網游一樣,鼠標右鍵按下加鼠標上下左右移動是視角.EDSF行走。

 紋理小室版

下一章節會給大家講到光照的運用。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM