Skewed: một camera quay trong một raycaster / raytracer dựa trên CPU đơn giản


7

TL; DR - trong phần mềm voxel raycaster đơn giản đầu tiên của tôi, tôi không thể làm cho các camera quay hoạt động, dường như các ma trận chính xác mặc dù vậy. Kết quả bị lệch: giống như kết xuất phẳng, được xoay chính xác, tuy nhiên bị biến dạng và không có độ sâu. (Trong khi điều chỉnh theo trục tức là không được bảo vệ, độ sâu và thị sai như mong đợi.)

Tôi đang cố gắng viết một voxel raycaster đơn giản như một bài tập học tập. Đây hoàn toàn là CPU dựa trên cho đến khi tôi tìm ra cách mọi thứ hoạt động chính xác - bây giờ, OpenGL chỉ là (ab) được sử dụng để làm mờ bitmap được tạo ra màn hình thường xuyên nhất có thể.

Bây giờ tôi đã đi đến điểm mà một máy ảnh chiếu phối cảnh có thể di chuyển khắp thế giới và tôi có thể kết xuất (chủ yếu, trừ một số tạo tác cần điều tra) các góc nhìn 3 chiều chính xác về "thế giới", về cơ bản là trống rỗng nhưng chứa một khối voxel của Bunny Bunny.

Vì vậy, tôi có một máy ảnh mà tôi có thể di chuyển lên xuống, oanh tạc sang trái và phải và "đi về phía trước / lùi" - tất cả đều được điều chỉnh theo trục cho đến nay, không quay camera. Đây là vấn đề của tôi.

Ảnh chụp màn hình # 1: độ sâu chính xác khi máy ảnh vẫn được căn chỉnh theo trục, tức là. không quay.

nhập mô tả hình ảnh ở đây

Bây giờ tôi đã có một vài ngày cố gắng để xoay vòng để làm việc. Logic cơ bản và lý thuyết đằng sau ma trận và phép quay 3D, theo lý thuyết, rất rõ ràng đối với tôi. Tuy nhiên, tôi mới chỉ đạt được "kết xuất 2.5" khi máy ảnh quay ... mắt cá, giống như trong Google Streetview: mặc dù tôi có một đại diện thế giới thể tích, có vẻ như tôi không thử vấn đề gì trước tiên. tạo kết xuất từ ​​"chế độ xem trước", sau đó xoay kết xuất phẳng đó theo xoay camera. Không cần phải nói, bây giờ tôi biết rằng các tia quay không đặc biệt cần thiết và dễ bị lỗi.

Tuy nhiên, trong thiết lập gần đây nhất của tôi, với thuật toán định vị và định hướng tia ray đơn giản nhất có thể, phép quay của tôi vẫn tạo ra kiểu dáng xoay tròn mắt cá giống nhau:

Ảnh chụp màn hình # 2: máy ảnh "xoay sang phải 39 độ" - lưu ý cách phía bên trái của khối lập phương màu xanh lam từ màn hình số 2 không hiển thị trong vòng xoay này, nhưng bây giờ "thực sự nên"!

nhập mô tả hình ảnh ở đây

Tất nhiên bây giờ tôi nhận thức được điều này: trong một thiết lập đơn giản, không có trục xoay đơn giản như tôi đã có lúc đầu, tia chỉ đi qua các bước nhỏ theo hướng z dương, chuyển hướng sang trái hoặc phải và trên cùng hoặc dưới cùng chỉ phụ thuộc vào vị trí pixel và ma trận chiếu. Khi tôi "xoay máy ảnh sang phải hoặc trái" - tức là tôi xoay nó quanh trục Y - chính những bước đó nên được chuyển đổi đơn giản bằng ma trận xoay thích hợp, phải không? Vì vậy, đối với chuyển động ngược, bước Z sẽ nhỏ hơn một chút khi cam quay càng nhiều, bù lại bằng "tăng" trong bước X. Tuy nhiên, đối với phân kỳ ngang + dọc dựa trên vị trí pixel, việc tăng phân số của bước x cần phải được "thêm" vào bước z. Bằng cách nào đó, không ai trong số nhiều ma trận mà tôi đã thử nghiệm,

