2012-03-25 5 views
1

간단한 보셀 레이 캐스터를 학습 연습으로 작성하려고합니다. 이것은 순수하게 CPU 기반입니다. 현재 상황을 정확하게 파악하기 전까지는 - OpenGL은 생성 된 비트 맵을 가능한 한 자주 화면에 표시하는 데 사용됩니다.기울이기 : 간단한 CPU 기반 보셀 레이서/레이 트레이서의 회전 카메라

이제 원근 투영 카메라가 세계를 움직일 수있는 시점에 이르렀으며 (주로 조사가 필요한 일부 인공물을 제외하고) 원근감있는 "세계"의 3 차원 뷰를 올바르게 렌더링 할 수있었습니다. 기본적으로 비어 있지만 스탠포드 버니 (Stanford Bunny)의 복셀 큐브가 들어 있습니다.

나는 카메라를 가지고 있는데, 나는 상하로 움직일 수 있고, 왼쪽과 오른쪽으로 도망 갈 수 있으며, "앞으로/뒤로 걸어 라."- 모든 축에 정렬되어 있으며 카메라는 회전하지 않습니다. 여기 내 문제가있다.

스크린 샷 : (1) raycasting voxels while......(2) the camera remains......(3) strictly axis-aligned.

은 지금은 일 회전을 얻으려고 노력하고 며칠 동안 있습니다. 이론적으로 행렬과 3D 회전의 기본 논리와 이론은 나에게 분명합니다. 그러나 나는 카메라가 회전 할 때만 "2.5 렌더링"을 달성했습니다. Google 어스 스트리트 뷰에서와 같이 물고기 눈이 조금 있습니다. 비록 내가 체적을 나타내는 세계 표현을 가지고 있지만, 내가 무엇을하려고해도 ... 먼저 "정면도"에서 렌더링을 생성 한 다음 카메라 회전에 따라 평면 렌더링을 회전합니다. 말할 필요도없이, 회전 광선이 특히 필요하지 않으며 오류가 발생하기 쉽다는 것을 이제 알고 있습니다.

아직도 나의 가장 최근의 설정에서, 가장 단순화 된 레이 캐스트 레이 - 위치와 방향 알고리즘을 가능으로, 내 회전은 여전히 ​​같은 물고기 eyey 평면 렌더링 - 회전 스타일의 모양이 생성

camera "rotated to the right by 39 degrees" - - 스크린 # 2의 큐브의 푸른 색 음영 처리 된 왼쪽면이이 회전에서 어떻게 보이지 않는지주의하십시오. 그러나 아직까지는 "정말입니다"!

물론 저는 이것을 알고 있습니다. 처음부터 가지고있는 것처럼 축 정렬이없는 회전 설정에서 광선은 z 축의 양의 방향을 따라 왼쪽으로 갈라서 간단히 이동합니다 또는 픽셀 위치 및 투영 행렬에 따라 오른쪽 및 위 또는 아래에만 적용됩니다. "카메라를 오른쪽 또는 왼쪽으로 회전"(즉, Y 축을 중심으로 회전) - 바로 그 단계는 적절한 회전 행렬에 의해 간단히 변형되어야합니다. 맞습니까? 따라서 순방향 탐색의 경우 Z 단계는 캠이 더 많이 회전할수록 조금 작아지고 X 단계의 "증가"에 의해 상쇄됩니다. 그러나 픽셀 위치 기반 수평 + 수직 발산의 경우, x 단계의 분수를 늘려 z 단계에 "추가"할 필요가 있습니다. 어쨌든, 내가 실험 한 많은 행렬들 중 어느 것도 매트릭스가없는 하드 코딩 된 장황한 sin/cos 계산을 사용한 실험은 실제로이 부분을 올바르게 처리하지 못합니다.

  • FX년도 : 픽셀 위치의 x와 y
  • rayPos 이동의 구문하지만 의사로 받아 -

    은 여기 내 기본적인 당 선 사전 탐색 알고리즘의 : 세계 공간에서 광선 시작 위치에 대한 vec3 (아래 계산)

  • rayDir : 각 단계에서 rayPos에 xyz 단계가 추가되는 동안 vec3 레이 통과
  • rayStep : 임시 VEC3
  • 캄포스 : 월드 공간에서의 카메라 위치에 대한 VEC3
  • camRad : 일반적인 원근 투영 : 라디안으로 카메라 회전
  • PMAT에 대한 VEC3 매트릭스

