光暈效果實現和3D流水線的思考

2021-09-06 04:37:44 字數 4843 閱讀 3069

最近在看阿哲的《3d地形製作全攻略》,寫得很好,但是好像網上找不到原始碼,本來想加qq請教一下,不過貌似被拒絕了。。。

按照書上的方法想做乙個光暈效果,看著其實還是不難,但是動手實現的時候還是遇到了麻煩,特別是進行世界座標->視角轉換->投影轉換->視口轉換的時候,理解起來還是費了一番功夫。

就此總結一下。

首先說一下光暈實現的思路,就是在世界座標系中確定太陽的位置,然後通過視角轉換->投影轉換->視口轉換,變換到螢幕座標,結算其與螢幕中心的連線,在這條直線上面貼上光暈的貼圖,光暈的alpha值由太陽(螢幕座標)到螢幕邊界的距離決定,開啟alpha融合渲染。

基本思想並不難理解,難點在於蘊含在視角轉換->投影轉換->視口轉換中的3d數學知識。

舉例說明:

視角矩陣形如:

-1,0,0,0

0,1,0,0

0,0,-1,0

0,-3347,300,1

視角變換是將攝像機變換到世界座標系的原點,並將其旋轉使攝像機的光軸與世界座標系z軸方向一致。同時,世界空間中的所以幾何體都隨著攝像機一同進行變換,以保證攝像機的視場恆定。

投影矩陣:

1.81,0,0,0

0,2.4,0,0

0,0,1,1//注意這一行的最後乙個1

0,0,-1,0

投影變換(透視投影),投影變換後,所以的點都被投影到x[-1,1]、y[-1,1],z[0,1]的範圍。

投影變換定義了視域體,並負責將視域體中的幾何體投影到投影視窗中。

視口矩陣:

m_screenwidth/2, 0, 0, 0,

0, -m_screenheight/2, 0, 0,

0, 0, 1, 0,

m_screenwidth/2, m_screenheight/2, 0, 1

視口變換的任務是將頂點座標從投影視窗轉換到螢幕的乙個矩形區域。

下面我們把轉換之前的點定為(0,3700,-2000,1)(x,y,z,w)

依次進行視角變換->投影變換

視角變換後,w的值依然為1

然後進行投影變換,

可以注意到投影變換後w的值由視角變換的結果的z分量決定,即w=z(視角變換後的z)*1;而這個z的幾何意義又是什麼呢?我們知道,視角變換後攝像機被移到座標系原點,鏡頭變換為面朝z的正方向,這時z如果為負值,不就是說明這個點在攝像機的後面不可見嗎?

下面繼續進行變換,上面說到投影變換後w的值由視角變換的結果的z分量決定,也就是說它跟z的符號相同,如果z為負,w也為負,說明是從背面投影過來,w為正是從正面投影到投影平面。

在光暈的實現中,太陽可能會從攝像機背面投影在z=1的平面上,這時w為負,這時候是不應該渲染光暈的。需要剪裁掉,所以渲染的條件為w>=0.0f

下面給出計算太陽螢幕座標的**和光暈渲染**:

計算太陽螢幕座標:

void chalomanager::computesuninscreen()

渲染光暈

void chalomanager::render()

else

if(m_x>m_screenwidth)

else

int iawayy;

if(m_y<0)

else

if(m_y>m_screenheight)

else

float faway=float((iawayx>iawayy)?iawayx:iawayy);

if(faway>m_border)return;//

m_border為邊界距離

float realintensity=1.0f-(faway/m_border);//

亮度int centerofscreenx=m_screenwidth/2;

int centerofscreeny=m_screenheight/2;

int dx=centerofscreenx-m_x;

int dy=centerofscreenx-m_y;

//計算頂點位置,顏色,以及光暈的大小

stscrvertex* v;

m_vertexbuffer->lock( 0, (int)m_halolist.size()*6*sizeof(stscrvertex), (void**)&v, 0);

