椿の日記

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

影を追加する

f:id:tbk:20110507170504p:image

シャドウバッファとかの元になってるやつ。流石にCPUの手抜き実装だとらくちんですね…

/*
    レイと球の交差位置取得。
*/
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 )
    {
        // 交差しているなら解を求める。レイの発射点側だけ求めればよい。
        float t = ( - b - sqrtf( D ) ) / a;;

        if( t > 0 )
        {
            // レイの発射後の位置なら衝突している
            *out_t = t;
            return true;
        }
        else
        {
            // レイの発射前の位置で衝突している
            return false;
        }
    }
    else
    {
        // 交差してないか、接触なら無視。
        return false;
    }
}

/*
    光線追跡
 */
uint32_t TraceRay( const Vector3& p, const Vector3& d, const Scene& scene )
{
    const float epsilon = 0.000001f;

    // レイと衝突するか判定
    Contact contact;

    if( Test_Ray_Scene( p, d, scene, &contact ) )
    {
        float sum = 0;

        for( std::vector<Vector3>::const_iterator it = scene.directionalLights.begin(); it != scene.directionalLights.end(); ++it )
        {
            // ディフューズライティング
            float diffuse = max( 0, MathUtil::Dot( contact.n, -*it ) );

            // 光源方向にレイをキャスト
            Contact contact2;

            if( Test_Ray_Scene( contact.p + contact.n * epsilon, -*it, scene, &contact2 ) )
            {
                // もし光源方向にオブジェクトがあるなら影になる
                sum += 0.5f * diffuse;
            }
            else
            {
                // もし光源方向にオブジェクトがないなら直接ライティング
                sum += diffuse;
            }
        }

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