알고리즘/의사 코드 :

회전되지 않은/축 정렬 할 때 - 사람들은 (하지 꽤 있지만) "기본적으로 대부분 올바른"입니다 화면 # 1에 따라 # 3를 통해 - 6,
// 1: rayPos is for now "this pixel, as a vector on the view plane in 3d, at The Origin" 
rayPos.X, rayPos.Y, rayPos.Z = ((fx/width) - 0.5), ((fy/height) - 0.5), 0 

// 2: rotate around Y axis depending on cam rotation. No prob since view plane still at Origin 0,0,0 
rayPos.MultMat(num.NewDmat4RotationY(camRad.Y)) 

// 3: a temp vec3. planeDist is -0.15 or some such -- fov-based dist of view plane from eye and also the non-normalized, "in axis-aligned world" traversal step size "forward into the screen" 
rayStep.X, rayStep.Y, rayStep.Z = 0, 0, planeDist 

// 4: rotate this too -- 0,zstep should become some meaningful xzstep,xzstep 
rayStep.MultMat(num.NewDmat4RotationY(CamRad.Y)) 

// set up direction vector from still-origin-based-ray-position-off-rotated-view-plane plus rotated-zstep-vector 
rayDir.X, rayDir.Y, rayDir.Z = -rayPos.X - me.rayStep.X, -rayPos.Y, rayPos.Z + rayStep.Z 

// perspective projection 
rayDir.Normalize() 
rayDir.MultMat(pmat) 

// before traversal, the ray starting position has to be transformed from origin-relative to campos-relative 
rayPos.Add(camPos) 

나는 순회를 건너 뛰는 및 부품을 샘플링하고있다.

답변

4

시스템을 다른 것보다 핀홀 카메라로 묘사하면 훨씬 쉽습니다. 이미지를 나타내는 직사각형의 표면에서 광선을 쏘는 대신, 이미지 평면이 될 직사각형을 통해 광선을 한 지점에서 장면 안으로 쏘십시오. 모든 기본 광선은 약간 다른 방향으로 만 동일한 원점을 가져야합니다. 방향은 기본 삼각 함수를 사용하여 이미지 평면의 픽셀을 통과시켜 결정합니다. 가장 간단한 예를 들자면, 포인트가 카메라에 있고, 이미지 평면이 z 축을 따라 하나의 단위이고, 높이와 폭이 두 개인 단위라고 상상해 봅시다. 이렇게하면 왼쪽 위 모서리에있는 픽셀이 (0,0,0)에서 (-1, -1, 1)로 이동하려고합니다. 방향을 얻기 위해 (-1, -1, 1)을 정규화하십시오. (실제로 광선 교차를 수행하기 위해 방향을 정규화 할 필요는 없지만, 광선을 이동 한 거리 또는 그와 비슷한 거리를 계산하기 전에 방향이 정규화되지 않았 음을 기억하십시오.) 다른 모든 픽셀에서, 평면의 크기를 각 방향의 픽셀 수로 나눠서 이미 수행 한 방식을 수행하려는 평면상의 점을 계산합니다.

다음은 가장 중요한 것입니다. 투시 투영을 시도하십시오. 이는 스캔 변환 기법에서 모든 꼭지점을 화면의 한 지점에 매핑하는 데 필요하지만 광선 추적에서 광선은 한 지점에서부터 공간으로 퍼지기 만하면됩니다. 시작점 (카메라 위치,이 예제의 원점)에서 이미지면을 통과하는 방향은 정확히 추적해야하는 방향입니다. 대신 직교 투영을 원한다면 (그리고 거의 절대 원하지 않는), 모든 광선에 대해 방향이 같고 시작 위치가 이미지 평면에 따라 달라 지므로이를 수행 할 수 있습니다.

이렇게하면 좋은 출발점이됩니다. 그런 다음 광선을 계산하기 위해 반복하기 전에 원점을 중심으로 이미지 평면을 회전하거나 광선 방향을 직접 회전하여 카메라 회전을 다시 추가 할 수 있습니다. 방향을 직접 바꾸는 데는 아무 문제가 없습니다.방향이 원점에서 시작하면 광선이 통과하는 위치에 불과하다는 것을 명심할 때 방향을 회전시키고 점을 통과하는 것이 똑같은 일을하는 것을 쉽게 볼 수 있습니다.