麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁 > 編程 > Delphi > 正文

NeHe的opengl教程delphi版(9)----星星

2019-11-18 18:30:17
字體:
來源:轉載
供稿:網(wǎng)友
{
歡迎進入第九課。到現(xiàn)在為止,您應該很好的理解OpenGL了。
『CKER:如果沒有的話,一定是我翻譯的罪過......』。
( myling補充道:我的罪過更大,呵呵)
您已經(jīng)學會了設置一個OpenGL窗口的每個細節(jié)。
學會在旋轉的物體上貼圖并打上光線以及混色(透明)處理。
這一課應該算是一課中級教程。
您將學到如下的知識:在3D場景中移動位圖,并去除位圖上的黑色象素(使用混色)。
接著為黑白紋理上色,最后您將學會創(chuàng)建豐富的色彩,
并把上過不同色彩的紋理相互混合,得到簡單的動畫效果。
我們在第一課的代碼基礎上進行修改。先在程序源碼的開始處增加幾個變量。
出于清晰起見,我重寫了整段代碼。
}

Var
   h_RC             : HGLRC;            // Rendering Context(著色描述表)。
   h_DC             : HDC;              // Device Context(設備描述表)
   h_Wnd            : HWND;             // 窗口句柄
   h_Instance       : HINST;            // 程序Instance(實例)。
   keys             : Array[0..255] Of Boolean; // 用于鍵盤例程的數(shù)組

   {下列這幾行新加的。
   twinkle和 tp是布爾變量, 表示它們只能設為 TRUE 或 FALSE。
   twinkle用來跟蹤 閃爍 效果是否啟用。
   tp用來檢查 'T'鍵有沒有被按下或松開.
   (按下時 tp=TRUE, 松開時 tp=FALSE).}
   twinkle          : Boolean;          // 閃爍的星星     (新增)
   tp               : Boolean;          // 'T' 按下了么?  (新增)
   {現(xiàn)在我們來創(chuàng)建一個結構。
    結構這詞聽起來有點可怕,但實際上并非如此。(就是delphi的紀錄類型)
    一個結構使用一組簡單類型的數(shù)據(jù) (以及變量等)來表達較大的具有相似性的數(shù)據(jù)組合。
    我們知道我們在保持對星星的跟蹤。
    您可以看到下面的就是 stars;
    每個星星有三個整型的色彩值。一個紅色 (r), 一個綠色 (g), 以及一個藍色 (b).
    此外,每個星星離屏幕中心的距離不同,
    而且可以是以屏幕中心為原點的任意360度中的一個角度。
    dist的浮點數(shù)來保持對距離 的跟蹤.
    angle的浮點數(shù)保持對星星角度值的跟蹤。
    因此我們使用了一組數(shù)據(jù)來描述屏幕上星星的色彩, 距離, 和角度。
    不幸的是我們不止對一個星星進行跟蹤。
    但是無需創(chuàng)建 50 個紅色值、 50 個綠色值、 50 個藍色值、 50 個距離值
    以及 50 個角度值,而只需創(chuàng)建一個數(shù)組star。}
Type
   stars = Record                       // 為星星創(chuàng)建一個結構,結構命名為stars
      r, g, b: integer;                 // 星星的顏色
      dist: GLfloat;                    // 星星距離中心的距離
      angle: GLfloat;                   // 當前星星所處的角度
   End;
Var
   star             : Array[0..49] Of stars;  // 使用 'stars' 結構生成一個包含 50個元素的 'star'數(shù)組

   {接下來我們設置幾個跟蹤變量:
   星星離觀察者的距離變量(zoom),
   我們所見到的星星所處的角度(tilt),
   以及使閃爍的星星繞Z軸自轉的變量spin。
   loop變量用來繪制50顆星星。
   texture[1]用來存放一個黑白紋理。
   如果您需要更多的紋理的話,
   您應該增加texture數(shù)組的大小至您決定采用的紋理個數(shù)。
   }

   zoom             : GLfloat = -15.0;  // 星星離觀察者的距離
   tilt             : GLfloat = 90.0;   // 星星的傾角
   spin             : GLfloat;          // 閃爍星星的自轉
   loop             : GLuint;           // 全局l Loop 變量
   texture          : Array[0..1] Of GLuint; // 存放一個紋理

PRocedure glGenTextures(n: GLsizei; Var textures: GLuint); stdcall; external
   opengl32;

Procedure glBindTexture(target: GLenum; texture: GLuint); stdcall; external
   opengl32;

