2009年4月5日 星期日

DirectX Shader 材質

最近拿起了3ds max,玩一玩裡頭的DirectX Shader 材質。發現它其實還挺好用的。

首先先將材質換成DirectX Shader

max_1

然後材質的參數就會換成這樣的介面

max_2

第一個,DirectX Shader的欄位,可以讓我們指定使用的Fx檔案,第二個Parameters的欄位,裡面所有的參數,都是從Fx檔案裡定義的。只要照著標準的規則寫,參數便能夠列在這上面,讓製作人員去調整。同時在做模型輸出的時候,也同樣可以取得這些設定的值。

至於這些個參數是怎麼定義的,可以打開default.fx來看。


// light direction (view space)
float3 lightDir : Direction < 
    string UIName = "Light Direction";
    string Object = "TargetLight";
    > = {-0.577, -0.577, 0.577};
// material reflectivity
float4 k_a  <
    string UIName = "Ambient";
    > = float4( 0.47f, 0.47f, 0.47f, 1.0f );    // ambient
float4 k_d  <
    string UIName = "Diffuse";
    > = float4( 0.47f, 0.47f, 0.47f, 1.0f );    // diffuse
float4 k_s  <
    string UIName = "Specular";
    > = float4( 1.0f, 1.0f, 1.0f, 1.0f );    // specular
int n<
    string UIName = "Specular Power";
    string UIType = "IntSpinner";
    float UIMin = 0.0f;
    float UIMax = 50.0f;   
    >  = 15;

這個程式的語法,稱做 DirectX Standard Annotations and  Semantics,角括號裡面的字串以及其它變數的宣告,在Effect Fx中是沒有作用的,但是,在max中,就定義了Parameters的參數介面。

除了在DirectX SDK中有文件說明,max的網站上也可以下載到相關的文件(不過版本很舊了)。

用DirectX Shader材質有兩個好處,一是這個Effect Fx的檔案我們可以直接在遊戲程式中使用。第二是,這個材質能夠所見即所得的顯示出來材質效果。

所以,我很認真的在考慮,也許就直接把Effect Fx檔案拿來當做引擎中的材質使用好了。

2009年3月19日 星期四

Intelligent Mistakes

Intelligent Mistakes: How to Incorporate Stupidity Into Your AI Code

by Mick West

===================================================

每天看Gamasutra,偶爾會看到一些好東西。

這個主題叫做「有智慧的錯誤」。

人都是會出錯的,所謂「人有失手,馬有亂蹄」,但是電腦AI不會出錯,只有計算夠不夠完整的問題。

但是這樣的遊戲,玩起來就死板板的,也喪失了一些趣味。

作者舉了他自己做的撞球遊戲當做例子,撞球遊戲的AI不難,就是簡單物理碰撞計算而已,對電腦來說,出桿可以非常非常的精準,但是「人」就不行了,要不就打歪,要不就力道不對,總之是不可能精準的像電腦一樣。

所以,這樣的遊戲玩起來,就是跟一個精準得要命的電腦對手在玩。不但每顆球都打得很「千」,連不小心放的「嗆斯」都沒有。

這就很無趣了。

AI is “too good”.

所以,要做一些精心設計的錯誤,讓玩家覺得他佔到便宜,好比說,偶爾故意放個「嗆斯」、偶爾「突槌」一下、偶爾不小心把母球打進洞....

這樣就有趣多了,人生本來就是充滿了不確定啊....

2009年3月12日 星期四

Remote Debug

遇過這樣的狀況嗎?

『我們的程式,在自己的電腦上執行,一切正常,但是交到別人手上執行,卻常常出問題,更不要說是交給老闆測試了,老闆的電腦特別奇怪,好好的程式交給老闆就一定會出事。』

這種時候,就是放61點天賦大絕的時候了。

這個大絕叫做『遠端除錯』,Remote Debug。

