3D 이미지를 화면에 뿌려보자 - 2

2018, Sep 10    

ray-casting (광선 추척법)을 이용하여 3D volume 을 rendering 해보자.

Renderer.cpp

bool Renderer::RenderVRAnyDirection(unsigned char* image,
    const int img_width, const int img_height, int DirKey)
{
    if(m_CurMode != VR) return false;

    int vol_width = m_pVolume->GetWidth();
    int vol_height = m_pVolume->GetHeight();
    int vol_depth = m_pVolume->GetDepth();

    /// 업벡터, 볼륨 센터 설정
    float3 up_vector = float3(0.f, 0.f, -1.f);
    float3 center_coord = float3(vol_width / 2.f, vol_height / 2.f, vol_depth / 2.f);

    /// 눈 좌표 회전
    float angle = 0.f;

    switch(DirKey)
    {
    case LEFT:
        angle = +10.f;
        break;
    case RIGHT:
        angle = -10.f;
        break;
    default:
        break;
    }

    angle = angle * 3.141592f / 180.f;
    float cos_ = cosf(angle);
    float sin_ = sinf(angle);
    
    float rotate_matrix[3][3] = {
        {cos_, (-1)*sin_, 0.f},
        {sin_,      cos_, 0.f},
        { 0.f,       0.f, 1.f}
    }

    float rotate_eye[3] = { m_eye_coord.x, m_eye_coord.y, m_eye_coord.z};
    rotate_eye[0] -= center_coord.x;
    rotate_eye[1] -= center_coord.y;
    rotate_eye[2] -= center_coord.z;

    float res_arr[3] = { 0.f };

    for(int i=0; i<3; i++)
    {
        float res = 0.f;
        for(int j=0; j<3; j++)
            res = res + rotate_eye[j] * rotate_matrix[i][j];
        
        res_arr[i] = res;
    }

    res_arr[0] += center_coord.x;
    res_arr[1] += center_coord.y;
    res_arr[2] += center_coord.z;

    m_eye_coord.x = res_arr[0];
    m_eye_coord.y = res_arr[1];
    m_eye_coord.z = res_arr[2];

    /// 뷰 벡터 계산
    float3 view_vector = center_coord - m_eye_coord;
    view_vector.normalize();

    /// x 벡터 계산
    float3 x_vector = cross(view_vector, up_vector);
    x_vector.normalize();

    /// y 벡터 계산
    float3 y_vector = cross(view_vector, x_vector);
    y_vector.normalize();

    for(int j=0; j< img_height; j++)
    {
        for(int i=0; i<img_width; i++)
        {
            /// 시작좌표 계산
            float3 cur_coord = m_eye_coord + x_vector*(i - img_width/2) + y_vector*(j - img_height/2);

            float t[2] = { 0.f };
            GetRayBound(t, cur_coord, view_vector);

            float color[3] = { 0.f };
            float alpha = 0.f;

            for(float k = t[0]; k < t[1]; t+=1.f)
            {
                float3 adv_coord = cur_coord + view_vector * k;
                if(adv_coord.x >= 0.f && adv_coord.x < vol_width   &&
                   adv_coord.y >= 0.f && adv_coord.y < vol_height  &&
                   adv_coord.z > =0.f && adv_coord.z < vol_depth )
                   {
                       int intensity = m_pVolume->GetVoxel(static_cast<int>(adv_coord.x),static_cast<int>(adv_coord.y), static_cast<int>(adv_coord.z));
                       float cur_blue = m_pTF->GetPalleteCValue(0, intensity);
                       float cur_green = m_pTF->GetPalleteCValue(1, intensity);
                       float cur_red = m_pTF->GetPalleteCValue(2, intensity);
                       float cur_alpha = m_pTF->GetPalleteAValue(intensity);

                       color[0] += (1.f - alpha)* cur_blue * cur_alpha;
                       color[1] += (1.f -alpha) * cur_green * cur_alpha;
                       color[2] += (1.f -alpha) * cur_red * cur_alpha;
                       alpha += (1.f - alpha) * cur_alpha;

                       if (alpha > 0.95f) break;
                   }
            }
            image[(img_width*j + i) * 3 + 0] = color[0];
            image[(img_width*j + i) * 3 + 1] = color[1];
            image[(img_width*j + i) * 3 + 2] = color[2];
        }
    }
    return true;
}

bighead-1dpallet