{
緊接著上面的代碼就是我們用來載入紋理的代碼。
我不打算再詳細的解釋這段代碼。
這跟我們在第六、七、八課中所用的代碼是一模一樣的。
這一次載入的位圖叫做star.bmp。
這里我們使用glGenTextures(1, &texture[0]),
來生成一個紋理。紋理采用線性濾波方式。
}

Function LoadTexture: boolean;          // 載入位圖并轉換成紋理
Var
   Status           : boolean;          // Status 指示器
   TextureImage     : Array[0..1] Of PTAUX_RGBImageRec; // 創(chuàng)建紋理的存儲空間
Begin
   Status := false;
   ZeroMemory(@TextureImage, sizeof(TextureImage)); // 將指針設為 NULL
   TextureImage[0] := LoadBMP('Star.bmp');
   If TextureImage[0] <> Nil Then
      Begin
         Status := TRUE;                // 將 Status 設為 TRUE
         glGenTextures(1, texture[0]);  // 創(chuàng)建紋理
         // 創(chuàng)建 Nearest 濾波貼圖
         glBindTexture(GL_TEXTURE_2D, texture[0]);
         // 生成紋理
         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);  // ( 新增 )
         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);  // ( 新增 )

         glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0].sizeX,
            TextureImage[0].sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE,
            TextureImage[0].data);
      End;
   If assigned(TextureImage[0]) Then    // 紋理是否存在
      If assigned(TextureImage[0].data) Then // 紋理圖像是否存在
         TextureImage[0].data := Nil;   // 釋放紋理圖像占用的內存
   TextureImage[0] := Nil;              // 釋放圖像結構
   result := Status;                    // 返回 Status
End;

{
在glInit()中設置OpenGL的渲染方式。這里不打算使用深度測試,
如果您使用第一課的代碼的話,
請確認是否已經(jīng)去掉了 glDepthFunc(GL_LEQUAL)和 glEnable(GL_DEPTH_TEST)。
否則,您所見到的效果將會一團糟。
這里我們使用了紋理映射,
因此請您確認您已經(jīng)加上了這些第一課中所沒有的代碼。
您會注意到我們通過混色來啟用了紋理映射。
}

Procedure glInit();
Begin
   If (Not LoadTexture) Then            // 調用紋理載入子例程( 新增 )
      exit;                             // 如果未能載入,退出( 新增 )

   glEnable(GL_TEXTURE_2D);             // 啟用紋理映射
   glShadeModel(GL_SMOOTH);             // 啟用陰影平滑
   glClearColor(0.0, 0.0, 0.0, 0.5);    // 黑色背景
   glClearDepth(1.0);                   // 設置深度緩存
   glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // 真正精細的透視修正
   glBlendFunc(GL_SRC_ALPHA, GL_ONE);   // 設置混色函數(shù)取得半透明效果
   glEnable(GL_BLEND);                  // 啟用混色

   {以下是新增的代碼。
   設置了每顆星星的起始角度、距離、和顏色。
   您會注意到修改結構的屬性有多容易。
   全部50顆星星都會被循環(huán)設置。
   要改變star[1]的角度我們所要做的只是star[1].angle=某個數(shù)值;
   就這么簡單!}
   For loop := 0 To 49 Do               // 創(chuàng)建循環(huán)設置全部星星
      Begin
         star[loop].angle := 0.0;       // 所有星星都從零角度開始
         {第loop顆星星離中心的距離是將loop的值除以星星的總顆數(shù),然后乘上5.0。
         基本上這樣使得后一顆星星比前一顆星星離中心更遠一點。
         這樣當loop為50時(最后一顆星星),loop 除以 num正好是1.0。
         之所以要乘以5.0是因為1.0*5.0 就是 5.0。
         『CKER:廢話,廢話!這老外怎么跟孔乙己似的!:)』
         5.0已經(jīng)很接近屏幕邊緣。我不想星星飛出屏幕,5.0是最好的選擇了。
         當然如果如果您將場景設置的更深入屏幕里面的話,
         也許可以使用大于5.0的數(shù)值,但星星看起來就更小一些(都是透視的緣故)。
         您還會注意到每顆星星的顏色都是從0~255之間的一個隨機數(shù)。
         也許您會奇怪為何這里的顏色得取值范圍不是OpenGL通常的0.0~1.0之間。
         這里我們使用的顏色設置函數(shù)是glColor4ub,而不是以前的glColor4f。
         ub意味著參數(shù)是Unsigned Byte型的。
         一個byte的取值范圍是0~255。
         這里使用byte值取隨機整數(shù)似乎要比取一個浮點的隨機數(shù)更容易一些。
         }
         star[loop].dist := (Trunc(loop) / 50) * 5.0; // 計算星星離中心的距離
         star[loop].r := random(256);   // 為star[loop]設置隨機紅色分量
         star[loop].g := random(256);   // 為star[loop]設置隨機紅色分量
         star[loop].b := random(256);   // 為star[loop]設置隨機紅色分量
      End;