概念是這樣,我們在近端--也就是我們自己的電腦--用VC或是其他的編譯工具進行除錯,程式則是在遠端電腦(也就是老闆的電腦)上執行,Trace/Debug的做法,與我們在自己的電腦上除錯是相同的,所不同的是,我們控制的是老闆電腦上的程式。

用這種方式除錯,遠端電腦上是不需要安裝任何的編譯工具的,只需要兩種東西。

一個是程式的執行檔和相關的資料檔案,另外一個就是稱做Remote Debug Server或是Remote Debug Monitor的程式。這個Remote Debug Monitor是一個很小的程式,通常放在VC或是編譯工具的安裝光碟中,請拿出來安裝在遠端電腦上。

然後,在遠端電腦先將remote debug server跑起來,等待近端的連線。

接著我們在近端電腦打開程式專案,做一些設定--每一種編譯工具的設定方式都不同,甚至不同版本的VC++都有不同的設置方式--之後,開始debug run。這時候,遠端電腦上的執行檔就會被跑起來,而所有的debug output訊息,會顯示在近端的編譯工具裡。同時,也可以設定break point,去trace 遠端電腦上的程式流程。

這樣,我們就能夠很快的發現bug,解決bug,也就不會在老闆面前滅團了。

2009年2月6日 星期五

邪惡的巨集

巨集(Macro)是邪惡的。

它很好用,可以簡化我們的程式碼,節省很多Coding的時間。

但是它暗地裡在破壞我們程式碼的物件架構,在物件封裝中到處鑽孔。

所以,前兩天,我將程式碼裡頭的

#include "windowsx.h"

給拔掉。

這個標頭檔,定義了很多巨集,有些是簡化windows訊息程式碼,有些是簡化windows API。平常是很好用的啦,但是,好死不死的,我有個樹狀結構的物件,裡頭有幾個函式-- GetFirstChild, GetNextChild, ... 就跟windows API的巨集衝突到了。

好端端擺在物件中的GetFirstChild函式,被windows API的GetFirstChild巨集取代掉,所以編譯器瞬間開始混亂,看不懂我的程式碼在幹什麼,連錯誤回報也是亂報一通不知所云。

花了時間除錯,拔掉了這些個讓人偷懶的巨集。

所以這巨集真不是好東西。

裹著糖衣的毒藥。

Code Complete的作者在書裡也有說,巨集,能不用就不用,務必謹慎使用。

是啊,別偷懶了,該拔掉的就拔掉吧。

==================================================

其實今天一早,還遇見了另一個類似的問題。

我在數學函式庫裡,定義了一個靜態常數PI (就是圓周率啦),還特別放在一個Math物件中,用Math::PI這樣的語法來存取,避免這種常數定義衝突的狀況。

class Math
{
...
static const float PI;
};

不過,又來了,好死不死,Max SDK裡面也定義了一個PI,而且是直接#define,

#define PI  ((float)3.1415926535)

結果我怎麼辦? 我只能先引入自己數學函式庫的標頭檔,然後再引入Max SDK的標頭檔,順序絕對不能換,否則編譯器就會開始錯亂。

2009年1月23日 星期五

又多了個小外甥

今天才寫,有點晚了。

一月十五日,老妹生了第二胎,是個3240克的健康胖小子。

本來,還想著要他跟姐姐一樣過完年才出來,不過這小子的確跟姐姐一樣,也是大約37週就把媽媽的營養吃完,準備出來。

也好,兩人的生日都是正月十五,姐姐是農曆,弟弟是國曆。

看起來黑黑的,似乎又是個小黑皮。

這個胖小子,也是妹妹的夫家期盼了很久的男丁,上頭已經有三個姐姐了。

昨天老妹家裡在幫小娃娃取名字,剛好在MSN上撞見,我就跟著參考了意見。

「宗」: 不要,太菜市場了。

「宸」: 網路上查了字典,這個字好。辰是龍,屋頂下的龍,表示這個字是帝王的住所,也可以引申為帝王的意思。

「菘」: 看起來不錯,仔細一查,哇咧,原來這個植物就是「白菜」。算了,還是不要這個字吧。

