조명 계산에 제곱 반경과 반 제곱 반경의 유틸리티는 무엇입니까?


16

"Battlefield 3의 DirectX 11 렌더링"PowerPoint의 슬라이드 중 하나에서 다음 코드를 발견했습니다.

struct Light {
    float3 pos; float sqrRadius;
    float3 color; float invSqrRadius;
}

왜 반경을 저장하는 대신 왜 제곱 반지름과 심지어 제곱 반지름 (단순히 제곱 반지름이라고 생각하는지)을 저장해야하는지 이해할 수 없습니까? 그들은이 데이터를 어떻게 계산에 사용합니까? 또한 콘 및 라인 라이트는 어떻습니까? 이 구조체는 포인트 라이트 전용이어야합니다. 다른 유형에서는 작동하지 않습니다. 데이터가 충분하지 않습니다. 아직도 나는 그들이 그 광장과 invSquare를 어떻게 사용하는지 알고 싶습니다.

업데이트 : 네, 마침내 얻었습니다.

다음은 그물에서 쉽게 찾을 수있는 고전적인 광 감쇠 방정식입니다.

float3 lightVector = lightPosition - surfacePosition;

float attenuation = saturate(1 - length(lightVector)/lightRadius);

length(lightVector)실제로이 작업을 수행하는 것처럼 상대적으로 비용이 많이 듭니다 .

length(lightVector) = sqrt(dot(lightVector, lightVector);

게다가, 분할 운영 (/lightRadius)또한 상당히 비싸다.

이런 방식으로 빛 감쇠를 계산하는 대신 다음과 같은 방식으로 빛 감쇠를 계산할 수 있습니다.

attenuation = saturate(1 - dot(lightVector, lightVector)*invRadiusSqr);

여기서 invRadiusSqr은 CPU 레벨에서 사전 계산되어 쉐이더 상수로 전달 될 수 있습니다.

또한, 결과적으로 (이전의 경우 선형 대신) 2 차 광 감쇠가 발생하는데, IRL 광이 2 차 감쇠를 갖는 것으로보다 우수합니다.

도와 주셔서 감사합니다!


13
심. 셰이더는 16 바이트로 정렬됩니다. 그리고 코드의 형식을 살펴보면 두 개의 float4로 묶여 있음을 알 수 있습니다. 캐시에서 무료로 얻을 때 유용한 것을 저장하지 않는 이유는 무엇입니까?
Tordin

답변:


23

이것은 단순히 invSqrRadius = 1/SqrRadius빛을 캐싱 할 때마다 각 조명에 대해 반 제곱 반경을 계산하는 대신 곱셈과 비교할 때 적어도 나눗셈이 "느린"연산이기 때문에 일종의 최적화 입니다.

이 최적화는 특히 다음과 관련이 있습니다.

  • 각 조명에 대해 작업이 많이 수행되면 값을 캐싱하면 추가 CPU / GPU주기가 해제됩니다.
  • 그리고 값을 읽는 데 필요한 메모리 액세스 시간이 실제로는 다시 계산하는 것보다 빠르다고 가정하십시오.

그것이 어떻게 사용되는지에 관해서는, 나는 그들의 특정 구현에 대해서는 확신하지 못하지만에 관해서 1/sqrRadius는 단순히 빛 감쇠, 감쇠 및 컬링에 사용됩니다. 방향성 및 스포트라이트와도 관련이 있습니다. 스포트라이트의 경우 유일한 차이점 은 감쇠를 적용한 스포트라이트 계수를 계산해야한다는 것 입니다. 태양과 같은 방향성 조명과 관련하여 일반적으로 감쇠 또는 감쇠가 없으므로 무시됩니다.

[편집] 더 자세히 설명하기 위해 관련성이없는 데이터 는 아닙니다 . 빛의 조도는 다음 방정식을 사용하여 계산할 수 있습니다.

E = Phi / 4 * pi * rSqr;

어디

E 는 플럭스의 면적 밀도입니다.

Phi 는 래디언스 플럭스입니다.

4 * pi * rSqr 은 구의 표면적입니다.

이 방정식은 수신 된 에너지의 양이 제곱 거리로 떨어지는 이유를 설명합니다.

또 다른 요점은 특정 정점에 대한 빛의 기여도를 계산하기 위해 정점과 빛 사이의 거리를 계산해야한다는 것입니다 (이 값은 캐시되지 않을 것입니다). 정점은 빛의 범위 내외부에서 다음 지점으로 인도 할 수 있습니다 어디 Radius Square컬링 유용합니다.

라이트 폴 오프 및 컬링을 계산하기위한 실제적인 예를 원한다면, 이는 타일 기반 지연 렌더러에서 특히 유용합니다. 여기에 하나의 예가 있습니다.


저주, 당신은 7 초나 나를 때렸다! ;) (그리고 더 포괄적 인 답변도 있습니다!)
Trevor Powell