End;

{
現(xiàn)在我們轉入glDraw()繪圖代碼。
如果您使用第一課的代碼,刪除舊的DrawGLScene代碼,只需將下面的代碼復制過去就行了。
實際上,第一課的代碼只有兩行,所以沒太多東西要刪掉的。
}

Procedure glDraw();
Begin
   glClear(GL_COLOR_BUFFER_BIT Or GL_DEPTH_BUFFER_BIT); // 清除屏幕和深度緩存

   glBindTexture(GL_TEXTURE_2D, texture[0]); // 選擇紋理
   For loop := 0 To 49 Do               // 循環(huán)設置所有的星星
      Begin
         glLoadIdentity();              // 繪制每顆星星之前,重置模型觀察矩陣
         glTranslatef(0.0, 0.0, zoom);  // 深入屏幕里面 (使用 'zoom'的值)
         glRotatef(tilt, 1.0, 0.0, 0.0); // 傾斜視角(使用 'tilt'的值)
         {
         現(xiàn)在我們來移動星星。
         星星開始時位于屏幕的中心。
         我們要做的第一件事是把場景沿Y軸旋轉。
         如果我們旋轉90度的話,X軸不再是自左至右的了,他將由里向外穿出屏幕。
         為了讓大家更清楚些,舉個例子。假想您站在房子中間。
         再設想您左側的墻上寫著-x,前面的墻上寫著-z,
         右面墻上就是+x咯,您身后的墻上則是+z。
         加入整個房子向右轉90度,但您沒有動,那么前面的墻上將是-x而不再是-z了。
         所有其他的墻也都跟著移動。-z出現(xiàn)在右側,+z出現(xiàn)在左側,+x出現(xiàn)在您背后。
         神經(jīng)錯亂了吧?通過旋轉場景,我們改變了x和z平面的方向。
         第二行代碼沿x軸移動一個正值。
         通常x軸上的正值代表移向了屏幕的右側(也就是通常的x軸的正向),
         但這里由于我們繞y軸旋轉了坐標系,x軸的正向可以是任意方向。
         如果我們轉180度的話,屏幕的左右側就鏡像反向了。
         因此,當我們沿 x軸正向移動時,可能向左,向右,向前或向后。
         }
         glRotatef(star[loop].angle, 0.0, 1.0, 0.0); //旋轉至當前所畫星星的角度
         glTranslatef(star[loop].dist, 0.0, 0.0); // 沿X軸正向移動
         {
         接著的代碼帶點小技巧。
         星星實際上是一個平面的紋理。
         現(xiàn)在您在屏幕中心畫了個平面的四邊形然后貼上紋理,這看起來很不錯。
         一切都如您所想的那樣。但是當您當您沿著y軸轉上個90度的話,
         紋理在屏幕上就只剩右側和左側的兩條邊朝著您。 看起來就是一條細線。
         這不是我們所想要的。我們希望星星永遠正面朝著我們,而不管屏幕如何旋轉或傾斜。
         我們通過在繪制星星之前,抵消對星星所作的任何旋轉來實現(xiàn)這個愿望。
         您可以采用逆序來抵消旋轉。當我們傾斜屏幕時,我們實際上以當前角度旋轉了星星。
         通過逆序,我們又以當前角度"反旋轉"星星。也就是以當前角度的負值來旋轉星星。
         就是說,
         如果我們將星星旋轉了10度的話,又將其旋轉-10度來使星星在那個軸上重新面對屏幕。
         下面的第一行抵消了沿y軸的旋轉。然后,我們還需要抵消掉沿x軸的屏幕傾斜。
         要做到這一點,我們只需要將屏幕再旋轉-tilt傾角。
         在抵消掉x和y軸的旋轉后,星星又完全面對著我們了。
         }
         glRotatef(-star[loop].angle, 0.0, 1.0, 0.0); // 取消當前星星的角度
         glRotatef(-tilt, 1.0, 0.0, 0.0); // 取消屏幕傾斜
         {如果 twinkle 為  TRUE,我們在屏幕上先畫一次不旋轉的星星:
         將星星總數(shù)(num) 減去當前的星星數(shù)(loop)再減去1,
         來提取每顆星星的不同顏色(這么做是因為循環(huán)范圍從0到num-1)。
         舉例來說,結果為10的時候,我們就使用10號星星的顏色。
         這樣相鄰星星的顏色總是不同的。這不是個好法子,但很有效。
         最后一個值是alpha通道分量。這個值越小,這顆星星就越暗。
         由于啟用了twinkle,每顆星星最后會被繪制兩遍。
         程序運行起來會慢一些,這要看您的機器性能如何了。
         但兩遍繪制的星星顏色相互融合,會產生很棒的效果。
         同時由于第一遍的星星沒有旋轉,啟用twinkle后的星星看起來有一種動畫效果。
         (如果您這里看不懂得話,就自己去看程序的運行效果吧。)
         值得注意的是給紋理上色是件很容易的事。
         盡管紋理本身是黑白的,紋理將變成我們在繪制它之前選定的任意顏色。
         此外,同樣值得注意的是我們在這里使用的顏色值是byte型的,
         而不是通常的浮點數(shù)。甚至alpha通道分量也是如此。}

         If (twinkle) Then              // 啟用閃爍效果
            Begin
               // 使用byte型數(shù)值指定一個顏色
               glColor4ub(star[(50 - loop) - 1].r, star[(50 - loop) - 1].g,
                  star[(50 - loop) - 1].b, 255);
               glBegin(GL_QUADS);       // 開始繪制紋理映射過的四邊形
               glTexCoord2f(0.0, 0.0);
               glVertex3f(-1.0, -1.0, 0.0);
               glTexCoord2f(1.0, 0.0);
               glVertex3f(1.0, -1.0, 0.0);
               glTexCoord2f(1.0, 1.0);
               glVertex3f(1.0, 1.0, 0.0);
               glTexCoord2f(0.0, 1.0);
               glVertex3f(-1.0, 1.0, 0.0);
               glEnd();                 // 四邊形繪制結束
            End;

         {
         現(xiàn)在繪制第二遍的星星。
         唯一和前面的代碼不同的是這一遍的星星肯定會被繪制,并且這次的星星繞著z軸旋轉。
         }
         glRotatef(spin, 0.0, 0.0, 1.0); // 繞z軸旋轉星星
         //  使用byte型數(shù)值指定一個顏色
         glColor4ub(star[loop].r, star[loop].g, star[loop].b, 255);
         glBegin(GL_QUADS);             // 開始繪制紋理映射過的四邊形
         glTexCoord2f(0.0, 0.0);
         glVertex3f(-1.0, -1.0, 0.0);
         glTexCoord2f(1.0, 0.0);
         glVertex3f(1.0, -1.0, 0.0);
         glTexCoord2f(1.0, 1.0);
         glVertex3f(1.0, 1.0, 0.0);
         glTexCoord2f(0.0, 1.0);
         glVertex3f(-1.0, 1.0, 0.0);
         glEnd();                       // 四邊形繪制結束

         {以下的代碼代表星星的運動。
         我們增加spin的值來旋轉所有的星星(公轉)。
         然后,將每顆星星的自轉角度增加loop/num。
         這使離中心更遠的星星轉的更快。最后減少每顆星星離屏幕中心的距離。
         這樣看起來,星星們好像被不斷地吸入屏幕的中心。}
         spin := spin + 0.01;           // 星星的公轉
         star[loop].angle := star[loop].angle + Trunc(loop) / 50;  // 改變星星的自轉角度
         star[loop].dist := star[loop].dist - 0.01; // 改變星星離中心的距離

         {接著幾行檢查星星是否已經(jīng)碰到了屏幕中心。
         當星星碰到屏幕中心時,我們?yōu)樗x一個新顏色,然后往外移5個單位,
         這顆星星將踏上它回歸屏幕中心的旅程。}

         If (star[loop].dist < 0.0) Then // 星星到達中心了么
            Begin
               star[loop].dist := star[loop].dist + 5.0; // 往外移5個單位
               star[loop].r := random(256); // 賦一個新紅色分量
               star[loop].g := random(256); // 賦一個新綠色分量
               star[loop].b := random(256); // 賦一個新藍色分量
            End;
      End;
