最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

【Minecraft原理探索】編程繪制旋轉的方塊線框

2019-07-04 15:12 作者:Flinx_方凌旭  | 我要投稿

本文轉載自CSDN博客

原文地址:https://blog.csdn.net/qq_38069872/article/details/66473338?

B站視頻展示:https://www.bilibili.com/video/av24620355/


我對Minecraft十分熱愛,同時也對用簡單的方塊表現(xiàn)世界的原理十分好奇。各種三維軟件的原理必定特別深奧,而簡單的Minecraft蘊含簡單的原理,讓我有了一探究竟的信心。

百科中有這樣一行文字:

“游戲引擎 The Lightweight Java Game Library(LWJGL),基于OpenGL”

我搜索一番卻沒有什么收獲。


以下是我自己的思考。


假設屏幕后面的世界中有一個方塊,從眼睛(以下稱“視點”)向某一個頂點作一條射線,那么射線與屏幕的交點就是該頂點應該在屏幕上顯示的位置,我們要做的就是由該頂點的世界坐標得到它在屏幕上的xy坐標。一個明顯的事實是,一條射線經(jīng)過的任何頂點在屏幕上對應的位置相同。所以,我們可以由此得到啟發(fā),通過這條射線把頂點坐標轉換成屏幕坐標。


過程如下:

世界坐標(x,y,z)

視點相對坐標(x-x0,y-y0,z-z0)

視點相對球坐標(r,s,d)

視線球坐標(r-r0,s-s0,d)

屏幕坐標(x,y)


為了簡便,在計算時首先以視點為原點建立空間直角坐標系,將頂點坐標轉換為與視點的相對坐標,同樣地,射線的始端就位于原點。射線沒有長度,我們最關心的是它的方向,這需要兩個量來表示。一個簡單的例子是,我們玩3D游戲(這里指Minecraft)時,為了移動視角,可以將鼠標上下左右移動,對應抬頭、低頭、左轉、右轉,同時視線的方向隨之變動,我們就可以看向天球上任意一點。這表明,在空間中兩個量可以確定射線的方向————方位角、仰角。那么我們就從基礎做起吧——一個立方體線框的xuanzhua


還是為了簡便,使用左手直角坐標系,即以右、上、前作為x、y、z軸的正方向——畢竟我們看不到身后的事物。方位角以z軸正半軸為始邊,順時針旋轉為正角,逆時針旋轉為負角。過視射線作一個平面垂直于xz平面,視射線與兩平面交線的夾角就是仰角s,即視射線與它在xz平面上的投影的夾角。這里對球坐標的定義和地球經(jīng)緯度的概念差不多。


俯視坐標圖


如圖,我們以這個方塊右下角的頂點為例。首先以正方形中心為坐標原點建立極坐標系,依照定義,以x軸正半軸為始邊,逆時針旋轉為正角,順時針旋轉為負角,這就是這個方塊的自身坐標系。綠線與水平藍線的夾角即為方位角,利用三角函數(shù)求得xz坐標,然后加上正方形中心的坐標轉換為世界坐標。


以下給出球坐標的計算公式,其中距離d是用來判斷前后遮蓋的,本程序用不到。


tanr=x/z

tans=y/sqrt(x*x+z*z)

d=sqrt(x*x+y*y+z*z)


由于本程序沒有旋轉視角的功能,所以略去轉換玩家相對坐標和視線相對球坐標的過程,即視點位于世界原點,視線與z軸重合。


當最終得到方塊頂點相對于視線的球坐標后,我們就要確定這一點在屏幕上的位置。首先,我們的視線必定垂直穿過屏幕的中心,視點與屏幕四角的連線形成了一個錐體。所有位于這個錐體中的頂點都會映射在屏幕上一個確定的位置,即視線與該頂點的連線交于屏幕上的那一點。


如果屏幕是弧形的,圖形渲染就會變得十分簡單,因為屏幕中圖像隨視角變化的變化是均勻的。但我們的屏幕是平直的,所以我們還需要進一步處理。大家玩Minecraft時應該會注意到,屏幕四角的圖形好像被拉伸了一樣,我們可以畫一個圖來解釋這一現(xiàn)象。首先畫一個正方形和它的內切圓,從圓心向與你相對的那條邊作垂線,然后間隔相同的角度向兩側作射線,你會發(fā)現(xiàn)它們在正方形邊上截得的線段由中間向兩側是逐漸變長的。


公式:x=tanr*x0/2*tan(S/2)


推導過程:設視點到屏幕的距離為d,視角為S,屏幕寬度為x0,視射線與屏幕的交點到屏幕中心的距離為x,視射線與中心視線的夾角為r


tan(S/2)=(1/2*x0)/d=x0/2*d

tanr=x/d

d=x0/2*tan(S/2)=x/tanr

x=tanr*x0/2*tan(S/2)


可見,此公式是假定屏幕中心為坐標原點,因此計算結果需要加上屏幕寬度或高度的一半。但是屏幕坐標系的y軸的正方向是向下的,所以需要把頂點的屏幕y坐標乘以-1,于是我干脆把頂點的世界y坐標就以其相反數(shù)賦值。