for(int i=0;iint centerofhalox=centerofscreenx-(float)(dx*m_halolist[i].getpos());

int centerofhaloy=centerofscreeny-(float)(dy*m_halolist[i].getpos());

int halosize=m_screenwidth*m_halolist[i].getsize()/2;

//更新光暈的亮度

d3dxcolor color = m_halolist[i].getcolor();

color.a *= realintensity;

if (color.a > 1.0f) color.a = 1.0f;

if (color.a < 0.0f) color.a = 0.0f;

v->_color=color;

v->_rhw=1.0f;

v->_x=(float)(centerofhalox-halosize);

v->_y=(float)(centerofhaloy-halosize);

v->_z=0.0f;

v->_tu=0.0f;

v->_tv=0.0f;

v++;

v->_color=color;

v->_rhw=1.0f;

v->_x=(float)(centerofhalox+halosize);

v->_y=(float)(centerofhaloy-halosize);

v->_z=0.0f;

v->_tu=1.0f;

v->_tv=0.0f;

v++;

v->_color=color;

v->_rhw=1.0f;

v->_x=(float)(centerofhalox+halosize);

v->_y=(float)(centerofhaloy+halosize);

v->_z=0.0f;

v->_tu=1.0f;

v->_tv=1.0f;

v++;

v->_color=color;

v->_rhw=1.0f;

v->_x=(float)(centerofhalox-halosize);

v->_y=(float)(centerofhaloy-halosize);

v->_z=0.0f;

v->_tu=0.0f;

v->_tv=0.0f;

v++;

v->_color=color;

v->_rhw=1.0f;

v->_x=(float)(centerofhalox+halosize);

v->_y=(float)(centerofhaloy+halosize);

v->_z=0.0f;

v->_tu=1.0f;

v->_tv=1.0f;

v++;

v->_color=color;

v->_rhw=1.0f;

v->_x=(float)(centerofhalox-halosize);

v->_y=(float)(centerofhaloy+halosize);

v->_z=0.0f;

v->_tu=0.0f;

v->_tv=1.0f;

v++;

}m_vertexbuffer->unlock();

//設定融合

m_device->setrenderstate( d3drs_alphablendenable, true );

m_device->setrenderstate(d3drs_srcblend, d3dblend_srcalpha);

m_device->setrenderstate(d3drs_destblend, d3dblend_one);

m_device->settexturestagestate(0, d3dtss_alphaarg1, d3dta_texture);

m_device->settexturestagestate(0, d3dtss_alphaarg2, d3dta_diffuse);

m_device->settexturestagestate(0, d3dtss_alphaop, d3dtop_modulate);

m_device->settexturestagestate(0, d3dtss_colorarg1, d3dta_diffuse);

m_device->settexturestagestate(0, d3dtss_colorarg2, d3dta_texture);

m_device->settexturestagestate(0, d3dtss_colorop, d3dtop_modulate);

//m_device->setmaterial(&m_mtrl);

//這句好像沒有什麼用

m_device->setfvf(d3dfvf_halo);

m_device->setstreamsource(0, m_vertexbuffer, 0, sizeof(stscrvertex));

for (int n=0; n < m_halolist.size(); n++)

m_device->setrenderstate( d3drs_alphablendenable, false);

}}

吃了今天的苦頭,我知道了想要走得更遠,基礎很重要呀。真的有必要軟體實現一次3d流水線。

transform的3D效果實現

原理 構建乙個立方體,四方體共有六個面,採用定位及其位移旋轉實現。css樣式 rect wrap 容器 container 立方體的每個面 slide slide img 實現方法,六個面重疊,以前面的乙個面為準,向前移動200px,向後沿著z軸移動200px構建前後面 左右各沿著y軸旋轉90度,前...

對3D渲染管線(渲染流水線)的理解

渲染管線的概念 3d渲染管線也稱為渲染流水線,可以將其理解為乙個流程,就是我們準備一些資料,讓gpu對這些資料做一些處理,最後得出一張二維影象,渲染流程主要分為幾個大的階段 資料準備階段,頂點處理階段,光柵操作階段,畫素著色階段。一 資料準備階段 該階段主要是根據使用者提供的頂點及索引資訊,構建多邊...

D3D 9和D3D 11繪製流水線對比

繪製流水線 pipline 是圖形學程式設計中屬於各種圖形學框架的骨架。windows平台下3d遊戲開發幾乎都會用到d3d來進行遊戲引擎的設計。d3d 9是使用比較廣泛的乙個版本,d3d 9 中比較核心的就是固定渲染管線 fixed function pipline 下圖是從官方的sdk中翻譯的,從...