複数のオブジェクトの表示
複数のオブジェクトを表示するので、Sceneオブジェクトを作って、最近傍衝突点を返す関数を作る。
struct Scene { std::vector<Sphere> spheres; std::vector<Plane> planes; std::vector<Vector3> directionalLights; }; struct Contact { Vector3 p; Vector3 n; float t; }; Scene CreateScene() { Sphere sphere( Vector3( 0, 0, 1 ), 1.0f ); Plane plane( Vector3( 0, 1, 0 ), -0.1f ); Vector3 directionalLight = MathUtil::Normal( Vector3( -1, -1, 1 ) ); Scene scene; scene.spheres.push_back( sphere ); scene.planes.push_back( plane ); scene.directionalLights.push_back( directionalLight ); return scene; } /* レイと平面の交差位置取得。 平面方程式 p・n = d 直線方程式 p = p0 + vt について代入してtについて解くと得られる。 */ bool Test_Ray_Plane( const Vector3& p0, const Vector3& v, const Plane& plane, float* out_t ) { float t = ( plane.d - MathUtil::Dot( p0, plane.n ) ) / MathUtil::Dot( v, plane.n ); if( t > 0 ) { *out_t = t; return true; } else { return false; } } bool Test_Ray_Scene( const Vector3& p0, const Vector3& v, const Scene& scene, Contact* out_contact ) { Contact contact; contact.t = FLT_MAX; for( std::vector<Sphere>::const_iterator it = scene.spheres.begin(); it != scene.spheres.end(); ++it ) { float t; if( Test_Ray_Sphere( p0, v, *it, &t ) ) { if( t < contact.t ) { contact.t = t; contact.p = p0 + t * v; contact.n = MathUtil::Normal( contact.p - it->p ); } } } for( std::vector<Plane>::const_iterator it = scene.planes.begin(); it != scene.planes.end(); ++it ) { float t; if( Test_Ray_Plane( p0, v, *it, &t ) ) { if( t < contact.t ) { contact.t = t; contact.p = p0 + t * v; contact.n = MathUtil::Normal( it->n ); } } } if( contact.t < FLT_MAX ) { *out_contact = contact; return true; } else { return false; } } /* 光線追跡 */ uint32_t TraceRay( const Vector3& p, const Vector3& d, const Scene& scene ) { // レイと衝突するか判定 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 ) ); // ディフューズライティング sum += diffuse; } return FRGBAToARGB32( sum, sum, sum, 1.0f ); } else { return 0x00000080; } }