坐標轉換的過程到此解釋完畢,下面開始動手實踐。


#include<stdio.h>

#include<math.h>

?

int main(void){

int i,j;

double xa,za,r=0;

?

struct POINT {

????double x,y,z;

int xs,ys;

};

struct POINT table[8];


for(i=0;i<4;i++){

table[i].y=20;

}

for(i=4;i<8;i++){

table[i].y=40;

}


FILE *fp=NULL;

fp=fopen("block.txt","w");


if(fp==NULL){

return -1;

}


for(j=0;j<360;j++){

xa=14.1421356*cos(r);? //? 14.1421356=20/sqrt(2)=10*sqrt(2)

za=14.1421356*sin(r);

table[0].x=xa;

table[0].z=80+za;

table[1].x=-za;

table[1].z=80+xa;

table[2].x=-xa;

table[2].z=80-za;

table[3].x=za;

table[3].z=80-xa;

table[4].x=table[0].x;

table[4].z=table[0].z;

table[5].x=table[1].x;

table[5].z=table[1].z;

table[6].x=table[2].x;

table[6].z=table[2].z;

table[7].x=table[3].x;

table[7].z=table[3].z;

?

for(i=0;i<8;i++){

table[i].xs=(int)(table[i].x*482/table[i].z);

table[i].ys=(int)(table[i].y/sqrt(table[i].x*table[i].x+table[i].z*table[i].z)*340);

fprintf(fp,"%d,%d,",table[i].xs+200,table[i].ys+100);

// fprintf(fp,"xa=%f,za=%f,r=%f,i=%d,xs=%d,ys=%d\n",xa,za,r,i,table[i].xs,table[i].ys);

}


r+=0.0174532;? //? 0.0174532=2pi/360

}


fclose(fp);

fp=NULL;


return 0;

}

由于我現(xiàn)在只會寫字符模式程序,對顯示圖形束手無策,所以我使用haribote操作系統(tǒng)(見于《30天自制操作系統(tǒng)》)的API來完成圖形顯示。以下程序中用block.txt的內容為數(shù)組p賦值。

#include "apilib.h"

?

int p[360*16]={};

?

void HariMain(void){

int win,buf,timer,i=0;

api_initmalloc();

buf = api_malloc(150 * 50);

win = api_openwin(buf, 512, 384, -1, "block");

api_boxfilwin(win+1, 5, 24, 506, 378, 0);

timer = api_alloctimer();

api_inittimer(timer, 128);


for (;;) {

api_boxfilwin(win+1, 5, 24, 506, 378, 0);


api_linewin(win+1,p[i],p[i+1],p[i+2],p[i+3],3);

api_linewin(win+1,p[i+2],p[i+3],p[i+4],p[i+5],4);

api_linewin(win+1,p[i+4],p[i+5],p[i+6],p[i+7],5);

api_linewin(win+1,p[i+6],p[i+7],p[i],p[i+1],6);


api_linewin(win+1,p[i+8],p[i+9],p[i+10],p[i+11],7);

api_linewin(win+1,p[i+10],p[i+11],p[i+12],p[i+13],8);

api_linewin(win+1,p[i+12],p[i+13],p[i+14],p[i+15],9);

api_linewin(win+1,p[i+14],p[i+15],p[i+8],p[i+9],10);


api_linewin(win+1,p[i],p[i+1],p[i+8],p[i+9],11);

api_linewin(win+1,p[i+2],p[i+3],p[i+10],p[i+11],12);

api_linewin(win+1,p[i+4],p[i+5],p[i+12],p[i+13],13);

api_linewin(win+1,p[i+6],p[i+7],p[i+14],p[i+15],14);


api_refreshwin(win, 5, 24, 506, 378);


api_settimer(timer, 1);

i+=16;

if(i>=360*16){

i-=360*16;

}


if (api_getkey(1) != 128) {

api_end();

}

}

}

QEMU內截圖

下一步是改進api_linewin,加入抗鋸齒功能,然后再編寫一個填充不規(guī)則四邊形的API。還需繼續(xù)努力!

---------------------?

作者:Flinx_方凌旭?

來源:CSDN?

原文:https://blog.csdn.net/qq_38069872/article/details/66473338?

版權聲明:本文為博主原創(chuàng)文章,轉載請附上博文鏈接!

【Minecraft原理探索】編程繪制旋轉的方塊線框的評論 (共 條)

分享到微博請遵守國家法律
蓬莱市| 金乡县| 凤台县| 红河县| 句容市| 朔州市| 和政县| 武功县| 峨眉山市| 武冈市| 会东县| 临清市| 高要市| 南丹县| 台江县| 福州市| 务川| 涟源市| 巩义市| 济源市| 利津县| 渭源县| 广汉市| 嘉祥县| 罗定市| 西华县| 青岛市| 仁布县| 奉化市| 措勤县| 云浮市| 东安县| 榆树市| 济源市| 诸城市| 仙游县| 怀集县| 绥中县| 宝丰县| 昌江| 四子王旗|