update: 2012/06/21
reference:
1. OpenGL ES 2.0 for iPhone Tutorial Part 2: Textures | Ray Wenderlich
2. I touchs: OpenGL ES 2.0 Tutorial Part 2 - 1
紋理貼圖之二
A. 修正被伸展的效果
1. 說明:
a. 造成伸展效果的原因是: 我們目前只是為每個頂點設定一個紋理座標, 並且
重覆使用這些頂點.
b. 例如, 我們把立方體的前面左下角對應到 (0, 0). 但是在左邊那一面, 相同的
頂點卻變成了在右下方, 所以如果此時對應到的紋理座標同樣為 (0, 0) 就
沒有意義了, 它應該是 (1, 0).
c. 在 OpenGL 裡, 你不能把頂點只是當成頂點座標, 它是由以下所組合而成的
獨一無二的點: 座標, 顏色, 紋理座標以及任何在你的結構中所擁有的其它元素.
***************************************************************
2. 開啓 OpenGLView.m 檔案, 修改如下:
//setp01
#import "OpenGLView.h"
//@add for projection
#import "CC3GLMatrix.h"
//@add
#define TEX_COORD_MAX 1
....
//setp02
/*
const Vertex Vertices[] = {
{{1, -1, 0}, {1, 0, 0, 1}, {1, 0}},
{{1, 1, 0}, {1, 0, 0, 1}, {1, 1}},
{{-1, 1, 0}, {0, 1, 0, 1}, {0, 1}},
{{-1, -1, 0}, {0, 1, 0, 1}, {0, 0}},
{{1, -1, -1}, {1, 0, 0, 1}, {1, 0}},
{{1, 1, -1}, {1, 0, 0, 1}, {1, 1}},
{{-1, 1, -1}, {0, 1, 0, 1}, {0, 1}},
{{-1, -1, -1}, {0, 1, 0, 1}, {0, 0}}
};
*/
//@update
// 要確保紋理座標能正確的對應:
// 為每個面建立各自不同的: 頂點, 顏色與紋理座標
const Vertex Vertices[] = {
// Front
{{1, -1, 0}, {1, 0, 0, 1}, {TEX_COORD_MAX, 0}},
{{1, 1, 0}, {0, 1, 0, 1}, {TEX_COORD_MAX, TEX_COORD_MAX}},
{{-1, 1, 0}, {0, 0, 1, 1}, {0, TEX_COORD_MAX}},
{{-1, -1, 0}, {0, 0, 0, 1}, {0, 0}},
// Back
{{1, 1, -2}, {1, 0, 0, 1}, {TEX_COORD_MAX, 0}},
{{-1, -1, -2}, {0, 1, 0, 1}, {TEX_COORD_MAX, TEX_COORD_MAX}},
{{1, -1, -2}, {0, 0, 1, 1}, {0, TEX_COORD_MAX}},
{{-1, 1, -2}, {0, 0, 0, 1}, {0, 0}},
// Left
{{-1, -1, 0}, {1, 0, 0, 1}, {TEX_COORD_MAX, 0}},
{{-1, 1, 0}, {0, 1, 0, 1}, {TEX_COORD_MAX, TEX_COORD_MAX}},
{{-1, 1, -2}, {0, 0, 1, 1}, {0, TEX_COORD_MAX}},
{{-1, -1, -2}, {0, 0, 0, 1}, {0, 0}},
// Right
{{1, -1, -2}, {1, 0, 0, 1}, {TEX_COORD_MAX, 0}},
{{1, 1, -2}, {0, 1, 0, 1}, {TEX_COORD_MAX, TEX_COORD_MAX}},
{{1, 1, 0}, {0, 0, 1, 1}, {0, TEX_COORD_MAX}},
{{1, -1, 0}, {0, 0, 0, 1}, {0, 0}},
// Top
{{1, 1, 0}, {1, 0, 0, 1}, {TEX_COORD_MAX, 0}},
{{1, 1, -2}, {0, 1, 0, 1}, {TEX_COORD_MAX, TEX_COORD_MAX}},
{{-1, 1, -2}, {0, 0, 1, 1}, {0, TEX_COORD_MAX}},
{{-1, 1, 0}, {0, 0, 0, 1}, {0, 0}},
// Bottom
{{1, -1, -2}, {1, 0, 0, 1}, {TEX_COORD_MAX, 0}},
{{1, -1, 0}, {0, 1, 0, 1}, {TEX_COORD_MAX, TEX_COORD_MAX}},
{{-1, -1, 0}, {0, 0, 1, 1}, {0, TEX_COORD_MAX}},
{{-1, -1, -2}, {0, 0, 0, 1}, {0, 0}}
};
....
//setp03
/*
const GLubyte Indices[] = {
// Front
0, 1, 2,
2, 3, 0,
// Back
4, 6, 5,
4, 7, 6,
// Left
2, 7, 3,
7, 6, 2,
// Right
0, 4, 1,
4, 1, 5,
// Top
6, 2, 1,
1, 6, 5,
// Bottom
0, 3, 7,
0, 7, 4
};
*/
//@update
const GLubyte Indices[] = {
// Front
0, 1, 2,
2, 3, 0,
// Back
4, 5, 6,
4, 5, 7,
// Left
8, 9, 10,
10, 11, 8,
// Right
12, 13, 14,
14, 15, 12,
// Top
16, 17, 18,
18, 19, 16,
// Bottom
20, 21, 22,
22, 23, 20
};
....
***************************************************************
3. 編譯並執行:
B. 重複貼圖
1. 說明:
在 OpenGL 裡, 如果你喜歡的話, 可以很容易地在物體表面上建立重複的
紋理貼圖. 我們所要使用的地磚紋理, 最好是無縫的紋理.
2. 開啓 OpenGLView.m 檔案, 修改如下:
....
//@add
//#define TEX_COORD_MAX 1
#define TEX_COORD_MAX 4
....
說明: 現在我們讓立方體的每個面從左下角 (0, 0) 到右上角 (4, 4) 都對應到
紋理貼圖上.
3. 編譯並執行:
可以看到沿著立方體表面的重複紋理.
說明: 能夠這樣自動完成的原因是 GL_TEXTURE_WRAP_S 與
GL_TEXTURE_WRAP_T 的預設值為 GL_REPEAT. 如果不想讓紋理
如此重復的話, 你可以利用 glTexParameteri 來覆寫預設的值.
-----------------------------------------------------------------------------------------
C. 加入花樣
1. 開啓 OpenGLView.h 檔案, 修改如下:....
@interface OpenGLView : UIView
{
....
//@add
//
// 我們分別需要二個 vertex / index buffers
// 一個給立方體, 另一個給擁有 "魚骨花樣" 的那一個表面
GLuint _vertexBuffer;
GLuint _indexBuffer;
GLuint _vertexBuffer2;
GLuint _indexBuffer2;
}
....
2. 開啓 OpenGLView.m 檔案, 修改如下:
....
// step01
//@add: 為要繪製魚骨紋理的矩形定義一組新的頂點集合
//
// 我們將它設置的比前方表面還要小一些, 並且將 Z 座標的值稍微調高一些, 讓它浮現.
// 不然的話, 在作深度測試時就會被摒棄掉.
const Vertex Vertices2[] = {
{{0.5, -0.5, 0.01}, {1, 1, 1, 1}, {1, 1}},
{{0.5, 0.5, 0.01}, {1, 1, 1, 1}, {1, 0}},
{{-0.5, 0.5, 0.01}, {1, 1, 1, 1}, {0, 0}},
{{-0.5, -0.5, 0.01}, {1, 1, 1, 1}, {0, 1}},
};
//@add
const GLubyte Indices2[] = {
1, 0, 2, 3
};
@implementation OpenGLView
....
// step02
- (void)setupVBOs
{
/*
GLuint vertexBuffer;
// Create a new Vertex Buffer object
glGenBuffers(1, &vertexBuffer);
// Bind "vertexBuffer" to GL_ARRAY_BUFFER
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
// Send the data over to OpenGL-land
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices), Vertices, GL_STATIC_DRAW);
GLuint indexBuffer;
// Create a new Index Buffer object
glGenBuffers(1, &indexBuffer);
// Bind "indexBuffer" to GL_ELEMENT_ARRAY_BUFFER
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
// Send the data over to OpenGL-land
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Indices), Indices, GL_STATIC_DRAW);
*/
// 原本的頂點 Buffer
glGenBuffers(1, &_vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices), Vertices, GL_STATIC_DRAW);
//原本的索引 Buffer
glGenBuffers(1, &_indexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Indices), Indices, GL_STATIC_DRAW);
// 包含魚骨的矩形之頂點 Buffer
glGenBuffers(1, &_vertexBuffer2);
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer2);
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices2), Vertices2, GL_STATIC_DRAW);
// 包含魚骨的矩形之索引 Buffer
glGenBuffers(1, &_indexBuffer2);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer2);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Indices2), Indices2, GL_STATIC_DRAW);
}
....
// step03
....
- (void)render:(CADisplayLink *)displayLink
{
....
glViewport(0, 0, self.frame.size.width, self.frame.size.height);
//@add: right after call to glViewport
// 繪製紋理前先將立方體的 vertex/index buffer 綁定
// (不能夠再假設它已設定好了)
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer);
....
}
....
// step04
....
- (void)render:(CADisplayLink *)displayLink
{
....
//@add: right before [_context presentRenderbuffer:]
//
// 綁定包含魚骨的矩形之 vertex/index buffers
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer2);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer2);
// 載入魚骨的紋理
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, _fishTexture);
glUniform1i(_textureUniform, 0);
glUniformMatrix4fv(_modelViewUniform, 1, 0, modelView.glMatrix);
// 設定屬性
glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0);
glVertexAttribPointer(_colorSlot, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*) (sizeof(float) * 3));
glVertexAttribPointer(_texCoordSlot, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*) (sizeof(float) * 7));
// 使用 GL_TRIANGLE_STRIP 來產生三角形, 可降低 index buffer 的大小.
glDrawElements(GL_TRIANGLE_STRIP, sizeof(Indices2)/sizeof(Indices2[0]), GL_UNSIGNED_BYTE, 0);
// Present the render/color buffer to the UIView's layer!
[_context presentRenderbuffer:GL_RENDERBUFFER];
}
....
3. 編譯並執行:
D. 啟用渲染效果
1. 開啓 OpenGLView.m 檔案, 修改如下:....
- (void)render:(CADisplayLink *)displayLink
{
//@add for blending
//
// 設定 blending 的規則
//
// GL_ONE:(for the source) 渲染所有來源圖片的像素.
//
// GL_ONE_MINUS_SRC_ALPHA:(for the destination)
// 渲染所有目標圖片資料, 除了已設置的來源圖片.
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
// 啟用渲染
glEnable(GL_BLEND);
....
}
備註: 關於渲染的模式, 可參考: 這篇教學文章.
2. 編譯並執行:
沒有留言:
張貼留言
注意:只有此網誌的成員可以留言。