基礎(chǔ)紋理

紋理只是一種能夠應(yīng)用到場景中的三角形上的圖像數(shù)據(jù)瞧剖,它通過經(jīng)過過濾的紋理單元(texel,相當(dāng)于紋理的像素)填充到實心區(qū)域。

基礎(chǔ)紋理

原始圖像數(shù)據(jù)

像素包裝

  • 圖形數(shù)據(jù)在內(nèi)存中很少以緊密包裝的形式存在,為了性能,一副圖像的每一行都應(yīng)該從一個特定字節(jié)對齊地址開始(犧牲了空間)梯找,絕大多數(shù)編譯器會自動把變量和緩沖區(qū)放置在一個針對該架構(gòu)對齊優(yōu)化的地址上
  • Windows中的RMP文件格式的像素數(shù)據(jù)使用4字節(jié)排列;然而Targa(TGA)文件格式則是1個字節(jié)排列的(這樣不會浪費空間)

改變或恢復(fù)像素的儲存方式:

void glPixelStorei(GLenum pname,GLint param);

void glPixelStoref(GLenum pname,GLfloat param);

如圖我們想要改成緊密包裝像素數(shù)據(jù)益涧,應(yīng)該調(diào)用glPixelStorei(GL_UNPACK_ALIGNMENT,1);//GL_UNPACK_ALIGNMENT制定ruhr從數(shù)據(jù)緩沖區(qū)中解包圖像數(shù)據(jù)

像素圖

  • 像素圖在內(nèi)存布局上與位圖非常相似锈锤,但是每個像素都需要一個以上的儲存位來表示。每個像素的附加位允許儲存強度(intensity,有時被陳偉亮度久免,即luminance的值)或者顏色分量值浅辙。
  • 可以使用下面的函數(shù)將顏色緩沖區(qū)的內(nèi)容作為像素圖直接讀取.
void glReadPixels(GLint x,GLint y,GLSizei width,GLSizei height,
GLenum format,GLenum type,const void *pixels);
/*
x,y制定為舉行左下角的窗口坐標(biāo),然后制定矩形的width和height值(像素形式)阎姥。如果顏色緩沖區(qū)儲存的數(shù)據(jù)與我們要求的不同记舆,OpenGL將負(fù)責(zé)進行必要的轉(zhuǎn)換。
*pixels必須是合法的
format制定piels指向的數(shù)據(jù)元素的顏色布局
type解釋參數(shù)*pixels指向的數(shù)據(jù)呼巴,他告訴OpenGL使用緩存區(qū)中的什么數(shù)據(jù)類型來存儲顏色分量
*/

glReadPixels從圖形硬件中復(fù)制數(shù)據(jù)泽腮,通常通過總線傳輸?shù)较到y(tǒng)內(nèi)存

包裝的像素格式

包裝的像素格式將顏色數(shù)據(jù)壓縮到了盡可能少的儲存位中,每個顏色通道的位數(shù)顯示在常量中

對于glReadPixels函數(shù)來說衣赶,讀取操作在雙緩沖區(qū)的渲染環(huán)境下載后臺緩沖區(qū)進行诊赊,在單緩沖區(qū)渲染環(huán)境下則在前臺緩沖區(qū)進行

可以用void glReadBuffer(GLenum mode);改變這些像素操作的源

保存像素

用glWriteTGA函數(shù)來講屏幕圖像保存為一個Targa文件

讀取像素

讀取Targa文件以備OpenGL使用的函數(shù)

載入紋理

有三個OpenGL函數(shù)最經(jīng)常用來從存儲器緩沖區(qū)中載入(比如說,從一個磁盤文件中讀雀椤)紋理數(shù)據(jù):

