마인 크래프트처럼 물이 깊게 어둡게 보이게하려면 어떻게해야합니까?


24

Minecraft에서는 물을 더 깊게 볼 때 점점 더 어두워집니다. 누구나 그런 식으로 코딩하는 방법을 알고 있습니까?

효과가있는 마인 크래프트 효과가있는 마인 크래프트

효과없는 비슷한 게임 효과없는 비슷한 게임


18
워터 큐브의 재질이 반투명하므로 자동으로 수행되지 않습니까?
pek

나는 그렇게 생각하지 않습니다. 비교 효과없이 그림을 추가했습니다.
Xavier

2
아마도 물 큐브에만 적용되는 첨가제 혼합 효과일까요? 다시 말하지만, 재료는 반투명이기 때문에 쉬워야합니다.
pek

1
깊이에 따라 상자의 색상을 변경할 수도 있습니다.
Ali1S232

답변:


51

수심을 기준으로 조명수에는 기본적으로 두 가지 방법이 있습니다.

복셀 조명

Minecraft는 복셀 기반 조명을 사용하며 블록 유형에 따라 밝기를 낮추어 인접한 큐브로 빛을 전파하여 작동합니다. 어두운 바다는이 시스템의 부작용입니다.

물은 햇빛을 차단하고 빛을 블록 당 3 단계 씩 줄입니다 (기본 1 단계 대신).

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

출처 : 마인 크래프트 위키-Light

거리 기반 그림자

전통적인 조명 모델을 사용하는 게임에서는 광원과 해저 사이에있는 물의 양을 측정하여이 효과를 만들 수 있습니다. 그런 다음이 거리에 따라 빛이 희미 해집니다. 이를위한 몇 가지 방법이 있습니다.

직접 계산

평평한 표면이있는 경우, 수면으로부터이 표면 법선 \ vec {n}과이 법선의 내적 및 표면 위치 에스를 지오메트리 쉐이더로 전달하면 빛이 물로 이동하는 거리를 쉽게 계산할 수 있습니다 .

효과적인 물 거리는

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

여기서 \ vec {p}정점의 위치 알파는 지표면 아래의 빛 방향과 수면을 향한 수면 법선 사이의 각도입니다.

알파가 질 때 물이 들어올 때 빛이 굴절되기 때문에 50 °보다 약간 작아집니다.
다음은 좋은 설명이 포함 된 블로그 게시물입니다 . 디지털 카메라 : 내부 전반사
자세한 내용이 포함 된 또 다른 게시물 : 디지털 카메라 : Snell의 굴절 법칙

물과 평행 한 표면에 하이트 맵을 사용하는 경우 \ left (s-\ vec {n} \ cdot \ vec {p} \ right)가됩니다 \ left (s-h \ right). 태양이 수면 바로 위에있는 경우 올바른 계수는 1입니다.
포인트 라이트를 사용하면 광원 알파에 대한 상대 위치를 기준으로 각 정점에 대해 계산해야합니다 .

고정 수위 또는 고정 광 방향으로 방정식의 일부는 일정하므로 성능상의 이유로 셰이더에서 계산해서는 안됩니다.

장점 :

  • 빠르고 정확한

단점 :

  • 일반적으로 하나의 표면 만 고려되므로 평평한 수면 또는 바로 위의 조명에 대해서만 작동합니다. 거친 표면과 기울어 진 빛의 조합은 시차 매핑으로 확장 될 수 있습니다.
  • 부식제 없음

그림자 매핑

수면을 광원에서 볼 때 별도의 깊이 맵으로 렌더링하는 경우 해당 깊이 텍스처를 사용하여 표면에 닿기 전에 물에서 빛이 이동하는 거리를 계산할 수 있습니다.
이를 위해 각 정점을 정점 셰이더에서 광원의 뷰 투영으로 투영하고 픽셀 셰이더에서 텍스처 조회를 수행합니다.

표면이 비교적 평평한 경우 더 나은 결과를 얻으려면 굴절 된 광원을 사용해야합니다.

장점 :

  • 자체 폐색되지 않는 한 비교적 복잡한 물 형상으로 작동합니다. *
  • 거의 모든 종류의 부분적으로 투명한 볼륨에 재사용 할 수 있습니다.

단점 :

  • 직접 계산보다 느립니다.
  • 깊이 맵에 추가 VRAM이 필요합니다.
  • 100 % 정확하지 않습니다.