End;

{
 現(xiàn)在我們添加監(jiān)視鍵盤的代碼。
 下移到WinMain()。找到SwapBuffers(hDC)一行。
 我們就在這一行后面增加鍵盤監(jiān)視代碼。
 代碼將檢查T鍵是否已按下。
 如果T鍵按下過,并且又放開了,if塊內的代碼將被執(zhí)行。
 如果twinkle為FALSE,他將變?yōu)門RUE。
 反之亦然。只要T鍵按下, tp就變?yōu)門RUE。
 這樣處理可以防止如果您一直按著T鍵的話,塊內的代碼被反復執(zhí)行。
 }
 If (keys[ord('T')] And Not tp) Then  // 是否T 鍵已按下并且 tp值為 FALSE
    Begin
       tp := TRUE;        // 若是,將tp設為TRUE
       twinkle := Not twinkle; // 翻轉 twinkle的值
    End;
 {
 下面的代碼檢查是否松開了T鍵。
 若是,使 tp=FALSE。
 除非tp的值為FALSE,
 否則按著T鍵時什么也不會發(fā)生。所以這行代碼很重要。
 }
 If (Not keys[Ord('T')]) Then //  T 鍵已松開了么?
    Begin
       tp := FALSE;       // 若是 ,tp為 FALSE
    End;
 {余下的代碼檢查上、下方向鍵,向上翻頁鍵或向下翻頁鍵是否按下。}
 If (keys[VK_UP]) Then    // 上方向鍵按下了么?
    tilt := tilt - 0.5;   // 屏幕向上傾斜
 If (keys[VK_DOWN]) Then  // 下方向鍵按下了么?
    tilt := tilt + 0.5;   // 屏幕向下傾斜
 If (keys[VK_PRIOR]) Then // 向上翻頁鍵按下了么
    zoom := zoom - 0.2;   // 縮小
 If (keys[VK_NEXT]) Then  // 向下翻頁鍵按下了么?
    zoom := zoom + 0.2;   // 放大
 {
 這一課我盡我所能來解釋如何加載一個灰階位圖紋理,
 (使用混色)去掉它的背景色后,再給它上色,最后讓它在3D場景中移動。
 我已經(jīng)向您展示了如何創(chuàng)建漂亮的顏色與動畫效果。
 實現(xiàn)原理是在原始位圖上再重疊一份位圖拷貝。
 到現(xiàn)在為止,只要您很好的理解了我所教您的一切,
 您應該已經(jīng)能夠毫無問題的制作您自己的3D Demo了。
 所有的基礎知識都已包括在內!}