void glTexImage1D((GLenum target, GLint level, GLenum internalformat,GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type,void* data);
void glTexImage2D((GLenum target, GLint level, GLenum internalformat,GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type,void* data);
void glTexImage3D((GLenum target, GLint level, GLenum internalformat,GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type,void* data)

target 指定目標(biāo)紋理碧磅,這個值必須是GL_TEXTURE_2D。
level 執(zhí)行細(xì)節(jié)級別遵馆。0是最基本的圖像級別鲸郊,n表示第N級貼圖細(xì)化級別。
internalformat 指定紋理中的顏色組件团搞⊙贤可選的值有GL_ALPHA,GL_RGB,GL_RGBA,GL_LUMINANCE, GL_LUMINANCE_ALPHA 等幾種多艇。
width 指定紋理圖像的寬度逻恐,必須是2的n次方。紋理圖片至少要支持64個材質(zhì)元素的寬度
height 指定紋理圖像的高度峻黍,必須是2的m次方复隆。紋理圖片至少要支持64個材質(zhì)元素的高度
border 指定邊框的寬度。必須為0姆涩。
format 像素數(shù)據(jù)的顏色格式, 不需要和internalformatt取值必須相同挽拂。可選的值參考internalformat骨饿。
type 指定像素數(shù)據(jù)的數(shù)據(jù)類型亏栈。可以使用的值有GL_UNSIGNED_BYTE,GL_UNSIGNED_SHORT_5_6_5,GL_UNSIGNED_SHORT_4_4_4_4,GL_UNSIGNED_SHORT_5_5_5_1
最后三個參數(shù)format, type, data和用于把圖像放入顏色緩沖區(qū)的glDrawPixels函數(shù)的對應(yīng)參數(shù)相同

使用顏色緩沖區(qū)

一維和二維紋理也可以從顏色緩沖區(qū)加載數(shù)據(jù)宏赘,我們可以從顏色緩沖區(qū)讀取一幅圖像绒北,并通過下面這兩個函數(shù)將它作為一個新的紋理使用。

void glCopyTexImage1D(  GLenum      target,
    GLint   level,
    GLenum      internalformat,
    GLint   x,
    GLint   y,
    GLsizei     width,
    GLint   border);
void glCopyTexImage2D(  GLenum      target,
    GLint   level,
    GLenum      internalformat,
    GLint   x,
    GLint   y,
    GLsizei     width,
    GLint   border);

更新紋理

替換紋理通常比重新加載一個新紋理快得多察署,用于完成這個任務(wù)的是glTexSubImage()闷游。
glCopyTexSubImage函數(shù)允許從顏色緩沖區(qū)讀取紋理,并插入或替換原來紋理的一部分。
顏色緩沖區(qū)是2D的脐往,不存在一種對應(yīng)方法來講一副2D彩色圖像作為一個3D紋理的來源休吠,但我們可以使用glCopyTexSubImage3D函數(shù),在一個三位問李重使用顏色緩沖區(qū)的數(shù)據(jù)來設(shè)置它的一個紋理單元平面

紋理對象

在紋理之間進行切換或者重新加載不同的紋理圖像開銷很大业簿。紋理對象支持我們一次加載一個以上的紋理狀態(tài)瘤礁,以及在它們之間的快速切換。
void glGenTextures(GLsizei n,GLunit *textures)分配一些紋理對象
void glBindTextures(GLenum n,GLunit texture)綁定一種紋理狀態(tài)
void glDeleteTextures(GLsizei n,GLunit *textures)刪除紋理對象
GLboolean glIsTexture(GLuint texture)對紋理對象名進行測試梅尤,以判斷它們是否有效

紋理應(yīng)用

加載紋理只是在幾何圖形上應(yīng)用紋理的第一部蔚携。最低限度我們必須同時提供紋理坐標(biāo),并設(shè)置紋理坐標(biāo)環(huán)繞模式和紋理過濾克饶。最后酝蜒,我們可以選擇對紋理進行Mip貼圖,以提高紋理貼圖性能和/或視覺質(zhì)量

紋理坐標(biāo)

紋理坐標(biāo)是x和y軸上0到1之間的范圍(注意我們使用的是2D紋理圖片)矾湃。使用紋理坐標(biāo)獲取紋理顏色叫做采樣(Sampling)亡脑。紋理坐標(biāo)起始于(0,0)也就是紋理圖片的左下角,終結(jié)于紋理圖片的右上角(1,1)邀跃。下面的圖片展示了我們是如何把紋理坐標(biāo)映射到三角形上的霉咨。

紋理坐標(biāo)映射

我們?yōu)槿切螠?zhǔn)備了3個紋理坐標(biāo)點。如上圖所示拍屑,我們希望三角形的左下角對應(yīng)紋理的左下角途戒,因此我們把三角左下角的頂點的紋理坐標(biāo)設(shè)置為(0,0);三角形的上頂點對應(yīng)于圖片的中間所以我們把它的紋理坐標(biāo)設(shè)置為(0.5,1.0)僵驰;同理右下方的頂點設(shè)置為(1.0,0)喷斋。我們只要傳遞這三個紋理坐標(biāo)給頂點著色器就行了,接著片段著色器會為每個片段生成紋理坐標(biāo)的插值蒜茴。
紋理坐標(biāo)看起來就像這樣:
GLfloat texCoords[] = {
0.0f, 0.0f, // 左下角
1.0f, 0.0f, // 右下角
0.5f, 1.0f // 頂部位置
};
如圖星爪,一維、二維粉私、三維紋理坐標(biāo)(s顽腾、t、r诺核、q與x抄肖、y、z窖杀、w相類似)(q為縮放因子)


紋理坐標(biāo)

紋理參數(shù)

glTexParameterf(GLenum target,GLenum pname,GLfloat param);
glTexParameteri(GLenum target,GLenum pname,GLint param);
glTexParameterfv(GLenum target,GLenum pname,GLfloat * params);
glTexParameteriv(GLenum target,GLenum pname,GLint *params);

基本過濾

紋理過濾:根據(jù)一個拉伸或收縮的紋理貼圖計算顏色偏短的過程稱為紋理過濾
最近鄰過濾是我們能夠選擇的最簡單漓摩、最快速的過濾方法,其最顯著的特征就是當(dāng)紋理被拉伸到特別大的時候所出現(xiàn)的大片斑駁狀像素陈瘦。

//最近鄰過濾用于GL_TEXTURE_2D,為放大和縮小過濾器設(shè)置紋理過濾器
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAX_FILTER,GL_NEAREST)
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST)

線性過濾:更接近真實幌甘,沒有人工操作的痕跡

//簡單設(shè)置線性過濾
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAX_FILTER,GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR)
過濾對比

紋理環(huán)繞

紋理采樣有幾種不同的插值方式潮售。我們需要自己告訴OpenGL在紋理中采用哪種采樣方式。

  • 紋理坐標(biāo)通常的范圍是從(0, 0)到(1, 1)锅风,如果我們把紋理坐標(biāo)設(shè)置為范圍以外會發(fā)生什么酥诽?OpenGL默認(rèn)的行為是重復(fù)這個紋理圖像(我們簡單地忽略浮點紋理坐標(biāo)的整數(shù)部分),但OpenGL提供了更多的選擇:

環(huán)繞方式:

  1. GL_REPEAT 紋理的默認(rèn)行為皱埠,重復(fù)紋理圖像
  2. GL_MIRRORED_REPEAT和GL_REPEAT一樣肮帐,除了重復(fù)的圖片是鏡像放置的
  3. GL_CLAMP_TO_EDGE紋理坐標(biāo)會在0到1之間,超出的部分會重復(fù)紋理坐標(biāo)的邊緣边器,就是邊緣被拉伸
  4. GL_CLAMP_TO_BORDER超出的部分是用戶指定的邊緣的顏色

當(dāng)紋理坐標(biāo)超出默認(rèn)范圍時训枢,每個值都有不同的視覺效果輸出。我們來看看這些紋理圖像的例子:



前面提到的選項都可以使用glTexParameter
函數(shù)單獨設(shè)置每個坐標(biāo)軸s忘巧、t(如果是使用3D紋理那么還有一個r)它們和x恒界、y(z)是相等的:

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);

