Làm cách nào tôi có thể làm cho nước có vẻ tối hơn với độ sâu, như trong Minecraft?


24

Trong Minecraft khi bạn nhìn vào nước, bạn càng nhìn sâu hơn. Có ai biết làm thế nào để mã hóa một cái gì đó như vậy?

Minecraft có hiệu lực minecraft có hiệu lực

trò chơi tương tự mà không có hiệu lực trò chơi tương tự mà không có hiệu lực


18
Điều này không được thực hiện tự động vì vật liệu của khối nước là bán trong suốt?
pek

Tôi không nghĩ vậy. Tôi đã thêm một hình ảnh mà không có hiệu ứng để so sánh.
Xavier

2
Có lẽ đó là một hiệu ứng pha trộn phụ gia chỉ áp dụng trên các khối nước? Một lần nữa, điều này sẽ dễ dàng vì vật liệu là bán trong suốt.
pek

1
bạn cũng có thể thay đổi màu sắc của hộp theo độ sâu.
Ali1S232

Câu trả lời:


51

Về cơ bản có hai cách tiếp cận khác nhau để chiếu sáng nước dựa trên độ sâu:

Voxel-Ánh sáng

Minecraft sử dụng ánh sáng dựa trên voxel, hoạt động bằng cách truyền ánh sáng đến các hình khối liền kề, giảm độ sáng tùy thuộc vào loại khối. Đại dương tối là một tác dụng phụ của hệ thống này.

Nước chặn ánh sáng mặt trời và giảm 3 mức ánh sáng cho mỗi khối (thay vì mức 1 mặc định), có nghĩa là độ sáng trong đại dương cho mỗi khoảng cách từ bề mặt là:

0 (surface): 15 (direct sunlight)
1:           12
2:            9
3:            6
4:            3
5 and below:  0 (darkness)

Nguồn: Minecraft Wiki - Ánh sáng

Shadowing dựa trên khoảng cách

Trong các trò chơi với mô hình chiếu sáng truyền thống, hiệu ứng này có thể được tạo ra bằng cách đo lượng nước nằm giữa nguồn sáng và đáy đại dương. Ánh sáng sau đó bị mờ dần dựa trên khoảng cách này. Có một vài phương pháp để làm điều này:

Tính toán trực tiếp

Nếu bạn có một bề mặt phẳng, bạn có thể dễ dàng tính toán khoảng cách ánh sáng truyền trong nước nếu bạn vượt qua bề mặt bình thường khỏi mặt nước \ vec {n}và sản phẩm chấm của bình thường này và một vị trí bề mặt Svào bóng đổ hình học.

Khoảng cách nước hiệu quả là

\ max (\ left (s - \ vec {n} \ cdot \ vec {p} \ right), 0) \ cdot \ left (1 + \ tan (\ alpha) \ right)

nơi \ vec {p}là vị trí của các đỉnh và alphalà góc giữa hướng ánh sáng xuống mặt biển và mặt nước bình thường đối với cơ thể của nước.

Vào lúc hoàng hôn, alphachỉ đạt được ít hơn 50 ° vì ánh sáng bị khúc xạ khi xuống nước.
Đây là một bài đăng blog với một lời giải thích tốt: Máy ảnh kỹ thuật số: Tổng phản xạ nội bộ
Một bài đăng khác có nhiều chi tiết hơn: Máy ảnh kỹ thuật số: Định luật khúc xạ của Snell

Nếu bạn đang sử dụng sơ đồ chiều cao trên bề mặt song song với nước, \ left (s - \ vec {n} \ cdot \ vec {p} \ phải)sẽ trở thành \ trái (s - h \ phải). Hệ số đúng bằng 1 nếu mặt trời ở ngay trên mặt nước.
Với ánh sáng điểm, bạn phải tính toán alphacho từng đỉnh dựa trên vị trí tương đối với nguồn sáng.

Với mực nước cố định hoặc hướng sáng cố định, các phần của phương trình là không đổi và không nên tính toán trong bóng đổ vì lý do hiệu suất.

Ưu điểm:

  • Nhanh và chính xác