* 광선 POV의 깊이를 다음과 같이 계산하여 가장 가까운 고체 표면 앞에서 물의 양을 결정할 수 있습니다.

  1. 장면에서 솔리드 지오메트리를 정상적으로 렌더링합니다. 각 조각에 대해 결과 텍스처에 깊이 값을 추가합니다.
  2. 깊이 버퍼를 업데이트하지 않고 수면을 렌더링하고 결과에서 조각 깊이를 뺍니다.
  3. 뒷면을 같은 방식으로 렌더링하지만 조각 깊이를 결과에 추가하십시오.

결과 텍스처는 이제 라이트 뷰 스페이스에서 라이트 앞의 물의 양을 포함하므로 값을 사용하기 전에 다시 변환해야합니다. 이 방법은 방향 조명 (마이너스 굴절)을 계산하는 데 사용되지만 표면이 매우 불규칙하고 같은 조각에 영향을주는 수역 사이에 많은 양의 공기가있는 경우 주변 조명이 잘못 될 수 있습니다.
장단점은 깊이를 계산하는 동안 하나 이상의 버퍼가 필요하고 더 많은 지오메트리를 그려야하기 때문에 성능이 더 나빠진다는 점을 제외하면 일반 섀도우 매핑의 경우와 같습니다.

광선 추적

레이트 레이싱은 투명 볼륨 렌더링을위한 가장 정확하지만 가장 비싼 솔루션입니다. 이를 수행하는 방법은 두 가지가 있습니다. 1. 해저에서 지표면으로의 추적 2. 광원에서 물로의 추적. 밝기를 계산하려면 바닥의 각 지점마다 여러 개의 광선이 필요합니다.

장점 :

  • 모든 지오메트리에서 올바르게 작동합니다.
  • 올바른 가성 비!

단점 :

  • 느린!

추가 효과

물을 렌더링 할 때 고려해야 할 사항이 몇 가지 더 있습니다.

안개

관찰자에게 이동하는 동안 물 속의 빛이 다시 산란되므로 단색으로 혼합해야합니다.

옵저버가 잠긴 경우, 깊이 버퍼의 최종 결과에 따라 안개를 렌더링 할 수 있습니다. 안개 색상은 아니지만 밀도는 표면에서 관찰자의 거리에 따라 변해야합니다! (Minecraft는이 부분의 효과 만 사용합니다.)

관찰자가 위에서 물을 보면 수면과 지오메트리 사이의 깊이 차이를 기반으로 안개를 계산해야합니다. 안개 색상은 깊이 차이가 클수록 약간 어두워 지지만 안개가 완전히 불투명 한 지점으로 만 변경되어야합니다.

안개 색상은 각 픽셀의보기 방향에 따라 달라 지므로 두 경우 모두 아래를 내려다볼 때 약간 어둡습니다.

가짜 화선

가짜 가성으로 데칼 대신 매끄러운 타일링 3D 텍스처를 사용하는 경우 수직 표면에서 스트레칭을 피할 수 있습니다. 표면 근처에서 산란 된 빛의 강도는 3 차원으로 다양하므로 2D 텍스처를 사용하면 일반적으로 장면 어딘가에서 스트레칭이 생성됩니다. 바닥의 ​​꼭짓점 위치를 다른 좌표계로 투영하여 조명 각도 변경을 모델링 할 수 있습니다.

또 다른 가능성은 빛의 좌표계에서 표면 위치를 기준으로 빛의 밀도를 계산하는 것입니다.

화선은 깊이가 증가함에 따라 확산 광보다 빠르게 사라집니다.

색 그라데이션

색상이 다르게 흩어져 있으므로 밝은 색상은 깊이가 증가함에 따라 변해야합니다. 또한 예를 들어 해변이 수면과 교차하는 갑작스러운 가장자리를 방지합니다.

입사각

굴절 때문에 빛은 평상시보다 훨씬 가파르게 해저에 닿습니다. 스넬의 법칙에 대한 위키 백과의 문서 각도와 벡터에 대한 공식을 가지고있다.


6

나는 Minecraft의 하늘 조명 효과가 똑바로 있다고 생각합니다. 태양이 어디에 있든 상관없이 그 위에있는 것들에 의해 음영이 나타납니다. 그런 다음 횃불 등의 로컬 조명에 드롭 오프 효과가 적용됩니다. 광원에서 멀어 질수록 큐브의 빛은 줄어 듭니다.