第一個參數(shù)指定了紋理目標(biāo);我們使用的是2D紋理砚嘴,因此紋理目標(biāo)是GL_TEXTURE_2D十酣。
第二個參數(shù)需要我們?nèi)ジ嬷覀兿MピO(shè)置哪個紋理軸。我們打算設(shè)置的是WRAP選項际长,并且指定S和T軸耸采。最后一個參數(shù)需要我們傳遞放置方式掐禁,在這個例子里我們在當(dāng)前激活紋理上應(yīng)用GL_MIRRORED_REPEAT忠怖。
如果我們選擇GL_CLAMP_TO_BORDER選項,我們還要指定一個邊緣的顏色簇搅。這次使用glTexParameter
函數(shù)的fv后綴形式如绸,加上GL_TEXTURE_BORDER_COLOR作為選項嘱朽,這個函數(shù)需要我們傳遞一個邊緣顏色的float數(shù)組作為顏色值:

float borderColor[] = { 1.0f, 1.0f, 0.0f, 1.0f };
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);

綜合應(yīng)用

示例程序金字塔
// Pyramid.cpp
// OpenGL SuperBible, Chapter 5
// Demonstrates Texture mapping a pyramid
// Program by Richard S. Wright Jr.

#include <GLTools.h>    // OpenGL toolkit
#include <GLMatrixStack.h>
#include <GLFrame.h>
#include <GLFrustum.h>
#include <GLBatch.h>
#include <GLGeometryTransform.h>

#include <math.h>
#ifdef __APPLE__
#include <glut/glut.h>
#else
#define FREEGLUT_STATIC
#include <GL/glut.h>
#endif

/////////////////////////////////////////////////////////////////////////////////
// An assortment of needed classes
GLShaderManager     shaderManager;
GLMatrixStack       modelViewMatrix;
GLMatrixStack       projectionMatrix;//投影矩陣堆棧
GLFrame             cameraFrame;//全局照相機實例
GLFrame             objectFrame;
GLFrustum           viewFrustum;//投影矩陣

GLBatch             pyramidBatch;

GLuint              textureID;

GLGeometryTransform transformPipeline;// 變換管線
M3DMatrix44f        shadowMatrix;


void MakePyramid(GLBatch& pyramidBatch)
{
    //6個三角形18個頂點,1代表在這個批次中將應(yīng)用一個紋理
    pyramidBatch.Begin(GL_TRIANGLES, 18, 1);

    // Bottom of pyramid
    pyramidBatch.Normal3f(0.0f, -1.0f, 0.0f);//向批次中添加一個表面法線竭沫,代表表面(頂點)面對的方向燥翅。在大多數(shù)光照模式下是必須的
    pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f);//添加一個紋理坐標(biāo)
    pyramidBatch.Vertex3f(-1.0f, -1.0f, -1.0f);//添加了頂點的位置

    pyramidBatch.Normal3f(0.0f, -1.0f, 0.0f);
    pyramidBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
    pyramidBatch.Vertex3f(1.0f, -1.0f, -1.0f);

    pyramidBatch.Normal3f(0.0f, -1.0f, 0.0f);
    pyramidBatch.MultiTexCoord2f(0, 1.0f, 1.0f);
    pyramidBatch.Vertex3f(1.0f, -1.0f, 1.0f);

    pyramidBatch.Normal3f(0.0f, -1.0f, 0.0f);
    pyramidBatch.MultiTexCoord2f(0, 0.0f, 1.0f);
    pyramidBatch.Vertex3f(-1.0f, -1.0f, 1.0f);

    pyramidBatch.Normal3f(0.0f, -1.0f, 0.0f);
    pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
    pyramidBatch.Vertex3f(-1.0f, -1.0f, -1.0f);

    pyramidBatch.Normal3f(0.0f, -1.0f, 0.0f);
    pyramidBatch.MultiTexCoord2f(0, 1.0f, 1.0f);
    pyramidBatch.Vertex3f(1.0f, -1.0f, 1.0f);


    M3DVector3f vApex = { 0.0f, 1.0f, 0.0f }; // Vector of three floats(x, y, z)
    M3DVector3f vFrontLeft = { -1.0f, -1.0f, 1.0f };
    M3DVector3f vFrontRight = { 1.0f, -1.0f, 1.0f };
    M3DVector3f vBackLeft = { -1.0f, -1.0f, -1.0f };
    M3DVector3f vBackRight = { 1.0f, -1.0f, -1.0f };
    M3DVector3f n;

    // Front of Pyramid
    //glTool函數(shù)庫包含了一個函數(shù)骑篙,專門用于根據(jù)一個多邊形上的3個點計算一條法線向量:
    //該方法的第一個參數(shù)用于存儲求得的法線向量蜕提,還要另外向它傳遞3個向量,表示取自多邊形或三角形上的點
    //(以逆時針環(huán)繞方向指定)靶端。注意谎势,該方法返回的法線向量并不一定是單位長度的
    m3dFindNormal(n, vApex, vFrontLeft, vFrontRight);
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0, 0.5f, 1.0f);
    pyramidBatch.Vertex3fv(vApex);      // Apex

    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
    pyramidBatch.Vertex3fv(vFrontLeft);     // Front left corner

    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
    pyramidBatch.Vertex3fv(vFrontRight);        // Front right corner


    m3dFindNormal(n, vApex, vBackLeft, vFrontLeft);
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0, 0.5f, 1.0f);
    pyramidBatch.Vertex3fv(vApex);      // Apex

    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
    pyramidBatch.Vertex3fv(vBackLeft);      // Back left corner

    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
    pyramidBatch.Vertex3fv(vFrontLeft);     // Front left corner

    m3dFindNormal(n, vApex, vFrontRight, vBackRight);
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0, 0.5f, 1.0f);
    pyramidBatch.Vertex3fv(vApex);              // Apex

    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
    pyramidBatch.Vertex3fv(vFrontRight);        // Front right corner

    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
    pyramidBatch.Vertex3fv(vBackRight);         // Back right cornder


    m3dFindNormal(n, vApex, vBackRight, vBackLeft);
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0, 0.5f, 1.0f);
    pyramidBatch.Vertex3fv(vApex);      // Apex

    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
    pyramidBatch.Vertex3fv(vBackRight);     // Back right cornder

    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
    pyramidBatch.Vertex3fv(vBackLeft);      // Back left corner

    pyramidBatch.End();
}

