球體的渲染效果比較突出爽航,所以本主題完成一個球體的繪制彪见,并利用一些基本的渲染技巧實現(xiàn)渲染。
??1. 球體繪制的數(shù)學(xué)模型嘉竟;
??2. 球體繪制的實現(xiàn);
??3. 球體的渲染的改進效果;
球體繪制的數(shù)學(xué)模型
球體繪制的數(shù)學(xué)模型
-
第一步:計算z坐標(biāo)
- 球面繪制舍扰,首先按z方向倦蚪,切分成多節(jié),每節(jié)就是一個圓周边苹;就是上圖的1截出來的部分就是2所示的圓周陵且。
- 截出的圓周有一個高,就是z-坐標(biāo)个束;
- 圓周的高慕购,其實就是這個圓周與圓心形成的錐形的角度決定了圓周的截斷高度。這樣可以輕松計算出
-
第二步:等高截的圓周的半徑r
- 這個圓周半徑也容易計算
- 這個圓周半徑也容易計算
-
第三步:計算圓周上的x茬底,y
- 圓周半徑確定的情況下沪悲,x,y容易計算
- 圓周半徑確定的情況下沪悲,x,y容易計算
代碼實現(xiàn)
線計算u桩警,v確定下的球面點坐標(biāo)
- 代碼中添加了一個球面總得半徑可训,這個半徑不影響上面的球面坐標(biāo)的計算原理,但決定了球的大小捶枢。
glm::vec3 getPoint(GLfloat u, GLfloat v){
GLfloat r = 0.9f;
GLfloat pi = glm::pi<GLfloat>();
GLfloat z = r * std::cos(pi * u);
GLfloat x = r * std::sin(pi * u) * std::cos(2 * pi * v);
GLfloat y = r * std::sin(pi * u) * std::sin(2 * pi * v);
// std::cout << x << "," << y << "," << z << std::endl;
return glm::vec3(x, y, z);
}
循環(huán)u握截,v計算球面上的多個點
- 注意:
- u的取值區(qū)間
[0,180]
,v的取值區(qū)間[0,360]
烂叔。 - 計算的4個點谨胞,形成兩個三角形的6個點。
- 我們假設(shè)u蒜鸡,v是
[0, 1]
胯努,然后轉(zhuǎn)換為[0, 180]
與[0, 360]
。 - 計算出來的點放入數(shù)組(其中內(nèi)存拷貝的時候逢防,內(nèi)存地址的偏移基本單位與指針類型有關(guān))
- u的取值區(qū)間
void createSphere(GLfloat *sphere, GLuint Longitude, GLuint Latitude){
// Longitude:經(jīng)線切分個數(shù)
// Latitude:緯線切分個數(shù)
GLfloat lon_step = 1.0f/Longitude;
GLfloat lat_step = 1.0f/Latitude;
GLuint offset = 0;
for(int lat = 0; lat < Latitude; lat++){ // 緯線u
for(int lon = 0;lon < Longitude; lon++){ // 經(jīng)線v
// 一次構(gòu)造4個點叶沛,兩個三角形,
glm::vec3 point1 = getPoint(lat * lat_step, lon * lon_step);
glm::vec3 point2 = getPoint((lat + 1) * lat_step, lon * lon_step);
glm::vec3 point3 = getPoint((lat + 1) * lat_step, (lon + 1) * lon_step);
glm::vec3 point4 = getPoint(lat * lat_step, (lon + 1) * lon_step);
memcpy(sphere + offset, glm::value_ptr(point1), 3 * sizeof(GLfloat));
offset += 3;
memcpy(sphere + offset, glm::value_ptr(point4), 3 * sizeof(GLfloat));
offset += 3;
memcpy(sphere + offset, glm::value_ptr(point3), 3 * sizeof(GLfloat));
offset += 3;
memcpy(sphere + offset, glm::value_ptr(point1), 3 * sizeof(GLfloat));
offset += 3;
memcpy(sphere + offset, glm::value_ptr(point3), 3 * sizeof(GLfloat));
offset += 3;
memcpy(sphere + offset, glm::value_ptr(point2), 3 * sizeof(GLfloat));
offset += 3;
}
}
// std::cout<<"offset:" << offset << std::endl;
}
調(diào)用代碼
- 其中z等分忘朝,這里定義為:
- GLuint lats = 30;
- 每個圓周上的點的個數(shù)定義為:
- GLuint lons = 60;
GLfloat vertices[6 * 3 * lats * lons ];
std::cout<< "total:" << sizeof(vertices) << std::endl;
createSphere(vertices, lons, lats);
data.addData(vertices, sizeof(vertices), 0, 3); // 開啟Shader第一個參數(shù)位置灰署,頂點3個一組。
- 頂點著色器是缺省的
- 其中添加了簡單的世界坐標(biāo)變換mode局嘁,照相機坐標(biāo)view溉箕,與透視變換perspective。
#version 410 core
layout (location = 0) in vec3 aPos;
uniform mat4 model;
uniform mat4 view;
uniform mat4 perspective;
void main(){
gl_Position = perspective * view * model * vec4(aPos, 1.0);
}
- 片著色器是缺省的
#version 410 core
out vec4 FragColor;
void main(){
FragColor = vec4(1.0f, 0.0f, 0.0f, 1.0f);
}
- 效果- 繪制方式:
glDrawArrays(GL_LINE_LOOP, 0, 6 * lats * lons);
球體的網(wǎng)格線繪制
- 效果-繪制方式:
glDrawArrays(GL_POINTS, 0, 6 * lats * lons);
球體的網(wǎng)格點繪制
- 效果-繪制方式:
glDrawArrays(GL_TRIANGLES, 0, 6 * lats * lons);
球體的三角面繪制
改進與變化
顏色
- 使用球面坐標(biāo)作為顏色
GLfloat vertices[6 * 3 * lats * lons ];
std::cout<< "total:" << sizeof(vertices) << std::endl;
createSphere(vertices, lons, lats);
data.addData(vertices, sizeof(vertices), 0, 3); // 開啟Shader第一個參數(shù)位置悦昵,頂點3個一組蒿赢。
// 直接使用切面坐標(biāo)做顏色坐標(biāo)
data.addData(vertices, sizeof(vertices), 1, 3); // 開啟Shader第一個參數(shù)位置互捌,頂點3個一組。
- 效果:代碼中做了一個Model的縮小矩陣變換
model = glm::scale(model, glm::vec3(0.5f, 0.5f, 0.5f));
球體的顏色渲染
紋理
- 頂點著色器
#version 410 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
uniform mat4 model;
uniform mat4 view;
uniform mat4 perspective;
out vec4 vColor;
void main(){
vColor = vec4(aColor, 1.0f);
gl_Position = perspective * view * model * vec4(aPos, 1.0);
}
- 片著色器
#version 410 core
uniform sampler2D aTexture;
out vec4 FragColor;
in vec4 vColor;
void main(){
// FragColor = vColor;
vec2 vTexture = vec2(vColor.x, vColor.y); // 因為x,y有正負(fù),這個這里不處理,就形成對稱紋理效果
FragColor = texture(aTexture, vTexture) * vColor;
}
- 紋理添加代碼
///////////////////////////////////////////////////
// 添加紋理對象
GLint w = 0, h = 0, d = 0;
data.addTexture("texture.png",&w, &h, &d);
///////////////////////////////////////////////////
shader.initProgram();
shader.compileShaderFromFile("./glsl_script/glsl04_v_sphere_texture.glsl", GL_VERTEX_SHADER);
shader.compileShaderFromFile("./glsl_script/glsl04_f_sphere_texture.glsl", GL_FRAGMENT_SHADER);
shader.link();
shader.setUniform_1i("aTexture",0);
-
效果
球體的紋理渲染