本文由zhangbaochong原創,轉載請注明出處http://www.cnblogs.com/zhangbaochong/p/5751111.html
由於開學就大四面臨找工作了,為了整理下項目,最近又把上學期練手寫的一個c++軟光柵渲染demo拿出來重新改了改,稍微優化了一下,順便增加了光照。雖然寫的比較簡單,但還是拿出來分享一下,希望能起個拋磚引玉的作用吧,也歡迎指點批評O(∩_∩)O~
(ps :項目代碼只有4000行左右,性能方面也比較渣,高性能的光柵渲染可以看空明大大的SALVIAhttp://www.cnblogs.com/lingjingqiu/)
1.主要模塊功能
1.1數學庫
向量、矩陣的實現與變換(矩陣平移、旋轉、轉置、行列式、逆矩陣);
視角矩陣、投影矩陣和屏幕坐標轉換矩陣;
一些常用函數(插值、RGB顏色轉UINT、角度弧度轉換、求反射向量).
1.2后緩沖區
設置像素,我一開始采用SetPixel()函數,發現速度慢的不忍直視。后來改成用CreateDIBSections創建位圖,直接向內存中寫像素顏色值,完了后一塊BitBlt到窗口就行了。
1.3模型標准
由於之前一直在寫directx11的代碼,所以這里也采用標准d3d的坐標模型,左手系+world view proj三矩陣
1.4幾何階段
頂點從模型空間到世界空間到相機空間到齊次裁剪空間,對應的主要是三個矩陣world view proj,數學庫中提供了相應方法。
圖元裝配,也就是將頂點以一定順序組裝成三角形,本項目中采用頂點索引的方式來組織頂點,並且三角形順時針順序對應的法線朝向外面。之所以規定好順序,是為了法線方向的一致性,只有這樣才能進行后面的背面消隱。
投影后的坐標再進行透視除法,讓頂點坐標位於cvv中(x[-1,1],y[-1,1],z[0,1]),裁剪過后再將cvv坐標轉化為屏幕中對應的坐標。
1.4三角形光柵化
線框模型使用的bresenham畫線算法。
三角形光柵算法:http://blog.csdn.net/cppyin/article/details/6232453
填充三角形使用的掃描線。
1.5背面消隱
可以參考:http://blog.csdn.net/cppyin/article/details/6207206
1.6簡單CVV裁剪
1.7支持紋理
紋理uv坐標同d3d,紋理坐標尋址同d3d的wrap方式,貼圖在物體表面重復,類似於我們設置桌面是圖片的平鋪方式。當坐標大於1時,通過去掉整數部分,根據得到的小數部分來得到紋理值;坐標小於0,則加上一個最小正數,讓坐標大於0。
1.8簡單光照
phong光照模型,實現平行光、點光源與聚光燈三種。
1.9簡單着色器
寫了一個着色器類,有VS和PS兩個函數對應頂點着色器和像素着色器,部分代碼如下:

1 VertexOut BoxShader::VS(const VertexIn& vin) 2 { 3 VertexOut out; 4 out.posH = vin.pos * m_worldViewProj; 5 6 out.posTrans = vin.pos * m_world; 7 out.normal = out.normal * m_worldInvTranspose; 8 9 out.color = vin.color; 10 out.tex = vin.tex; 11 12 return out; 13 } 14 15 ZCVector BoxShader::PS(VertexOut& pin) 16 { 17 //單位化法線 18 pin.normal.Normalize(); 19 20 //紋理采樣 21 ZCVector texColor = m_tex.Sample(pin.tex); 22 23 //頂點到觀察點向量 24 ZCVector toEye = (m_eyePos - pin.posTrans).Normalize(); 25 26 //初始化顏色值全部為0 27 ZCVector ambient(0.f, 0.f, 0.f, 0.f); 28 ZCVector diffuse(0.f, 0.f, 0.f, 0.f); 29 ZCVector specular(0.f, 0.f, 0.f, 0.f); 30 31 //光源計算后得到的環境光、漫反射 、高光 32 ZCVector A, D, S; 33 34 Lights::ComputeDirectionalLight(m_material, m_dirLight, pin.normal, toEye, A, D, S); 35 36 ambient = ambient + A; 37 diffuse = diffuse + D; 38 specular = specular + S; 39 40 41 //紋理+光照計算公式: 紋理*(環境光+漫反射光)+高光 42 ZCVector litColor = texColor * (ambient + diffuse) + specular; 43 44 //最終顏色透明度使用漫反射光的透明度 45 litColor.w = m_material.diffuse.w * texColor.w; 46 47 return litColor; 48 }
2.截圖效果
2.1線框模型
2.2頂點色
2.3紋理+光照
圖片本身是木紋材質,顯得比較粗糙/(ㄒoㄒ)/~~
3.源碼
項目托管到Github上了:https://github.com/zhangbaochong/Tiny3D
等有時間我會再優化一下,比如采用SIMD加速等等。最近應該沒時間搞這個了,d3d最近都沒怎么看,為了開學找工作得把算法數據結構再復習下!