// Load a TGA as a 2D Texture. Completely initialize the state
bool LoadTGATexture(const char *szFileName, GLenum minFilter, GLenum magFilter, GLenum wrapMode)
{
    GLbyte *pBits;
    int nWidth, nHeight, nComponents;
    GLenum eFormat;

    // Read the texture bits
    pBits = gltReadTGABits(szFileName, &nWidth, &nHeight, &nComponents, &eFormat);
    if (pBits == NULL)
        return false;

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapMode);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapMode);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter);

    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    glTexImage2D(GL_TEXTURE_2D, 0, nComponents, nWidth, nHeight, 0,
        eFormat, GL_UNSIGNED_BYTE, pBits);

    free(pBits);

    if (minFilter == GL_LINEAR_MIPMAP_LINEAR ||
        minFilter == GL_LINEAR_MIPMAP_NEAREST ||
        minFilter == GL_NEAREST_MIPMAP_LINEAR ||
        minFilter == GL_NEAREST_MIPMAP_NEAREST)
        glGenerateMipmap(GL_TEXTURE_2D);

    return true;
}


///////////////////////////////////////////////////////////////////////////////
// This function does any needed initialization on the rendering context. 
// This is the first opportunity to do any OpenGL related tasks.
void SetupRC()
{
    // Black background
    glClearColor(0.7f, 0.7f, 0.7f, 1.0f);
    //調(diào)用之前使用
    shaderManager.InitializeStockShaders();

    glEnable(GL_DEPTH_TEST);

    glGenTextures(1, &textureID);//分配一些紋理對象
    glBindTexture(GL_TEXTURE_2D, textureID);//綁定一種紋理狀態(tài)
    LoadTGATexture("stone.tga", GL_LINEAR, GL_LINEAR, GL_CLAMP_TO_EDGE);

    MakePyramid(pyramidBatch);

    cameraFrame.MoveForward(-7.0f);
}

///////////////////////////////////////////////////////////////////////////////
// Cleanup... such as deleting texture objects
void ShutdownRC(void)
{
    glDeleteTextures(1, &textureID);
}

///////////////////////////////////////////////////////////////////////////////
// Called to draw scene
void RenderScene(void)
{
    static GLfloat vLightPos[] = { 1.0f, 1.0f, 0.0f };
    static GLfloat vWhite[] = { 1.0f, 1.0f, 1.0f, 1.0f };

    // Clear the window with current clearing color
    //glClear()函數(shù)的作用是用當(dāng)前緩沖區(qū)清除值,
    //也就是glClearColor或者glClearDepth杨名、glClearIndex脏榆、glClearStencil、glClearAccum等函數(shù)所指定的值來清除指定的緩沖區(qū)台谍,
    //也可以使用glDrawBuffer一次清除多個顏色緩存须喂。
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
    //保存當(dāng)前模型視圖矩陣
    modelViewMatrix.PushMatrix();

    M3DMatrix44f mCamera;
    cameraFrame.GetCameraMatrix(mCamera);
    modelViewMatrix.MultMatrix(mCamera);

    M3DMatrix44f mObjectFrame;
    objectFrame.GetMatrix(mObjectFrame);
    modelViewMatrix.MultMatrix(mObjectFrame);

    glBindTexture(GL_TEXTURE_2D, textureID);//綁定紋理對象
    //繪制背景,點光源
    shaderManager.UseStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF,
        transformPipeline.GetModelViewMatrix(),
        transformPipeline.GetProjectionMatrix(),
        vLightPos, vWhite, 0);

    pyramidBatch.Draw();


    modelViewMatrix.PopMatrix();

    // Flush drawing commands
    glutSwapBuffers();
}


// Respond to arrow keys by moving the camera frame of reference
void SpecialKeys(int key, int x, int y)
{
    if (key == GLUT_KEY_UP)
        //void RotateWorld(float fAngle, float x, float y, float z)
        //在世界坐標(biāo)系中旋轉(zhuǎn)
        objectFrame.RotateWorld(m3dDegToRad(-5.0f), 1.0f, 0.0f, 0.0f); 

    if (key == GLUT_KEY_DOWN)
        objectFrame.RotateWorld(m3dDegToRad(5.0f), 1.0f, 0.0f, 0.0f);

    if (key == GLUT_KEY_LEFT)
        objectFrame.RotateWorld(m3dDegToRad(-5.0f), 0.0f, 1.0f, 0.0f);

    if (key == GLUT_KEY_RIGHT)
        objectFrame.RotateWorld(m3dDegToRad(5.0f), 0.0f, 1.0f, 0.0f);

    glutPostRedisplay();
    //glutPostRedisplay 標(biāo)記當(dāng)前窗口需要重新繪制。
    //通過glutMainLoop下一次循環(huán)時坞生,窗口顯示將被回調(diào)以重新顯示窗口的正常面板仔役。
}




///////////////////////////////////////////////////////////////////////////////
// Window has changed size, or has just been created. In either case, we need
// to use the window dimensions to set the viewport and the projection matrix.
void ChangeSize(int w, int h)
{
    glViewport(0, 0, w, h);
    //創(chuàng)建投影矩陣并把它載入到投影矩陣堆棧中
    viewFrustum.SetPerspective(35.0f, float(w) / float(h), 1.0f, 500.0f);
    projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
    //設(shè)置變換管線以使用兩個矩陣堆棧
    transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
}

///////////////////////////////////////////////////////////////////////////////
// Main entry point for GLUT based programs
int main(int argc, char* argv[])
{
    gltSetWorkingDirectory(argv[0]);

    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
    glutInitWindowSize(800, 600);
    glutCreateWindow("Pyramid");
    glutReshapeFunc(ChangeSize);
    glutSpecialFunc(SpecialKeys);
    glutDisplayFunc(RenderScene);//OpenGL渲染代碼

    GLenum err = glewInit();
    if (GLEW_OK != err) {
        fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
        return 1;
    }


    SetupRC();

    glutMainLoop();

    ShutdownRC();

    return 0;
}

Mip貼圖