「瑋」、「瑜」、「瑄」: 都不錯,都是「美玉」。不過就是有點像女生的名字,轉念一想,周瑜也用這個名字啊,還好啦。

最後選了「宸瑋」兩個字。很不錯吧,帝王的美玉。

小娃娃才出生一個星期,會不會對他期望太高了? 哈....

老妹照了幾張照片,不過都有點糊,還是小小張的看就好,放大看會更糊。

照片 001

照片 002

2009年1月13日 星期二

Finding Oriented Bounding Box

前一陣子發現計算OBB的演算法,研究了幾天,本以為大致都了解了,但深入去思考推導之後,卻才發現,原來我是錯得離譜,Totally Wrong!! (翻譯叫做 "一整個錯!!")

於是又從頭開始,一步一步從數學的角度來看。

觀念還是一樣,把美術模型的每一個頂點,都當做是取樣點,然後用Least Square Fit的方法,找出OBB需要的中心點以及三個軸向。

OBB的中心點取得,根據的是偏微分取極值的方法,三個軸向呢,則是用Principal Axis的概念,從Eigen vector來取得。

底下是兩個參考資料。

http://mathworld.wolfram.com/LeastSquaresFitting.html

http://www.geometrictools.com/Documentation/LeastSquaresFitting.pdf

這個推導,背後的數學有點小複雜,不過,大概都是些矩陣向量的運算概念。

最後呢,得到一個取得OBB的步驟。

1. 先建立一個可以解出Eigen value, Eigen vector的函式庫(或者去抄一個)

2. 把所有頂點座標加起來,找出平均值,就是OBB的中心。

3. 對於每一個頂點,計算與中心點在 x,y,z 三個方向的誤差值 X,Y,Z ,取得兩兩相乘的值,XX, XY, XZ, YY, YZ, ZZ,把每個頂點所算出來的這六個值,全部加起來平均。然後塞到一個3x3的矩陣內。

4. 把這個矩陣丟給Eigen System求解,拿回三個Eigen vector。

5. 用這三個Eigen vector得到的座標系統,轉換原來的頂點,找出在這個座標系統中的Box長寬高。

2009年1月6日 星期二

數學才是王道

話說,元旦連續假日,大家都放假了,我還要上班。

把Code拿出來看看,想說處理一下引擎裡Bounding Box的計算。

找了一些Open Source的參考Code來看,想看看有沒有什麼比較有效率的演算方式來計算Bounding Box。

然後,我就愣住了。

眼前的這個演算法,把所有頂點的資料拿去算一個covariance matrix,再用這個matrix求解eigen vector以及eigen value,然後....就算出了包圍所有頂點的最佳的Oriented Bounding Box。eigen vector是OBB的三個軸向。用找到的三個軸向,來計算OBB的軸半徑。

我傻眼了。

eigen vector有那麼神嗎? 連這個都能算。還有covariance matrix究竟是什麼東西啊?

開始研究了幾天,總算是比較清楚整個運算的來龍去脈。

有時間整理出來的話,再拿來分享好了。

簡單的說,covariance matrix計算(x,y,z)數據的變異量以及彼此之間的影響,例如,x軸方向的數據,在y軸數據變動時,所受到的影響,這東西可以從最小平方差的總和,以偏微分取極值的方式導出類似的計算。

接下來這樣想,假設我們已經知道了OBB的三個軸向,我們就可以將所有的頂點(x,y,z),轉成在OBB座標系中的頂點(x',y',z'),而以(x',y',z')所計算得的covariance matrix,兩個不同的軸向(x'與y'或是 y'與z'等等...)之間的互相變異量應該是最小的,滿足這樣條件的三個軸向,就是最佳的OBB軸向。

這些計算一直演算下來,就出現了eigen value problem,所以最後eigen vector又出來幫忙,解決了問題。

好,結論。

結論就是....

數學才是王道啊!!

==========================================

Update: 原來還是看錯了,對應eigen vector的eigen value並不是軸半徑,covariance matrix只用來取得OBB的軸向。