Nhược điểm:

  • Chỉ hoạt động cho các bề mặt nước phẳng hoặc chỉ cho ánh sáng từ trực tiếp bên trên, vì chỉ có một bề mặt thường được tính đến. (Sự kết hợp giữa bề mặt gồ ghề và ánh sáng nghiêng có thể hoạt động đến một số mở rộng với ánh xạ thị sai.)
  • Không ăn da

Bản đồ bóng

Nếu bạn hiển thị mặt nước thành một bản đồ độ sâu riêng biệt (nhìn từ nguồn sáng), bạn có thể sử dụng kết cấu độ sâu đó để tính khoảng cách ánh sáng đi trong nước trước khi chạm vào bề mặt.
Để thực hiện việc này, bạn chiếu từng đỉnh vào hình chiếu chế độ xem của nguồn sáng trong trình tạo bóng đỉnh và thực hiện tra cứu kết cấu trong trình đổ bóng pixel.

Nếu bề mặt tương đối bằng phẳng, bạn nên sử dụng nguồn sáng khúc xạ để có kết quả tốt hơn.

Ưu điểm:

  • Hoạt động với hình học nước tương đối phức tạp, miễn là nó không bao gồm chính nó. *
  • Có thể được tái sử dụng cho hầu hết mọi loại khối lượng trong suốt một phần.

Nhược điểm:

  • Chậm hơn so với tính toán trực tiếp.
  • Cần thêm VRAM cho bản đồ độ sâu.
  • Không chính xác 100%.

* Bạn có thể xác định lượng nước ở phía trước bề mặt rắn gần nhất bằng cách đếm độ sâu từ POV của ánh sáng như sau:

  1. Kết xuất hình học rắn trong cảnh của bạn như bình thường. Đối với mỗi phân đoạn, bạn thêm giá trị độ sâu vào kết cấu kết quả.
  2. Kết xuất mặt trước của nước mà không cập nhật bộ đệm độ sâu và trừ độ sâu của mảnh vỡ khỏi kết quả.
  3. Kết xuất các mặt sau theo cùng một cách, nhưng thêm độ sâu mảnh vào kết quả.

Kết cấu kết quả hiện chứa lượng nước phía trước ánh sáng trong không gian xem ánh sáng, do đó, giá trị phải được chuyển đổi trở lại trước khi bạn sử dụng nó. Phương pháp này hoạt động để tính toán ánh sáng định hướng (trừ khúc xạ), nhưng sẽ dẫn đến ánh sáng xung quanh không chính xác nếu các bề mặt rất không đều và có một lượng không khí lớn giữa các vùng nước ảnh hưởng đến cùng một mảnh.
Những ưu và nhược điểm giống như đối với ánh xạ bóng bình thường, ngoại trừ việc bạn cần thêm một bộ đệm trong khi tính toán độ sâu và hiệu suất kém hơn vì bạn phải vẽ thêm hình học.

Có hi vọng

Ray theo dõi là giải pháp chính xác nhất nhưng cũng tốn kém nhất để hiển thị khối lượng trong suốt. Có hai cách để làm điều này: 1. Truy tìm từ đáy đại dương về phía mặt nước và 2. Truy tìm từ nguồn sáng hướng về mặt nước. Cần nhiều tia cho mỗi điểm trên sàn để tính độ sáng.

Ưu điểm:

  • Hoạt động chính xác với mọi hình học.
  • Đúng caustics!

Nhược điểm:

  • Chậm thôi!

Hiệu ứng bổ sung

Có một vài điều nữa cần tính đến khi kết xuất nước:

Sương mù

Ánh sáng trong nước bị tán xạ trở lại trong khi di chuyển đến người quan sát, vì vậy bạn nên pha trộn nó theo một màu đặc.

Nếu người quan sát bị ngập nước , bạn chỉ có thể kết xuất sương mù dựa trên kết quả cuối cùng của bộ đệm độ sâu. Màu sương mù, nhưng không phải mật độ của nó sẽ thay đổi theo khoảng cách của người quan sát so với bề mặt! (Minecraft chỉ sử dụng phần hiệu ứng này.)