Mip貼圖是一種強大的紋理技巧,不僅可以提高渲染性能是己,而且可以改善場景的顯示質(zhì)量又兵。Mipmap中每一個層級的小圖都是主圖的一個特定比例的縮小細(xì)節(jié)的復(fù)制品。雖然在某些必要的視角卒废,主圖仍然會被使用沛厨,來渲染完整的細(xì)節(jié)。但是當(dāng)貼圖被縮小或者只需要從遠(yuǎn)距離觀看時摔认,mipmap就會轉(zhuǎn)換到適當(dāng)?shù)膶蛹壞嫫ぁ!?/p>

Mip貼圖示例

Mip貼圖過濾

Mip貼圖過濾

活動的Mip貼圖

示例程序TUNNEL
//漢字注釋見書p151
// Tunnel.cpp
// Demonstrates mipmapping and using texture objects
// OpenGL SuperBible
// Richard S. Wright Jr.
#include <GLTools.h>
#include <GLShaderManager.h>
#include <GLFrustum.h>
#include <GLBatch.h>
#include <GLFrame.h>
#include <GLMatrixStack.h>
#include <GLGeometryTransform.h>

#ifdef __APPLE__
#include <glut/glut.h>
#else
#define FREEGLUT_STATIC
#include <GL/glut.h>
#endif


GLShaderManager     shaderManager;          // Shader Manager
GLMatrixStack       modelViewMatrix;        // Modelview Matrix
GLMatrixStack       projectionMatrix;       // Projection Matrix
GLFrustum           viewFrustum;            // View Frustum
GLGeometryTransform transformPipeline;      // Geometry Transform Pipeline

GLBatch             floorBatch;
GLBatch             ceilingBatch;
GLBatch             leftWallBatch;
GLBatch             rightWallBatch;

GLfloat             viewZ = -65.0f;

// Texture objects
#define TEXTURE_BRICK   0
#define TEXTURE_FLOOR   1
#define TEXTURE_CEILING 2
#define TEXTURE_COUNT   3
GLuint  textures[TEXTURE_COUNT];
const char *szTextureFiles[TEXTURE_COUNT] = { "brick.tga", "floor.tga", "ceiling.tga" };



///////////////////////////////////////////////////////////////////////////////
// Change texture filter for each texture object
void ProcessMenu(int value)
    {
    GLfloat fLargest;
    GLint iLoop;
    
    for(iLoop = 0; iLoop < TEXTURE_COUNT; iLoop++)
        {
        glBindTexture(GL_TEXTURE_2D, textures[iLoop]);
        
        switch(value)
            {
            case 0:
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
                break;
                
            case 1:
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
                break;
                
            case 2:
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
                break;
            
            case 3:
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);
                break;
            
            case 4:
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
                break;
                
            case 5:
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
                break;
                
            case 6:
                glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &fLargest);
                glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, fLargest);
                break;
                
            case 7:
                glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0f);
                break;
            }
        }
        
    // Trigger Redraw
    glutPostRedisplay();
    }


//////////////////////////////////////////////////////////////////
// This function does any needed initialization on the rendering
// context.  Here it sets up and initializes the texture objects.
void SetupRC()
    {
    GLbyte *pBytes;
    GLint iWidth, iHeight, iComponents;
    GLenum eFormat;
    GLint iLoop;
    
    // Black background
    glClearColor(0.0f, 0.0f, 0.0f,1.0f);
    
    shaderManager.InitializeStockShaders();

    // Load textures
    glGenTextures(TEXTURE_COUNT, textures);
    for(iLoop = 0; iLoop < TEXTURE_COUNT; iLoop++)
        {
        // Bind to next texture object
        glBindTexture(GL_TEXTURE_2D, textures[iLoop]);
        
        // Load texture, set filter and wrap modes
        pBytes = gltReadTGABits(szTextureFiles[iLoop],&iWidth, &iHeight,
                              &iComponents, &eFormat);

        // Load texture, set filter and wrap modes
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        glTexImage2D(GL_TEXTURE_2D, 0, iComponents, iWidth, iHeight, 0, eFormat, GL_UNSIGNED_BYTE, pBytes);
        glGenerateMipmap(GL_TEXTURE_2D);
        
        // Don't need original texture data any more
        free(pBytes);
        }
        
    // Build Geometry
    GLfloat z;
    floorBatch.Begin(GL_TRIANGLE_STRIP, 28, 1);
    for(z = 60.0f; z >= 0.0f; z -=10.0f)
        {
        floorBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
        floorBatch.Vertex3f(-10.0f, -10.0f, z);
         
        floorBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
        floorBatch.Vertex3f(10.0f, -10.0f, z);
         
        floorBatch.MultiTexCoord2f(0, 0.0f, 1.0f);
        floorBatch.Vertex3f(-10.0f, -10.0f, z - 10.0f);
         
        floorBatch.MultiTexCoord2f(0, 1.0f, 1.0f);
        floorBatch.Vertex3f(10.0f, -10.0f, z - 10.0f);
        }
    floorBatch.End();
    
    ceilingBatch.Begin(GL_TRIANGLE_STRIP, 28, 1);
    for(z = 60.0f; z >= 0.0f; z -=10.0f)
        {
        ceilingBatch.MultiTexCoord2f(0, 0.0f, 1.0f);
        ceilingBatch.Vertex3f(-10.0f, 10.0f, z - 10.0f);
        
        ceilingBatch.MultiTexCoord2f(0, 1.0f, 1.0f);
        ceilingBatch.Vertex3f(10.0f, 10.0f, z - 10.0f);
        
        ceilingBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
        ceilingBatch.Vertex3f(-10.0f, 10.0f, z);

        ceilingBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
        ceilingBatch.Vertex3f(10.0f, 10.0f, z);
        }
    ceilingBatch.End();
    
    leftWallBatch.Begin(GL_TRIANGLE_STRIP, 28, 1);
    for(z = 60.0f; z >= 0.0f; z -=10.0f)
        {
        leftWallBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
        leftWallBatch.Vertex3f(-10.0f, -10.0f, z);
        
        leftWallBatch.MultiTexCoord2f(0, 0.0f, 1.0f);
        leftWallBatch.Vertex3f(-10.0f, 10.0f, z);
        
        leftWallBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
        leftWallBatch.Vertex3f(-10.0f, -10.0f, z - 10.0f);

        leftWallBatch.MultiTexCoord2f(0, 1.0f, 1.0f);
        leftWallBatch.Vertex3f(-10.0f, 10.0f, z - 10.0f);
        }
    leftWallBatch.End();
    
    
    rightWallBatch.Begin(GL_TRIANGLE_STRIP, 28, 1);
    for(z = 60.0f; z >= 0.0f; z -=10.0f)
        {
        rightWallBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
        rightWallBatch.Vertex3f(10.0f, -10.0f, z);
        
        rightWallBatch.MultiTexCoord2f(0, 0.0f, 1.0f);
        rightWallBatch.Vertex3f(10.0f, 10.0f, z);
        
        rightWallBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
        rightWallBatch.Vertex3f(10.0f, -10.0f, z - 10.0f);

        rightWallBatch.MultiTexCoord2f(0, 1.0f, 1.0f);
        rightWallBatch.Vertex3f(10.0f, 10.0f, z - 10.0f);
        }
    rightWallBatch.End();
    }
    
