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.
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"!
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ả:
- fx và fy : 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ệ.