//========myling :

//1-9課已經(jīng)翻譯完了,就象NEHE說的,基本的知識已經(jīng)基本說完了

//我看了下后面的教程,好像是出自其他人之手,如果有好的例子,我會選擇性的繼

//續(xù)貼的,好累,睡一會:)  ,下次見


上一篇:在Delphi中實現(xiàn)圖片的旋轉、縮放

下一篇:NeHe的opengl教程delphi版(8)----簡單的透明

發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
學習交流
熱門圖片

新聞熱點

疑難解答

圖片精選

網(wǎng)友關注

主站蜘蛛池模板: 欧美一级黄色片在线观看 | 国产91一区 | 毛片免费看电影 | 精品一区二区久久久久久按摩 | 午夜噜噜噜 | 久久蜜桃精品一区二区三区综合网 | 国产一区二区国产 | 精品一区二区三区网站 | 久久av喷吹av高潮av懂色 | 亚洲午夜不卡 | 91精品国产91久久久久久 | 国产91精品久久久久久久 | 久草视频在线资源 | 国产高潮失禁喷水爽到抽搐视频 | www.54271.com| 久久艹国产精品 | 爱看久久 | 婷婷亚洲一区二区三区 | 欧美精品黄色 | av电影在线观看网址 | 亚洲精品xxx | 羞羞视频免费网站 | 黄色片视频在线观看 | 暴力肉体进入hdxxxx0 | 18一20岁一级毛片 | 欧产日产国产精品乱噜噜 | 91精品老司机 | 一级尻逼视频 | 欧美综合成人 | 91短视频网页版 | 久久国产精品网 | 成人羞羞视频在线观看 | 操操插插 | 国产精品自拍av | 亚洲国产高清视频 | 男女隐私免费视频 | jizzzzxxxxx| 欧美在线黄色 | 桥本有菜免费av一区二区三区 | 日本在线免费观看 | 毛片a片|