とりあえずレイトレース
http://d.hatena.ne.jp/mokehehe/20090716/raytracer
こちらの記事を参考にしながら、レイトレースの実験を開始しました。記事に習って、レイが正しく飛ばせているかどうかの実験からです…。
そういえば、初めてDirect2D使った。意外に便利かも。ウィンドウ作ってHWNDを渡すだけなんで、こういう用途に使うなら凄く便利です。(RenderTarget作るところとかのソースは乗せてないが)
#include "stdafx.h" #include "vector.h" /* 直線と球の交差判定。 球面方程式 || p - c || = r 直線方程式 p = p0 + vt pについて代入してtについて解くと得られる。 */ bool Intersect_Line_Sphere( const Vector3& p0, const Vector3& v, const Sphere& s ) { Vector3 m = p0 - s.p; // tについての二次方程式 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; // 交差してるなら解が2つ。接してるなら解が1つ。交差してなければ解0。 return D > 0; } /* 光線追跡 */ uint32_t TraceRay( const Vector3& p, const Vector3& d ) { // シーンとして球を1つ置いてみる Sphere s( Vector3( 0, 0, 1 ), 1.0f ); // 直線が衝突したら白、しなければ黒 if( Intersect_Line_Sphere( p, d, s ) ) { return 0xffffffff; } else { return 0x00000000; } } /* 画像を作成する 視点から原点方向を向き、垂直視野角alpha、アスペクト比aspectで視野を作る。 そしてxy平面(z=0)に像を作る。 像とピクセルの中心が対応する点に対して光線を追跡する。 */ void RenderImage( uint32_t width, uint32_t height, uint32_t* image ) { float e = 1; Vector3 eye( 0, 0, -e ); // 視点 float aspect = (float)width / (float)height; // 垂直方向に対する水平方向のアスペクト比 float alpha = PI / 4; // 垂直視野角 float h2 = sinf( alpha ) * e; // 縦方向の像の大きさ/2 float w2 = h2 * aspect; // 横方向の像の大きさ/2 // 矩形の中を(width,height)の大きさで分割します for( uint32_t j = 0; j < height; j++ ) { for( uint32_t i = 0; i < width; i++ ) { // 各ピクセルの中心への方向ベクトルを求める float px = ( ( (float)i + 0.5f ) / (float)width - 0.5f ) * w2 * 2; float py = -( ( (float)j + 0.5f ) / (float)height - 0.5f ) * h2 * 2; Vector3 p( px, py, 0 ); Vector3 d = MathUtil::Normal( p - eye ); // その方向に向けて光線追跡して色を回収 image[j*width + i] = TraceRay( eye, d ); } } } /* シーンの描画 画像作ってビットマップオブジェクト作って全画面貼り付け */ void RenderScene( ID2D1HwndRenderTarget* pRenderTarget ) { HRESULT hr; D2D1_SIZE_U size = pRenderTarget->GetPixelSize(); ID2D1Bitmap* pBitmap; uint32_t* image = new uint32_t[size.width * size.height]; RenderImage( size.width, size.height, image ); D2D1_PIXEL_FORMAT pixelFormat = D2D1::PixelFormat( DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE ); hr = pRenderTarget->CreateBitmap( size, image, size.width * sizeof(uint32_t), D2D1::BitmapProperties( pixelFormat ), &pBitmap ); if( FAILED(hr) ) { pRenderTarget->Clear(); } else { pRenderTarget->DrawBitmap( pBitmap ); } delete [] image; } void Render( ID2D1HwndRenderTarget* pRenderTarget ) { pRenderTarget->BeginDraw(); RenderScene( pRenderTarget ); pRenderTarget->EndDraw(); }