///////////////////////////////////////////////////
// Shutdown the rendering context. Just deletes the
// texture objects
void ShutdownRC(void)
    {
    glDeleteTextures(TEXTURE_COUNT, textures);
    }
    

///////////////////////////////////////////////////
// Respond to arrow keys, move the viewpoint back
// and forth
void SpecialKeys(int key, int x, int y)
    {
    if(key == GLUT_KEY_UP)
        viewZ += 0.5f;

    if(key == GLUT_KEY_DOWN)
        viewZ -= 0.5f;

    // Refresh the Window
    glutPostRedisplay();
    }

/////////////////////////////////////////////////////////////////////
// Change viewing volume and viewport.  Called when window is resized
void ChangeSize(int w, int h)
    {
    GLfloat fAspect;

    // Prevent a divide by zero
    if(h == 0)
        h = 1;

    // Set Viewport to window dimensions
    glViewport(0, 0, w, h);

    fAspect = (GLfloat)w/(GLfloat)h;

    // Produce the perspective projection
    viewFrustum.SetPerspective(80.0f,fAspect,1.0,120.0);
    projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
    transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);

    }

///////////////////////////////////////////////////////
// Called to draw scene
void RenderScene(void)
    {
    // Clear the window with current clearing color
    glClear(GL_COLOR_BUFFER_BIT);

    modelViewMatrix.PushMatrix();
        modelViewMatrix.Translate(0.0f, 0.0f, viewZ);
        
        shaderManager.UseStockShader(GLT_SHADER_TEXTURE_REPLACE, transformPipeline.GetModelViewProjectionMatrix(), 0);

        glBindTexture(GL_TEXTURE_2D, textures[TEXTURE_FLOOR]);
        floorBatch.Draw();
        
        glBindTexture(GL_TEXTURE_2D, textures[TEXTURE_CEILING]);
        ceilingBatch.Draw();
        
        glBindTexture(GL_TEXTURE_2D, textures[TEXTURE_BRICK]);
        leftWallBatch.Draw();
        rightWallBatch.Draw();
        
    modelViewMatrix.PopMatrix();

    // Buffer swap
    glutSwapBuffers();
    }


//////////////////////////////////////////////////////
// Program entry point
int main(int argc, char *argv[])
    {
    gltSetWorkingDirectory(argv[0]);

    // Standard initialization stuff
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
    glutInitWindowSize(800, 600);
    glutCreateWindow("Anisotropic Tunnel");
    glutReshapeFunc(ChangeSize);
    glutSpecialFunc(SpecialKeys);
    glutDisplayFunc(RenderScene);
    
    // Add menu entries to change filter
    glutCreateMenu(ProcessMenu);
    glutAddMenuEntry("GL_NEAREST",0);
    glutAddMenuEntry("GL_LINEAR",1);
    glutAddMenuEntry("GL_NEAREST_MIPMAP_NEAREST",2);
    glutAddMenuEntry("GL_NEAREST_MIPMAP_LINEAR", 3);
    glutAddMenuEntry("GL_LINEAR_MIPMAP_NEAREST", 4);
    glutAddMenuEntry("GL_LINEAR_MIPMAP_LINEAR", 5);
    glutAddMenuEntry("Anisotropic Filter", 6);
    glutAddMenuEntry("Anisotropic Off", 7);

    glutAttachMenu(GLUT_RIGHT_BUTTON);
    
    GLenum err = glewInit();
    if (GLEW_OK != err) {
        fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
        return 1;
        }
    
    // Startup, loop, shutdown
    SetupRC();
    glutMainLoop();
    ShutdownRC();
    
    return 0;
    }

各向異性過濾

如果我們在紋理過濾時考慮了觀察角度参袱,那么這種方法就叫做各向異性過濾

對比

紋理壓縮

紋理壓縮(Texture compression)是一種專為在三維計算機圖形渲染系統(tǒng)中存儲紋理而使用的圖像壓縮技術(shù)页屠。與普通圖像壓縮算法的不同之處在于,紋理壓縮算法為紋素隨機存取做了優(yōu)化蓖柔。

壓縮紋理

通用壓縮紋理格式

加載壓縮紋理

加載壓縮紋理

最后一個示例

SphereWorld
// SphereWorld.cpp
// OpenGL SuperBible
// New and improved (performance) sphere world
// Program by Richard S. Wright Jr.

#include <GLTools.h>
#include <GLShaderManager.h>
#include <GLFrustum.h>
#include <GLBatch.h>
#include <GLMatrixStack.h>
#include <GLGeometryTransform.h>
#include <StopWatch.h>

#include <math.h>
#include <stdio.h>

#ifdef __APPLE__
#include <glut/glut.h>
#else
#define FREEGLUT_STATIC
#include <GL/glut.h>
#endif

#define NUM_SPHERES 50
GLFrame spheres[NUM_SPHERES];

GLShaderManager     shaderManager;          // Shader Manager
GLMatrixStack       modelViewMatrix;        // Modelview Matrix
GLMatrixStack       projectionMatrix;       // Projection Matrix
GLFrustum           viewFrustum;            // View Frustum
GLGeometryTransform transformPipeline;      // Geometry Transform Pipeline
GLFrame             cameraFrame;            // Camera frame

