椿の日記

たぶんプログラムの話をします

ディフューズシェーディング

f:id:tbk:20110507150045p:image

そして何の変哲も無いディフューズシェーディング。

/*
    レイと球の交差位置取得。
*/
bool Test_Ray_Sphere( const Vector3& p0, const Vector3& v, const Sphere& s, float* out_t )
{
    Vector3 m = p0 - s.p;

    // tについての二次方程式(at^2 + 2bt + c = 0)
    float a = MathUtil::Dot( v, v );
    float b = MathUtil::Dot( v, m );
    float c = MathUtil::Dot( m, m ) - s.r * s.r;

    // 判別式を求める
    float D = b*b - a*c;

    if( D > 0 )
    {
        // 交差しているなら解を求める。レイの発射点側だけ求めればよい。
        *out_t = ( - b - sqrtf( D ) ) / a;
        return true;
    }
    else
    {
        // 交差してないか、接触なら無視。
        return false;
    }
}

/*
    RGBA値をUInt32に変換します。
 */
uint32_t FRGBAToARGB32( float r, float g, float b, float a )
{
    uint32_t ir = (uint32_t) min( 255.0f, max( 0.0f, r * 255.0f + 0.5f ) );
    uint32_t ig = (uint32_t) min( 255.0f, max( 0.0f, g * 255.0f + 0.5f ) );
    uint32_t ib = (uint32_t) min( 255.0f, max( 0.0f, b * 255.0f + 0.5f ) );
    uint32_t ia = (uint32_t) min( 255.0f, max( 0.0f, a * 255.0f + 0.5f ) );

    return (ia<<24) | (ir<<16) | (ig<<8) | ib;
}

/*
    光線追跡
 */
uint32_t TraceRay( const Vector3& p, const Vector3& d )
{
    // 球
    Sphere s( Vector3( 0, 0, 1 ), 1.0f );

    // 平行光源の定義
    Vector3 lightDirection = MathUtil::Normal( Vector3( -1, -1, 1 ) );

    // レイと衝突するか判定
    float t;

    if( Test_Ray_Sphere( p, d, s, &t ) )
    {
        Vector3 q = p + d * t;                                              // 衝突位置
        Vector3 n = MathUtil::Normal( q - s.p );                            // 衝突位置の法線
        float diffuse = max( 0, MathUtil::Dot( n, -lightDirection ) );      // ディフューズライティング

        return FRGBAToARGB32( diffuse, diffuse, diffuse, 1.0f );
    }
    else
    {
        return 0x00000080;
    }
}