2013-12-07 3 views
0

이 코드 스 니펫 (cubemap PCF 필터링 용)이 있습니다. 셰이더 모델 2를 위해 최적화하고 싶습니다. 유니폼에 저장된 순열 행렬을 사용하여 브랜치를 제거하려고 시도했지만 너무 많이 필요합니다 (2x24).쉐이더 코드 최적화

float3 l = normalize(ldir); 
float3 al = abs(l); 
float3 off2, off3, off4; 

if(al.x < al.y) 
{ 
    if(al.y < al.z) 
    { 
     // z is dominant 
     off2 = CubeOffset(l.zxy, float2(0, 1), texelsize).yzx; 
     off3 = CubeOffset(l.zxy, float2(1, 0), texelsize).yzx; 
     off4 = CubeOffset(l.zxy, float2(1, 1), texelsize).yzx; 
    } 
    else 
    { 
     // y is dominant 
     off2 = CubeOffset(l.yxz, float2(0, 1), texelsize).yxz; 
     off3 = CubeOffset(l.yxz, float2(1, 0), texelsize).yxz; 
     off4 = CubeOffset(l.yxz, float2(1, 1), texelsize).yxz; 
    } 
} 
else 
{ 
    if(al.x < al.z) 
    { 
     // z is dominant 
     off2 = CubeOffset(l.zxy, float2(0, 1), texelsize).yzx; 
     off3 = CubeOffset(l.zxy, float2(1, 0), texelsize).yzx; 
     off4 = CubeOffset(l.zxy, float2(1, 1), texelsize).yzx; 
    } 
    else 
    { 
     // x is dominant 
     off2 = CubeOffset(l, float2(0, 1), texelsize); 
     off3 = CubeOffset(l, float2(1, 0), texelsize); 
     off4 = CubeOffset(l, float2(1, 1), texelsize); 
    } 
} 

아마도 수학적 관계는 비교 (al.xyy < al.yzz) 및 스위 즐 사이에서 발견 될 수있다.

UPDATE : cubeoffset

float3 CubeOffset(float3 swiz, float2 off, float2 texelsize) 
{ 
    float3 ret; 

    ret.yz = swiz.yz + 2.0f * off * texelsize; 
    ret.x = sqrt(1.0f - dot(ret.yz, ret.yz)); 

    if(swiz.x < 0) 
     ret.x *= -1.0f; 

    return ret; 
} 

의 정의와 SM 2.0을 컴파일 HLSL 오류 :

error X5608: Compiled shader code uses too many arithmetic instruction slots (107). 
Max. allowed by the target (ps_2_0) is 64. 

error X5609: Compiled shader code uses too many instruction slots (111). 
Max. allowed by the target (ps_2_0) is 96. 

GLSL 잘 그것을 처리합니다. 목표는 이전 버전과의 호환성입니다.

은 (BTW. 알고리즘에 문제가있는 것입니다,하지만 지금 문제가 아닙니다) 정말 최적화

+0

'CubeOffset()'정의 – Drop

+0

을 추가하십시오. 나는 아마도 텍스처를 미리 계산할 것을 생각했다. – Asylum

+0

그건 그렇고, 최적화의 목적은 무엇인가? 지시 한도에 맞지 않습니까? 얼마나? – Drop

답변

0

SM 2.0으로 해결할 수 있는지 여부는 알 수 없지만 GPU 전원의 발전을 고려할 때 SM 3.0 솔루션을 제공합니다. CubeOffsetXXX가되고 싶어와

template <int samples> 
float PCFIrregularCUBE(sampler shadowmap, sampler noisetex, float3 ldir, float2 sloc, float2 texelsize) 
{ 
    const float kernelradius = 2.0f; 

    float3 l  = normalize(ldir); 
    float3 al = abs(l); 
    float2 noise; 
    float2 rotated; 

    float sd, t, s; 
    float d = length(ldir); 

    noise = tex2D(noisetex, sloc); 
    noise = normalize(noise * 2.0f - 1.0f); 

    float2 rotmat0 = float2(noise.x, noise.y); 
    float2 rotmat1 = float2(-noise.y, noise.x); 
    float3 off; 

    s = 0; 

    for(int i = 0; i < samples; ++i) { 
     rotated.x = dot(irreg_kernel[i], rotmat0) * kernelradius; 
     rotated.y = dot(irreg_kernel[i], rotmat1) * kernelradius; 

     if(al.x < al.y) { 
      if(al.y < al.z) 
       off = CubeOffsetZXY(l, rotated, texelsize); 
      else 
       off = CubeOffsetYXZ(l, rotated, texelsize); 
     } else { 
      if(al.x < al.z) 
       off = CubeOffsetZXY(l, rotated, texelsize); 
      else 
       off = CubeOffsetXYZ(l, rotated, texelsize); 
     } 

     sd = texCUBE(shadowmap, off).r; 

     t = ((d > sd) ? 0.0f : 1.0f); 
     s += ((sd < 0.001f) ? 1.0f : t); 
    } 

    return s * (1.0f/samples); 
} 

:이 코드는 내 자신의 쉐이더 언어에서 미리보기 (하지만 HLSL 유사)임을 염두에

보관하십시오 자세한 내용은

float3 CubeOffsetZXY(float3 swiz, float2 off, float2 texelsize) 
{ 
    float3 ret; 

    ret.xy = swiz.xy + 2.0f * off * texelsize * swiz.z; 
    ret.z = sqrt(1.0f - dot(ret.xy, ret.xy)); 

    if(swiz.z < 0) 
     ret.z *= -1.0f; 

    return ret; 
} 

당신 google for 불규칙한 PCF. ("카메라가 가까이"에서와 같이) 최악의 결과는 다음과 같습니다

cubemap irregular PCF shadow

공지 사항 불규칙한 PCF에 의한 "소금과 후추"노이즈. 멀리서 보면 그것은 완벽하게 수용 가능합니다 (Crysis 1 방법).

0

하지,하지만이를 테스트하는 것이 좋습니다.

분명히 항상 그런 것은 아니지만, 그런 경우에 가장 적합한 솔루션은 (지침 계산 등으로 인해) 맞지 않는 CPU 추가 코드로 이동하는 것입니다. 분기의 경우 다음을 수행 할 수 있습니다 조건 검사의 결과에 의해

  • 이동 분기 조건의 CPU
  • 분할 체크 별도의 쉐이더로 이동 지점의 몸
  • 바인드 적절한 쉐이더는

그것은이다 당신이 할 수있는 가장 간단한 일. 그리고 어셈블러에서 파고들 필요가 없습니다. 문제는 조건이 셰이더 내부에서 계산 될 때입니다.

어떻게 든 도움이 되길 바랍니다.

+0

조건은 쉐이더 내부에 있으므로 CPU로 옮길 수 없습니다 (ldir = wpos - lightpos). – Asylum