2011-02-05 5 views
6

현재 나는 작업중인 게임 엔진을위한 GLSL에서 쉐이더를 만드는 법을 배우고 있으며, 나는 퍼즐과 관련된 언어에 관한 질문을 가지고 있습니다. 3.0 미만의 셰이더 버전에서는 루프 조건에서 균일 변수를 사용할 수 없다는 것을 알게되었습니다. 예를 들어 다음 코드는 3.0 이전의 셰이더 버전에서는 작동하지 않습니다.GLSL break 명령어

for (int i = 0; i < uNumLights; i++) 
{ 
    ............... 
} 

그러나 그것은 반복 일정량으로 루프와이를 교체하지만,이 경우, uNumLights보다 크면 루프를 끊을 조건문을 포함 할 수 없다? 예 :

for (int i = 0; i < MAX_LIGHTS; i++) 
{ 
    if(i >= uNumLights) 
     break; 
    .............. 
} 

해당하지 않습니까? 후자는 이전 버전 GLSL에서 작동해야합니까? 그렇다면 빛의 수에 따라 다른 버전의 쉐이더를 사용하는 것과 같은 내가 읽은 다른 기술보다 구현하기가 더 쉽고 효율적이지 않습니까?
이것이 바보 같은 질문 일 수도 있지만 초보자인데 이것이 작동하지 않아야하는 이유를 찾을 수 없습니다.

답변

11

GLSL은 한, 혼란 스러울 수 있습니다.

실제적으로은 SMART 하드웨어에서 발생합니다. OpenGL 구현 내부의 HAL은 루프를 완전히 풀어 주므로 더 이상 점프가 더 이상 발생하지 않습니다. 그리고 이것은 비 상수로 그렇게하는 것이 왜 어려운지를 설명합니다.

어쨌든 비 상수를 사용하는 것이 기술적으로 가능하지만 구현시 유니폼을 변경할 때마다 셰이더를 다시 컴파일해야하며 무의미한 조치를 제공 할 수있는 최대 명령 수에 부합 할 수 있습니다 번호.

그 이유는 무엇 때문입니까? 그것은 나쁜 상황입니다.

너무 큰 상수를 입력하면 셰이더를 빌드 할 때 "너무 많은 명령어"컴파일러 오류가 발생합니다. 자, 유니폼에 어리석은 숫자를 입력하면 HAL이 새로운 코드를 생성하고이 제한에 부딪혀 실행하면 OpenGL은 무엇을 할 수 있습니까?
컴파일하고 링크 한 후에 프로그램을 검증했을 가능성이 가장 높았으며, 아마도 쉐이더 정보 로그를 질의했을 것입니다. 그리고 OpenGL은 모든 것이 잘되었다고 말했습니다. 이것은 어떤면에서 구속력있는 약속이며, 갑자기 다른 것을 결정할 수는 없습니다. 따라서이 상황이 발생할 수 없도록해야하며 동적 분기를 지원하지 않는 하드웨어 세대의 조건에서 유니폼을 허용하지 않는 것이 유일한 실행 가능한 솔루션입니다.
그렇지 않으면 잘못된 값을 거부하는 glUniform 내부에 어떤 형식의 유효성 검사가 필요합니다. 그러나 이것은 성공적인 (또는 실패한) 셰이더 재 컴파일에 달려 있기 때문에 동 기적으로 실행해야하므로 "아무 것도하지 않는"방법이됩니다.또한 GL_ARB_uniform_buffer_object이 일부 SM2 하드웨어 (예 : GeForce FX)에 노출되어있는 것으로 간주합니다. 즉, OpenGL에서 예측할 수없는 내용의 버퍼 객체를 던져 버릴 수 있으며 여전히 어떻게 든 작동 할 것으로 예상됩니다. 당신이 매핑을 해제 한 후에 버퍼의 메모리에서 유효하지 않은 값을 스캔해야합니다. 이것은 미친 짓입니다.

루프와 유사하게 모양이 비슷하더라도 if() 문은 SM2 하드웨어에서 분기하지 않습니다. 대신, 두 분기를 계산하고 조건부 이동을 수행합니다.

2

(저는 픽셀 쉐이더에 대해 이야기하고 있다고 가정합니다).
두 번째 변형은 shader 모델> = 3을 지원하는 gpu에서만 작동합니다. 동적 분기 (변수 uNumLights을 IF 조건에 넣는 것과 같은)는 gpu 쉐이더 모델 < 3에서도 지원되지 않습니다.

Here 다른 쉐이더 모델간에 지원되는 기능과 지원되지 않는 기능을 비교할 수 있습니다. for() 하드웨어 전혀 (같은 방식으로 if()에 적용되는) 그것을 할 수 없기 때문에이없는 경우에도, 조건 분기가 있어야한다는 당신에게 알 수 있듯이

+0

현재 쉐이더 모델 2.0 만 지원하는 오래된 비디오 카드에 쉐이더를 쓰고 있습니다. 이상한 점은 두 번째 변형이 실제로 작동한다는 것입니다. 또는 적어도 오류없이 컴파일됩니다. 기능에 관한 한, break 명령이 트리거 될 때 중지되는지 여부는 확실하지 않습니다. 첫 번째 과정은 전혀 컴파일되지 않습니다. –

+0

그러나 @ dm.skt에서 설명한대로 두 번째 변형은 쉐이더 재 컴파일의 높은 위험 때문에 효과적이지 않습니다. 따라서 HAL에서만 지원되는 구문 구조 (하드웨어에서는 아님)에 의존하지 않고 성능 히트를 제공합니다 :-) –