링크에 대한 자세한 설명, 특히 감사합니다! 후자의 링크에서 내가 이해 한 바에서 Battlefield 3는 반경이 아니라 광원과 수 광기 사이의 실제 거리를 저장합니다. 그것이 기사에서 사용하는 "d"값입니다.
cubrman

@cubrman 코드를 보지 않고 추측하기는 어렵다. 내 생각에 그것은 그것이 반 반지름 Sqr입니다. 그리고 그들이 사용하는 방정식은 기사와 크게 다를 수 있습니다.
concept3d

그러나 조명 계산에서 어떻게 맨손으로 거꾸로 된 반경을 사용할 수 있습니까? 그물에서 찾은 모든 소스는 수신면과 광원 사이의 거리를 찾아서 원래의 빛 반경으로 나눈 다음 결과를 제곱해야한다고 말합니다. 제곱 반경 또는 invSqrRadius를 어디에서 사용 하시겠습니까? 그것은 나에게 전혀 관련이없는 데이터처럼 보입니다.
cubrman

1
@cubrman이 답변을 업데이트했습니다.
concept3d

6

invSqrRadius는 1이 아닙니다-sqrRadius; 1 / sqrRadius입니다.

이는 sqrRadius로 나누지 않고 invSqrRadius를 곱할 수 있음을 의미합니다 (나눗셈은 곱셈보다 훨씬 비쌉니다).


6

여기에있는 다른 대답은 역 제곱 반경을 다루었지만 대신 제곱 반경을 살펴 보겠습니다 (concept3d가 터치했지만 추가 토론이 필요하다고 생각합니다).

유용한 제곱은 거리 비교입니다. 우리는 두 점 사이의 거리를 계산하는 데 제곱근이 포함되며, 제곱근은 계산 비용이 많이 들지만, 원하는 경우 거리를 비교 하는 것입니다 하는 것입니다 (어느거나 더 작은 것을 찾기 위해 결과) 우리는 제곱근을 버릴 수 있습니다.

sqrt (x)> sqrt (y)이면 x> y의 경우이기도합니다.

라이트의 경우, 제곱 반경은 라이트의 중심과 최대 범위 사이의 거리와 동일합니다. 물론 제곱입니다.

조명 계산의 경우 초기 사례에 사용할 수 있습니다. 조명하고있는 점과 조명의 중심 (제곱) 사이의 거리가 제곱 반경보다 크면 점이 빛을받지 않으므로 나머지 계산을 실행할 필요가 없습니다. 그러므로 이것은 단지 최적화 일뿐입니다 (비교적입니다). 우리는 제곱 반경을 사용하여 값 비싼 제곱근없이 거리를 비교하고 뺄셈과 내적의 대가를 치를 수 있습니다.

물론 이것이 BF3가 그것을 사용하고 있는지 정확히 알지 못하지만 마크에서 너무 멀지 않을 것으로 기대합니다.


따라서 올바르게 이해하면 코드는 다음과 같습니다. if (((lightPos-surfacePos), (lightPos-surfacePos))> lightRadiusSqr) 조명을 수행하지 않습니다
cubrman
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.