OpenGL ES 學(xué)習(xí)筆記(2)-復(fù)雜圖形繪制

結(jié)合球體和圓環(huán),學(xué)習(xí)復(fù)雜圖形繪制

1. 球體繪制

1.1. 思路

在上一篇筆記中說(shuō)過(guò),OpenGL可以畫點(diǎn)、線和三角形,為了能讓球體有立體顯示的效果我們采用線帶(line_strip)的方式就行繪制.
要想使用OpenGL畫復(fù)雜圖形,最重要的就是分解圖形.
首先看下圖中球體:


球體

分析上面的球體, 我們可以首先對(duì)球體橫向切片,這樣就會(huì)得到若干個(gè)圓臺(tái)(頂部特殊).


圓臺(tái)

拆分圓臺(tái):


拆分圓臺(tái)

當(dāng)我們拆開(kāi)圓臺(tái)之后,在上下圓上打點(diǎn)并連線,形成帶狀:
打點(diǎn)連線

綜上,畫一個(gè)球,實(shí)際就是把球拆分成一個(gè)個(gè)帶狀拼接起來(lái)形成.

1.2. 求坐標(biāo)

通過(guò)1.1中的球體可以看出,我們無(wú)非就是求得a、b點(diǎn)坐標(biāo),然后讓OpenGL引擎畫出來(lái).
已知半徑R,橫向切片次數(shù)stack,因?yàn)樾枰獧M向切開(kāi)180°,故橫向切角步長(zhǎng)為stackStep = (π/stack).
設(shè)第i次切片,r0為圓臺(tái)的半徑
通過(guò)上述條件求出,圖中 alpha = (-π/2) + (i * stackStep);
所以, y0 = R * sin(alpha); r0 = R*cos(alpha)
接下來(lái)看圓臺(tái)的俯視圖:


圓臺(tái)俯視圖

設(shè)設(shè)第j次打點(diǎn), 打點(diǎn)次數(shù)為slice,打點(diǎn)范圍為360°,故打點(diǎn)的步長(zhǎng)為sliceStep = (2π/since);
故圖中的beta = j * sliceStep;
可輕松求得: x0和y0的坐標(biāo):
x0 = r0 * cos(beta);
z0 = r0 * sin(beta);
同樣的辦法求得b(x1,y1,z1)的坐標(biāo).

1.3. 核心代碼

通過(guò)上面分析,很容易編寫代碼:

//計(jì)算球體坐標(biāo)
float R = 0.5f;//球的半徑
int stack = 8;//水平層數(shù)
float stackStep = ((float) (Math.PI / stack));//單位角度值 180度
int slice = 12;//豎直
float sliceStep = (float) ((Math.PI*2) / slice);//水平圓遞增角度 360度

//上下兩個(gè)圓的坐標(biāo) 半徑
float r0, r1, x0, x1, y0, y1, z0, z1;
//兩個(gè)切片的夾角
float alpha0 = 0;
float alpha1 = 0;
//切片圓的角度
float beta = 0;

//頂點(diǎn)坐標(biāo)
List<Float> coords = new ArrayList<>();
//外層循環(huán) 水平切片!
for (int i = 0; i <= stack; i++) {
    alpha0 = (float) (-Math.PI/2 + (i * stackStep));
    alpha1 = (float) (-Math.PI/2 + ((i+1) * stackStep));
    y0 = (float) (R * Math.sin(alpha0));
    r0 = (float) (R * Math.cos(alpha0));

    y1 = (float) (R * Math.sin(alpha1));
    r1 = (float) (R * Math.cos(alpha1));

    //循環(huán)每一層的圓
    for (int j = 0; j <= slice * 2; j++) {
        beta = j * sliceStep;
        x0 = (float) (r0 * Math.cos(beta));
        z0 = -(float) (r0 * Math.sin(beta));

        x1 = (float) (r1 * Math.cos(beta));
        z1 = -(float) (r1 * Math.sin(beta));
        coords.add(x0);
        coords.add(y0);
        coords.add(z0);
        coords.add(x1);
        coords.add(y1);
        coords.add(z1);
    }
}
FloatBuffer fbb = BufferUtil.list2FloatBuffer(coords);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, fbb);
gl.glDrawArrays(GL10.GL_LINE_STRIP, 0, coords.size()/3);

2. 圓環(huán)繪制

2.1. 思路

如果球體的繪制屢清楚了,圓環(huán)就更不在話下了,同樣還是把圓環(huán)拆分.
如下圖所示, 圓環(huán)就是一個(gè)一個(gè)圓套在一起形成圓環(huán),我們的目標(biāo)就是求得a點(diǎn)坐標(biāo).
為了描述清楚我把圓環(huán)中的圓單獨(dú)也抽在坐標(biāo)系中.


圓環(huán)
抽離坐標(biāo)系

2.2. 求坐標(biāo)

已知條件,內(nèi)環(huán)圓半徑 r, 環(huán)中圓半徑r'.
通過(guò)2.1圖中所示:
x0 = (r + r' + r' * cos(beta)) * cos(alpha);
y0 = (r + r' + r' * cos(beta)) * sin(alpha);
z0 = r' * sin(beta).
同樣的道理再求得下一個(gè)點(diǎn)坐標(biāo).

2.3 核心代碼


//開(kāi)始畫
float Rinner = 0.2f; //內(nèi)環(huán)半徑
float Rring = 0.3f; //環(huán)半徑

int count = 20; //環(huán) 圓與圓之間的循環(huán)次數(shù)
float alphaStep = (float) ((2 * Math.PI) / count);
float alpha;

int countRing = 20;//環(huán)上圓循環(huán)次數(shù)
float betaStep = (float) ((2 * Math.PI) / countRing);
float beta;

float x0, y0, z0, x1, y1, z1;

List<Float> coordsList = new ArrayList<>();

//外層 圓與圓之間
for (int i = 0; i < count; i++) {
    alpha = alphaStep * i;

    //環(huán)上圓的點(diǎn) (需要閉合)
    for (int j = 0; j <= countRing; j++) {
        beta = betaStep * j;

        x0 = (float) ((Rinner + Rring * (1 + Math.cos(beta))) * Math.cos(alpha));
        y0 = (float) ((Rinner + Rring * (1 + Math.cos(beta))) * Math.sin(alpha));
        z0 = -(float) (Rring * Math.sin(beta));

        x1 = (float) ((Rinner + Rring * (1 + Math.cos(beta))) * Math.cos(alpha + alphaStep));
        y1 = (float) ((Rinner + Rring * (1 + Math.cos(beta))) * Math.sin(alpha + alphaStep));
        z1 = -(float) (Rring * Math.sin(beta));

        coordsList.add(x0);
        coordsList.add(y0);
        coordsList.add(z0);
        coordsList.add(x1);
        coordsList.add(y1);
        coordsList.add(z1);
    }
}

gl.glVertexPointer(3, GL10.GL_FLOAT, 0, BufferUtil.list2ByteBuffer(coordsList));
gl.glDrawArrays(GL10.GL_LINE_STRIP, 0, coordsList.size()/3);

2.4 預(yù)覽圖

效果預(yù)覽

3. 項(xiàng)目地址

GitHub: https://github.com/changer0/OpenGLDemo

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容