Nếu người quan sát nhìn mặt nước từ trên cao , bạn cần tính toán sương mù dựa trên độ chênh lệch độ sâu giữa bề mặt và hình học dưới nước. Màu sương mù sẽ hơi tối hơn với độ chênh lệch độ sâu lớn hơn, nhưng chỉ nên thay đổi đến điểm sương mù mờ hoàn toàn.

Màu sương mù cũng phải phụ thuộc vào hướng xem của từng pixel, vì vậy nó hơi tối hơn khi nhìn xuống trong cả hai trường hợp.

Làm giả Caustics

Nếu bạn sử dụng kết cấu 3D ốp lát liền mạch thay vì decal cho tụ quang giả, bạn có thể tránh kéo dài trên các bề mặt thẳng đứng. Độ mạnh của ánh sáng tán xạ gần bề mặt thay đổi theo ba chiều, vì vậy sử dụng Kết cấu 2D thường tạo ra sự kéo dài ở đâu đó trong cảnh. Bạn có thể mô hình thay đổi góc ánh sáng bằng cách chiếu các vị trí đỉnh của sàn thành một hệ tọa độ khác.

Một khả năng khác là tính toán mật độ ánh sáng dựa trên vị trí bề mặt trong hệ tọa độ của ánh sáng, mặc dù điều đó rất có thể sẽ tốn một số hiệu suất.

Các tụ quang nên mờ dần nhanh hơn ánh sáng khuếch tán với độ sâu tăng dần.

Gradient màu

Màu sắc được phân tán khác nhau, vì vậy màu sắc ánh sáng nên thay đổi theo chiều sâu tăng dần. Điều này cũng ngăn chặn các cạnh đột ngột, ví dụ, một bãi biển giao với mặt nước.

Góc độ

Do khúc xạ, ánh sáng chiếu xuống đáy đại dương dốc hơn nhiều so với bình thường. Các bài viết trên Wikipedia về định luật Snell có công thức cho các góc và vectơ.


6

Tôi tin rằng hiệu ứng ánh sáng bầu trời trong Minecraft là thẳng xuống - mọi thứ bị che mờ bởi những gì ở trên chúng cho dù mặt trời ở đâu. Sau đó, ánh sáng cục bộ từ các ngọn đuốc, v.v ... được áp dụng với hiệu ứng thả xuống - càng xa nguồn sáng, khối lập phương càng ít ánh sáng.

Nếu được thực hiện theo cách này, mỗi lớp nước sẽ tích tụ lớp bên dưới nó, do đó mỗi lớp sẽ dần dần tối hơn. Tán lá cây cung cấp bóng mát như thế này, tuy nhiên nó không được tích lũy. Bạn có cùng một bóng râm dưới gốc cây cho dù đó là 1 hay 100 khối lá.

Một manh mối cho thấy đây là phương pháp đang được sử dụng là nước không bị tối hơn khi xa người xem hơn - chỉ khi bạn đi xuống. Vâng, hiệu ứng sương mù có tác dụng từ xa, nhưng không phải là hiệu ứng bóng tối của nước.

Vì vậy, công thức cơ bản để tính toán ánh sáng sẽ giống như thế này trong mã giả ...

light_on_cube = 1.0
for each cube above target cube, from lowest to highest {
   if cube being examined is tree foliage
      light_on_cube = 0.5
   else if cube being examined is water
      light_on_cube = light_on_cube - 0.1
   else if cube being examined is solid 
      light_on_cube = 0
}

Điều này không hoàn hảo để tính toán ánh sáng dưới phần nhô ra hoặc trong hang động, vì nó sẽ tối tối dưới phần nhô ra bằng phương pháp này. Nhưng người ta có thể thêm vào cả hai nguồn sáng cục bộ (đuốc, lửa, v.v.) cũng như coi các khối ánh sáng mặt trời là nguồn sáng. Một cái gì đó như thế này có thể làm điều đó ...

  1. Tính toán ánh sáng từ mặt trời từ trực tiếp bên trên (thông qua mã giả ở trên) cho mỗi khối.
  2. Nếu một khối lập phương có nguồn sáng bên cạnh, hãy xem xét nó được thắp sáng đầy đủ (1.0)
  3. Nếu một khối lập phương không nhận được mặt trời từ ngay phía trên, hãy cho nó một chút ánh sáng dựa trên khoảng cách từ nó đến một khối sáng hoàn toàn. Gần hơn có nghĩa là nhiều ánh sáng hơn, xa hơn có nghĩa là ít hơn (cho đến không).