이 방법으로 수행하면 각 물 층이 그 아래 층을 누적 음영 처리하므로 점진적으로 어두워집니다. 나무 단풍은 이와 같은 그늘을 제공하지만 누적되지는 않습니다. 1 개 또는 100 개의 단풍 큐브에 상관없이 나무 아래에서 같은 그늘을 얻습니다.

이것이 사용되는 방법 중 하나의 단서는 뷰어에서 멀어 질 때 물이 더 어두워지지 않는다는 것입니다. 그렇습니다. 안개 효과는 먼 거리에서 시작되지만 물 어두운 효과는 아닙니다.

따라서 조명을 계산하는 기본 공식은 의사 코드에서 다음과 같습니다.

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
}

이 방법을 사용하면 돌출부 아래에서 피치가 어두워 지므로 돌출부 또는 동굴에서 조명을 계산하는 데 적합하지 않습니다. 그러나 태양 광 블록을 광원으로 취급 할뿐만 아니라 지역 광원 (토치, 화재 등)을 모두 추가 할 수 있습니다. 이런 식으로 할 수 있습니다 ...

  1. 각 큐브에 대해 직사광선 (의사 코드를 통해)으로부터 태양 광을 계산합니다.
  2. 큐브 옆에 광원이있는 경우 완전히 켜져있는 것을 고려하십시오 (1.0)
  3. 큐브가 바로 위에서 태양을받지 못하면 완전히 조명 된 큐브에서 얼마나 멀리 떨어져 있는지에 따라 빛을 비 춥니 다. 가까이있을수록 빛이 많을수록 멀어 질수록 (0까지) 줄어 듭니다.

여기서 아이디어는 태양이나 토치에 의해 큐브가 켜지면 그 옆에있는 큐브도 어떤 방식 으로든 켜질 것입니다. 그리고 그 조명 큐브에서 멀어 질수록 빛이 줄어 듭니다. 확산 조명을 추정하는 일종의 멍청한 방법이지만 작동한다고 생각합니다 (?).


1
그래, 나는 그것이 티켓이라고 확신한다. 게임에서 비슷한 일을했습니다.
MichaelHouse

그건 그렇고 방금 블로그를 Google 리더 목록 Byte56에 추가했습니다. 개발자 블로그 FTW!
팀 홀트

오, 왜 고마워? 이 질문에 대한 주제에서 벗어나지 만 베일리 교수의 수업에 관한 블로그를 읽었습니다. 나는 작년에 그 수업에 있었다! 나는 당신이 작년에 그 프레젠테이션을했다고 확신합니다. 나는 당신의 이름이 익숙하다고 생각했습니다. 작은 세계 :)
MichaelHouse

3

아마도 나는 그 질문을 오해하고 있지만 왜 깊이에 따라 블록의 색상을 바꿀 수 없습니까?

깊이 d (블록 단위, 0부터 시작)가 있으면 적절한 밝기 방정식은 다음과 같습니다.

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

암호: L = (1.0 - m) * exp(-k * d) + m;

k 는 어두워지는 속도를 제어합니다 (높을수록 빠름). 합리적인 값은 0.5입니다.
m 은 원하는 최소 밝기입니다.
L 은 0에서 1까지 다양합니다.

사용중인 그래픽 API에서 블록 색상을 변경하는 방법을 모르는 경우 별도의 질문으로 사용하십시오 (사용하는 API 및 셰이더 사용 여부를 지정).


나는 단순히 그렇게 생각하지 않았습니다. 호기심에서 그 방정식을 어디서 얻었습니까?
Xavier

1
@ Xavier : 방금 만들었습니다. e^-kd비트 서서히 어떤 값 (깊이)를 통해 0으로 경향 가지 표준 함수 단지 지수 감쇠이다. 곱셈 (1-m)과 덧셈은 m붕괴를 스케일링하고 상쇄하여 최소로 끝나지만 m여전히 시작합니다 1. en.wikipedia.org/wiki/Exponential_decay
피터 알렉산더

더 깊은 색조의 블록은 블록이 알파 색상 인 경우에만 나타납니다. 이 경우 블록 색상을 변경할 필요가 없으며 알파는 효과를 자동으로 생성합니다.
Jonathan Connell

@Jonathan : 물 블록을 렌더링하지 않고 해저의 블록을 어둡게 렌더링 한 다음 수면에 단일 알파 레이어를 만듭니다.
피터 알렉산더

@Peter Alexander Ok, 나는이 블록 타입 게임에서 물조차도 블록으로 만들어 졌다고 가정했습니다.
Jonathan Connell
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.