GLTriangleBatch     torusBatch;
GLTriangleBatch     sphereBatch;
GLBatch             floorBatch;

GLuint              uiTextures[3];



void DrawSongAndDance(GLfloat yRot)     // Called to draw dancing objects
    {
    static GLfloat vWhite[] = { 1.0f, 1.0f, 1.0f, 1.0f };
    static GLfloat vLightPos[] = { 0.0f, 3.0f, 0.0f, 1.0f };
    
    // Get the light position in eye space
    M3DVector4f vLightTransformed;
    M3DMatrix44f mCamera;
    modelViewMatrix.GetMatrix(mCamera);
    m3dTransformVector4(vLightTransformed, vLightPos, mCamera);
    
    // Draw the light source
    modelViewMatrix.PushMatrix();
    modelViewMatrix.Translatev(vLightPos);
    shaderManager.UseStockShader(GLT_SHADER_FLAT, 
                                 transformPipeline.GetModelViewProjectionMatrix(),
                                 vWhite);
    sphereBatch.Draw();
    modelViewMatrix.PopMatrix();
    
    glBindTexture(GL_TEXTURE_2D, uiTextures[2]);
    for(int i = 0; i < NUM_SPHERES; i++) {
        modelViewMatrix.PushMatrix();
        modelViewMatrix.MultMatrix(spheres[i]);
        shaderManager.UseStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF,
                                     modelViewMatrix.GetMatrix(),
                                     transformPipeline.GetProjectionMatrix(),
                                     vLightTransformed, 
                                     vWhite,
                                     0);
        sphereBatch.Draw();
        modelViewMatrix.PopMatrix();
    }
    
    // Song and dance
    modelViewMatrix.Translate(0.0f, 0.2f, -2.5f);
    modelViewMatrix.PushMatrix();   // Saves the translated origin
    modelViewMatrix.Rotate(yRot, 0.0f, 1.0f, 0.0f);
    
    // Draw stuff relative to the camera
    glBindTexture(GL_TEXTURE_2D, uiTextures[1]);
    shaderManager.UseStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF,
                                 modelViewMatrix.GetMatrix(),
                                 transformPipeline.GetProjectionMatrix(),
                                 vLightTransformed, 
                                 vWhite,
                                 0);
    torusBatch.Draw();
    modelViewMatrix.PopMatrix(); // Erased the rotate
    
    modelViewMatrix.Rotate(yRot * -2.0f, 0.0f, 1.0f, 0.0f);
    modelViewMatrix.Translate(0.8f, 0.0f, 0.0f);
    
    glBindTexture(GL_TEXTURE_2D, uiTextures[2]);
    shaderManager.UseStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF,
                                 modelViewMatrix.GetMatrix(),
                                 transformPipeline.GetProjectionMatrix(),
                                 vLightTransformed, 
                                 vWhite,
                                 0);
    sphereBatch.Draw();
    }
    
    
bool LoadTGATexture(const char *szFileName, GLenum minFilter, GLenum magFilter, GLenum wrapMode)
    {
    GLbyte *pBits;
    int nWidth, nHeight, nComponents;
    GLenum eFormat;
    
    // Read the texture bits
    pBits = gltReadTGABits(szFileName, &nWidth, &nHeight, &nComponents, &eFormat);
    if(pBits == NULL) 
        return false;
    
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapMode);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapMode);
    
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter);
        
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB, nWidth, nHeight, 0,
                 eFormat, GL_UNSIGNED_BYTE, pBits);
    
    free(pBits);

    if(minFilter == GL_LINEAR_MIPMAP_LINEAR || 
       minFilter == GL_LINEAR_MIPMAP_NEAREST ||
       minFilter == GL_NEAREST_MIPMAP_LINEAR ||
       minFilter == GL_NEAREST_MIPMAP_NEAREST)
        glGenerateMipmap(GL_TEXTURE_2D);
            
    return true;
    }

        
//////////////////////////////////////////////////////////////////
// This function does any needed initialization on the rendering
// context. 
void SetupRC()
    {
    // Make sure OpenGL entry points are set
    glewInit();
    
    // Initialze Shader Manager
    shaderManager.InitializeStockShaders();
    
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_CULL_FACE);
    
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    
    // This makes a torus
    gltMakeTorus(torusBatch, 0.4f, 0.15f, 40, 20);
    
    // This makes a sphere
    gltMakeSphere(sphereBatch, 0.1f, 26, 13);
    
    
    // Make the solid ground
    GLfloat texSize = 10.0f;
    floorBatch.Begin(GL_TRIANGLE_FAN, 4, 1);
    floorBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
    floorBatch.Vertex3f(-20.0f, -0.41f, 20.0f);
    
    floorBatch.MultiTexCoord2f(0, texSize, 0.0f);
    floorBatch.Vertex3f(20.0f, -0.41f, 20.0f);
    
    floorBatch.MultiTexCoord2f(0, texSize, texSize);
    floorBatch.Vertex3f(20.0f, -0.41f, -20.0f);
    
    floorBatch.MultiTexCoord2f(0, 0.0f, texSize);
    floorBatch.Vertex3f(-20.0f, -0.41f, -20.0f);
    floorBatch.End();
    
    // Make 3 texture objects
    glGenTextures(3, uiTextures);
    
    // Load the Marble
    glBindTexture(GL_TEXTURE_2D, uiTextures[0]);
    LoadTGATexture("marble.tga", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_REPEAT);
    
    // Load Mars
    glBindTexture(GL_TEXTURE_2D, uiTextures[1]);
    LoadTGATexture("marslike.tga", GL_LINEAR_MIPMAP_LINEAR, 
                   GL_LINEAR, GL_CLAMP_TO_EDGE);
    
    // Load Moon
    glBindTexture(GL_TEXTURE_2D, uiTextures[2]);
    LoadTGATexture("moonlike.tga", GL_LINEAR_MIPMAP_LINEAR,
                   GL_LINEAR, GL_CLAMP_TO_EDGE);
                   
    // Randomly place the spheres
    for(int i = 0; i < NUM_SPHERES; i++) {
        GLfloat x = ((GLfloat)((rand() % 400) - 200) * 0.1f);
        GLfloat z = ((GLfloat)((rand() % 400) - 200) * 0.1f);
        spheres[i].SetOrigin(x, 0.0f, z);
        }
    }