Ý tưởng ở đây là nếu một khối lập phương được thắp sáng bởi mặt trời hoặc một ngọn đuốc, thì khối lập phương bên cạnh nó cũng sẽ được thắp sáng theo một cách nào đó. Và bạn càng ở xa khối ánh sáng đó thì sẽ càng ít ánh sáng. Đó là một cách để ước tính ánh sáng khuếch tán nhưng tôi nghĩ (?) Nó sẽ hoạt động.


1
Vâng, tôi khá chắc chắn đó là vé. Tôi đã làm một cái gì đó tương tự trong trò chơi của tôi.
MichaelHouse

Nhân tiện, tôi vừa thêm blog của bạn vào danh sách người đọc google của tôi Byte56 - blog của nhà phát triển FTW!
Tim Holt

Ồ, tại sao cảm ơn bạn. Vẫn không có chủ đề cho câu hỏi này, nhưng tôi chỉ đọc blog của bạn về lớp của giáo sư Bailey. Tôi đã ở trong lớp học năm ngoái! Tôi khá chắc chắn rằng bạn đã trình bày năm ngoái quá. Tôi nghĩ tên của bạn là quen thuộc. Thế giới nhỏ :)
MichaelHouse

3

Có lẽ tôi đang hiểu nhầm câu hỏi, nhưng tại sao bạn không thể thay đổi màu của các khối tùy thuộc vào độ sâu của chúng?

Nếu bạn có độ sâu d (tính theo khối, bắt đầu từ 0) thì phương trình hợp lý cho độ sáng sẽ là:

L = (1- m ) e - kd + m

Mã số: L = (1.0 - m) * exp(-k * d) + m;

k kiểm soát mức độ tối của nó nhanh hơn (cao hơn = nhanh hơn). Giá trị hợp lý sẽ là 0,5.
m là độ sáng tối thiểu bạn muốn.
L thay đổi từ 0 đến 1.

Nếu bạn không biết cách thay đổi màu của các khối trong bất kỳ API đồ họa nào bạn đang sử dụng thì vui lòng hỏi đó như một câu hỏi riêng biệt (nêu rõ API bạn sử dụng và liệu bạn có sử dụng trình tạo bóng hay không).


Tôi chỉ đơn giản là không nghĩ đến việc làm đó. Chỉ tò mò bạn đã lấy phương trình đó ở đâu?
Xavier

1
@Xavier: Tôi vừa làm nó lên. Các e^-kdbit là chỉ là một phân rã theo cấp số nhân, mà là một chức năng tiêu chuẩn cho điều mà dần dần có xu hướng không qua một số giá trị (chiều sâu). Phép nhân bằng (1-m)và cộng mchỉ là để chia tỷ lệ và bù cho sự phân rã sao cho nó kết thúc ở mức tối thiểu mnhưng vẫn bắt đầu từ 1. vi.wikipedia.org/wiki/Exponential_decay
Peter Alexander

Điều đó là, các khối của màu sắc sâu hơn sẽ chỉ được nhìn thấy nếu các khối có màu alpha; trong trường hợp không cần thay đổi màu khối, alpha sẽ tạo hiệu ứng tự động.
Jonathan Connell

@Jonathan: Bạn không kết xuất các khối nước, bạn kết xuất các khối trên đáy biển với màu tối và sau đó chỉ có một lớp alpha duy nhất trên mặt nước.
Peter Alexander

@Peter Alexander Ok, tôi cho rằng trong các trò chơi kiểu khối này, ngay cả nước cũng được tạo thành từ các khối.
Jonathan Connell
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.