Đây là thuật toán tiền truyền qua tia cơ bản của tôi - cú pháp trong Go, nhưng lấy nó làm mã giả:

  • fxfy : vị trí pixel x và y
  • rayPos : vec3 cho vị trí bắt đầu tia trong không gian thế giới (tính như dưới đây)
  • rayDir : vec3 cho các bước xyz được thêm vào rayPos trong mỗi bước trong quá trình truyền tia
  • rayStep : một vec3 tạm thời
  • camPos : vec3 cho vị trí camera trong không gian thế giới
  • camRad : vec3 để quay camera theo radian
  • pmat : ma trận chiếu phối cảnh điển hình

Thuật toán / mã giả:

// 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)

Tôi đang bỏ qua các phần truyền tải và lấy mẫu - theo ảnh chụp màn hình số 1, những phần đó "về cơ bản là chính xác" (mặc dù không đẹp) - khi được căn chỉnh theo trục / không được bảo vệ.


Thật thú vị ... Tôi có ấn tượng rằng bạn đã bỏ qua một ảnh chụp màn hình ở giữa # 1 và # 2, có phải vậy không?
Người dùng không tìm thấy

Câu trả lời:


2

Mã giả của bạn trong ngôn ngữ Go là một bí ẩn lớn đối với tôi, vì vậy tôi sẽ cố gắng mô tả cách tiếp cận của tôi :)

Trước hết bạn không cần bất kỳ ma trận chiếu phối cảnh nào. Tất cả những gì bạn cần để xây dựng tia xem hiện tại là:

  • vị trí camera
  • máy ảnh lên vector
  • máy ảnh nhìn vào vector
  • pixel hiện tại trên màn hình

Hãy giả sử rằng máy ảnh miễn phí của chúng tôi hoạt động đúng. Bây giờ chúng tôi lấy các vectơ của chúng tôi và thực hiện quá trình Gram kèm Schmidt . Điều này cho chúng ta cơ sở máy ảnh trực giao. Trong GLSL , bước này trông giống như thế này:

vec3 cameraW = normalize(cameraPosition - cameraLookAt);
vec3 cameraU = normalize(cross(cameraUp, cameraW));
vec3 cameraV = cross(cameraW, cameraU);

Ok, chúng tôi có cơ sở. Cơ sở này là phổ biến cho tất cả các pixel trên màn hình. Thậm chí nhiều hơn bất biến cho đến khi chúng ta di chuyển hoặc xoay camera. Để tính toán tia xem cho pixel hiện tại, người ta phải làm:

vec3 rayOrigin = cameraPosition;
vec3 rayDirection = normalize(p.x * cameraU + p.y * cameraV - cameraViewPlaneDistance * cameraW);

trong đó p- là tọa độ của pixel hiện tại của bạn.

Sau này bạn có xem tia. Đó là thời gian cao để làm một số công cụ raytracing hoặc raymar.

Hãy quay trở lại với máy ảnh miễn phí. Để di chuyển tiến hoặc lùi chúng ta chỉ cần dịch chuyển vị trí camera theo hướng của vectơ đích. Để di chuyển sang trái hoặc phải, chúng tôi trích xuất vectơ phải từ ma trận xoay camera và thêm nó vào vectơ đích và vị trí.

Để xoay camera chúng ta sử dụng ma trận xoay camera. Ma trận xoay camera đầu tiên là ma trận danh tính. Chúng tôi có ba phao: ngáp, ném và lăn. Khi người dùng di chuyển chuột, phao này sẽ tích lũy các góc quay. Khi cập nhật, chúng tôi phải áp dụng xoay này cho ma trận xoay camera của chúng tôi. Hãy ngáp tương ứng với các vòng quay quanh trục lên. Đầu tiên chúng ta trích xuất vectơ từ ma trận xoay và sau đó xây dựng ma trận xoay mới. Sau tất cả, chúng tôi nhân ma trận xoay camera và cái mới. Ở đây một số mã C ++ sử dụng thư viện glm :

vec3 up(cameraRotation[0][1], cameraRotation[1][1], cameraRotation[2][1]);
cameraRotation *= glm::rotate(mat4(1.0), yaw, up);

Hi vọng điêu nay co ich..

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.