////////////////////////////////////////////////////////////////////////
// Do shutdown for the rendering context
void ShutdownRC(void)
    {
    glDeleteTextures(3, uiTextures);
    }



        
// Called to draw scene
void RenderScene(void)
    {
    static CStopWatch   rotTimer;
    float yRot = rotTimer.GetElapsedSeconds() * 60.0f;
    
    
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
    modelViewMatrix.PushMatrix();   
    M3DMatrix44f mCamera;
    cameraFrame.GetCameraMatrix(mCamera);
    modelViewMatrix.MultMatrix(mCamera);
    
    // Draw the world upside down
    modelViewMatrix.PushMatrix();
    modelViewMatrix.Scale(1.0f, -1.0f, 1.0f); // Flips the Y Axis
    modelViewMatrix.Translate(0.0f, 0.8f, 0.0f); // Scootch the world down a bit...
    glFrontFace(GL_CW);
    DrawSongAndDance(yRot);
    glFrontFace(GL_CCW);
    modelViewMatrix.PopMatrix();
    
    // Draw the solid ground
    glEnable(GL_BLEND);
    glBindTexture(GL_TEXTURE_2D, uiTextures[0]);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    static GLfloat vFloorColor[] = { 1.0f, 1.0f, 1.0f, 0.75f};
    shaderManager.UseStockShader(GLT_SHADER_TEXTURE_MODULATE,
                                 transformPipeline.GetModelViewProjectionMatrix(),
                                 vFloorColor,
                                 0);
    
    floorBatch.Draw();
    glDisable(GL_BLEND);
    
    
    DrawSongAndDance(yRot);
    
    modelViewMatrix.PopMatrix();
    
        
    // Do the buffer Swap
    glutSwapBuffers();
        
    // Do it again
    glutPostRedisplay();
    }



// Respond to arrow keys by moving the camera frame of reference
void SpecialKeys(int key, int x, int y)
    {
    float linear = 0.1f;
    float angular = float(m3dDegToRad(5.0f));
    
    if(key == GLUT_KEY_UP)
        cameraFrame.MoveForward(linear);
    
    if(key == GLUT_KEY_DOWN)
        cameraFrame.MoveForward(-linear);
    
    if(key == GLUT_KEY_LEFT)
        cameraFrame.RotateWorld(angular, 0.0f, 1.0f, 0.0f);
    
    if(key == GLUT_KEY_RIGHT)
        cameraFrame.RotateWorld(-angular, 0.0f, 1.0f, 0.0f);    
    }


void ChangeSize(int nWidth, int nHeight)
    {
    glViewport(0, 0, nWidth, nHeight);
    transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
    
    viewFrustum.SetPerspective(35.0f, float(nWidth)/float(nHeight), 1.0f, 100.0f);
    projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
    modelViewMatrix.LoadIdentity();
    }

int main(int argc, char* argv[])
    {
    gltSetWorkingDirectory(argv[0]);
        
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowSize(800,600);
  
    glutCreateWindow("OpenGL SphereWorld");
 
    glutReshapeFunc(ChangeSize);
    glutDisplayFunc(RenderScene);
    glutSpecialFunc(SpecialKeys);

    SetupRC();
    glutMainLoop();    
    ShutdownRC();
    return 0;
    }

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末辰企,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子况鸣,更是在濱河造成了極大的恐慌牢贸,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,635評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件镐捧,死亡現(xiàn)場離奇詭異潜索,居然都是意外死亡,警方通過查閱死者的電腦和手機懂酱,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評論 3 399
  • 文/潘曉璐 我一進店門竹习,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人列牺,你說我怎么就攤上這事整陌。” “怎么了瞎领?”我有些...
    開封第一講書人閱讀 168,083評論 0 360
  • 文/不壞的土叔 我叫張陵泌辫,是天一觀的道長。 經(jīng)常有香客問我九默,道長震放,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,640評論 1 296
  • 正文 為了忘掉前任驼修,我火速辦了婚禮殿遂,結(jié)果婚禮上诈铛,老公的妹妹穿的比我還像新娘。我一直安慰自己墨礁,他們只是感情好癌瘾,可當(dāng)我...
    茶點故事閱讀 68,640評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著饵溅,像睡著了一般妨退。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蜕企,一...
    開封第一講書人閱讀 52,262評論 1 308
  • 那天咬荷,我揣著相機與錄音,去河邊找鬼轻掩。 笑死幸乒,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的唇牧。 我是一名探鬼主播罕扎,決...
    沈念sama閱讀 40,833評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼丐重!你這毒婦竟也來了腔召?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,736評論 0 276
  • 序言:老撾萬榮一對情侶失蹤扮惦,失蹤者是張志新(化名)和其女友劉穎臀蛛,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體崖蜜,經(jīng)...
    沈念sama閱讀 46,280評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡浊仆,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,369評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了豫领。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片抡柿。...
    茶點故事閱讀 40,503評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖等恐,靈堂內(nèi)的尸體忽然破棺而出洲劣,到底是詐尸還是另有隱情,我是刑警寧澤鼠锈,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布闪檬,位于F島的核電站,受9級特大地震影響购笆,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜虚循,卻給世界環(huán)境...
    茶點故事閱讀 41,870評論 3 333
  • 文/蒙蒙 一同欠、第九天 我趴在偏房一處隱蔽的房頂上張望样傍。 院中可真熱鬧,春花似錦铺遂、人聲如沸衫哥。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽撤逢。三九已至,卻和暖如春粮坞,著一層夾襖步出監(jiān)牢的瞬間蚊荣,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評論 1 272
  • 我被黑心中介騙來泰國打工莫杈, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留互例,地道東北人。 一個月前我還...
    沈念sama閱讀 48,909評論 3 376
  • 正文 我出身青樓筝闹,卻偏偏與公主長得像媳叨,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子关顷,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,512評論 2 359

推薦閱讀更多精彩內(nèi)容