2010-08-31

擷取 std::cout 字串

std::cout 方便我們把資料列印到 console 視窗,擷取這些字串可以拿來做其它用途,例如另存成 Log file、以其它方式顯示等...。底下的方法是當 cout 呼叫時, 會將 cout 的字串以 callback 的方式傳給 callback function。

1. 建立 cout wrapper class 繼承
std::basic_streambuf< char, std::char_traits< char > >

2. 在 class 的 constructor 加入(其中  m_pBuf 為暫存的 cout buffer):
m_pBuf = std::cout.rdbuf( this );

3.在 class 的 destructor 加入下列(還原原來的 cout buffer):
m_Stream.rdbuf( m_pBuf );

4. 利用此 class override 兩個 function 分別為 xsputn 及 overflow:
/**
* Override xsputn and make it forward data to the callback function.
*/
std::streamsize xsputn( const char* _Ptr, std::streamsize _Count )
{
 m_pCbFunc( _Ptr, _Count ); //m_pCbFunc 為使用者定義的 callback function
 return _Count;
}

/**
* Override overflow and make it forward data to the callback function.
*/
std::char_traits< char >::int_type overflow( std::char_traits< char >::int_type v )
{
 char ch = std::char_traits< char >::to_char_type( v );
 m_pCbFunc( &ch, 1 ); //m_pCbFunc 為使用者定義的 callback function

 return std::char_traits< char >::not_eof( v );
}

5. 程式建立此 class 之後,所有的 cout 呼叫都會將字串以 callback 方式傳給使用者定義的 callback function 了!

2010-08-25

在 Unity 3D 裡用 C# Script 產生 Mesh

首先建立一個 C# Script,這裡取名為 SimpleRect.cs,其內容如下(特別注意的是 class name 必須與檔名相同):
using UnityEngine;
using System.Collections;

public class SimpleRect : MonoBehaviour {

    // Use this for initialization
    void Start () {

        Mesh pm = new Mesh();
        pm.Clear();
        
        Vector3[] verts = new Vector3[4];
        verts[0].x = -0.5f;
        verts[0].y = 0.0f;
        verts[0].z = 0.5f;

        verts[1].x = 0.5f;
        verts[1].y = 0.0f;
        verts[1].z = 0.5f;

        verts[2].x = -0.5f;
        verts[2].y = 0.0f;
        verts[2].z = -0.5f;

        verts[3].x = 0.5f;
        verts[3].y = 0.0f;
        verts[3].z = -0.5f;
        pm.vertices = verts;

        int[] tris = new int[6];

        tris[0] = 0;
        tris[1] = 1;
        tris[2] = 2;
        
        tris[3] = 2;
        tris[4] = 1;
        tris[5] = 3;

        pm.triangles = tris;

        pm.RecalculateBounds();
        pm.RecalculateNormals();

        pm.Optimize();

        //建立 GameObject, 並指定 MeshFilter 的 Mesh:
        GameObject go = new GameObject();
        MeshFilter mf = go.AddComponent<meshfilter>();
        mf.mesh = pm;

        MeshRenderer mr = go.AddComponent<meshrenderer>(); 
    }

    // Update is called once per frame
    void Update () {

    }
}

082501
將 SimpleRect.cs 從 Project 拖移至 Hierarchy 視窗的 MainCamera 上


082502
點選 MainCamera 時,可看到 Inspector 裡多了 SimpleRect 的 Script


082503
此時進入 GameMode 就可以看到產生的 Rect

2010-08-10

Gamma 值的筆記

  1. PC 用的 Gamma 值多為 2.2,MAC 用的 Gamma 值為 1.8。
  2. Gamma 值套用到方程式 f(x) =pow(x, G), 其中 x 為顏色, G 為 Gamma 值。
  3. PC 螢幕顯示出來的顏色都會套用 Gamma 值 2.2,所以存在硬碟裡的圖片若是原圖(Gamma 1.0),則會偏黑。為了顯示正常的圖,儲存在硬碟裡的圖必須比較亮(Gamma 0.45)。
  4. 所有在硬碟裡的圖及乎都比較亮。(特殊圖檔除外,例:raw 檔...)
  5. 圖片計算光照的順序依序為:將圖片從硬碟取出,套用 Gamma 2.2 之後再計算光源,計算完成後套用 Gamma 0.45 ,然後再丟給螢幕顯示出來。
  6. 注意圖片取樣及寫入 framebuffer 時,硬體是否已自動做 Gamma 修正。

2010-08-05

2010-08-02

Sprite Manager for Unity3D

花兩週的時間寫一個視覺化的 Sprite 編輯器:


編輯器介面


在時間軸上新增 Sprite 圖層並設定好 keyframe 之後就可以可以編輯圖片大小, 位置, 旋轉角度, 透明度, 播放第幾個 Sprite 圖, 並且在各個 keyframe 之間自動內插產生動畫。

編輯器裡比較特殊的控制項為 時間軸控制項和編輯區域的控制項,因為 unity 沒有這些控制項,所以要自己刻出來,比較辛苦:


時間軸控制項

時間軸控制項的各個圖層皆代表一個 Sprite 圖, 深藍色的色塊代表 keyframe, 淺藍色的色塊代表自動內插並顯示的 frame,最上面的刻度軸代表目前的 frame, 紅色垂直線表示目前顯示的 frame。

編輯區控制項則是顯示及編輯目前 keyframe 裡的圖片,深藍色框線是目前遊戲的解析度,當時間軸的紅線移到內插的 frame 時, 它會及時顯示內插的結果。

接著要做的是, 滑鼠在某個 Sprite 上按下時, 產生按鈕的事件, 讓它除了能編輯 Sprite 動畫外, 還能當成基本的 GUI 編輯器。