반응형

ComPtr com 객체들을 받아주는 스마트포인터 레퍼런스카운트가 0 이 될때 삭제된다

 

IID_PPV_ARGS

id 와 포인터를 만들어내는 define

위 함수가 IID_PPV_ARGS 를 받고 있는데 이것은 id 와 이중 포인터를 받고 있는 인자임을 알수 있고 IID_PPV_ARGS는 두개의인자를 넘겨주기 수월하게 만드는 define 이다

 

 

IDXGIFactory 디바이스 출력과 관련된 부분들 ex 스왑체인

 

DX12 에선 View ==  Descriptor 과 같은 의미로 통용된다

 

ID3D12DesecriptorHeap 디스크립터 힙 

 

D3D12_CPU_DESCRIPTOR_HANDLE 리소스 버퍼의 정보를 담고 있는 핸들(리소스를 gpu 에 알려주기 위한 리소스 주소 등을 담고 있음)

 

 

 

 

반응형
반응형

 

메쉬는 같은데 데이터 값만 다른 인스턴싱의 예시 이미지들..

 

 

 

 

 

https://learn.microsoft.com/ko-kr/windows/win32/api/d3d11/nf-d3d11-id3d11devicecontext-drawindexedinstanced

 

ID3D11DeviceContext::D rawIndexedInstanced(d3d11.h) - Win32 apps

인덱싱된 인스턴스화된 기본 형식을 그립니다. (ID3D11DeviceContext.DrawIndexedInstanced)

learn.microsoft.com

 

 

CPU 단에서 위치등을 지정하여 gpu 에 인스턴싱을 하기 위한 방법으로 다음의 것들을 쓸 수 있다

IASetVertexBuffers

- 물체의 정점의 구조세팅을 말함, 각 물체의 위치정보들을 넘겨주게 됨

 

즉 하나의 오브젝트를 여러 위치에 대해 여러번 그리는것

 

  1. 한번에 그릴 여러 위치에 대한 데이터를 CPU 단에서 모아서GPU 에 한번에 보낸다
  2. GPU 에 넘겨줄 인스턴스 파라미들은 예를 들어 월드, 뷰, 투영행렬 등의 정보를 넘길 수 있다
  3. 리소스 버퍼 또한 한번에 데이터를 묶어 보낼 만큼의 양을 확보한다
  4.  

정점 셰이더에서 입력으로 사용될 정보들이 추가로 있는 걸 알 수 있자 world, MV, MVP

보통 월드, 카메라, 투영을 전역으로 넘겨 받는데

 

위 VS_IN 에서 인스턴싱이 꼭 이런 데이터만 넘어오는 것은 아니지만 인스턴싱시 VS 에서도 데이터를 받아서 오브젝트마다 위치를 다르게 처리 할 수 있는 예시로 볼 수 있다 ( 오브젝트 메시는 동일하지만)

다시 말해 오브젝트마다 최소한의 다른 데이터만 넘겨 주어 렌더링 한다는 것이다

 

뭉처서 넘기는 만큼 드로우 콜 횟수가 줄어들게 됨으로 더 빠른 성능을 보인다

 

파티클 같은경우 최소한의 정점만 (보통 정점 1개) 만 통과 시켜 지오메트리 셰이더에서 파티클이 그려져야 하는경우

Plane 을 마들어 파티킬을 그려 인스턴싱의 효과를 더욱 극대화 할 수 있다

https://3dmpengines.tistory.com/2317

 

성능은 1.5~2배 이상의 성능 향상을볼 수 있다( 상황에 따라 다름)

 

 

 

 

 

 

반응형
반응형

 

 

 

 

 

뒤의 인자가 인스턴싱에 대한 처리의 개수를 얘기하는것으로 정점셰이더에서는 한번만 처리하고

인스턴싱 개수만큰 파이프라인에서 정점셰이더이후의 과정을 개수만큼 반복하게 되어 cpu 에서 gpu 로의 전송 과정을 아낄 수 있다

각 인스턴싱된 오브젝트들은 SV_InstanceID 로 구분할 수 있다
 
 

 

 
파티클들의 위치나 방향을 cpu 에서 gpu 로 넘겨주는게 아니라 gpu 내부에서 SturcturedBuffer 를gpu 쪽에 만들어 놓으면 gpu 내에서 현재 파티클의 정보를 g_data 에 넣고 이것에 대한 움직이는 정보를 RWStructuredBuffer 에다가 기록을 하여 파티클을 움직이도록 처리 할수 있다, GPU 내에서.
[t9 는 t 는 텍스처 같은 형태로 자료의 크기가 상수버퍼 처럼 정해져 있지 않는 것을 사용한다는 것 또한 알 수 있다]

 

그리고 물체들의 위치는 이전 단계인 Compute Shader 에서 위치를 먼저 계산해 놓게 된다

 

 

 

그려질 필요가 없다면 지오메트리 셰이더에서 파티클을 그리지 않는다

GS 는 도형 정보를 수정 할수 있따, 추가 및 제거

최적화를 위해 정점 하나만 받아서 정점이 살아 있지 않다면 정점을 더이상(메시를) 그리지 않는다
그려질 필요가 없다면 모든 정점을 받을 필요가 없기 때문

outputSteam 은 정점을 생성 할거라면 이곳에 정점들을 추가해 이 정점에 대한 메시를 그리게 된다

즉 outputSteam 이것이 비어져 넘겨지게 되면 아무것도 그리지 않는다는것

 

VIew space 주석이 있는 곳이 정점을 뷰시점에서 사각형을 만들어 outputSteam 에 추가해 사각형을 만들고 있다는 것을 알 수 있다

 

이렇게 처리하면 CPU 와 GPU 의 병복 현상을 많이 줄일 수 있어서 성능향상이 될 수있다

 

 

전체적인 순서를 컴퓨트 셰이더를 통하여 위치나 방향 생명주기를 먼저 계산한다음 이 정보를 GPU 배열에 저장해 놓고

이 정보를 그대로 정점셰이더와 지오메트리 셰이더를 지나면서 파티클을 그리는 순서이다

반응형
반응형

샘플러 상태 사용

연결된 텍스처와 샘플러

대부분의 경우 텍스처를 셰이더에서 샘플링할 때 텍스처 샘플링 상태는 텍스처 설정에서 나옵니다. 기본적으로 텍스처와 샘플러는 함께 결합되어 있습니다. 다음은 DX9 스타일 셰이더 구문을 사용할 때의 기본 동작입니다.

sampler2D _MainTex;
// ...
half4 color = tex2D(_MainTex, uv);

sampler2D, sampler3D, samplerCUBE HLSL 키워드를 사용하여 텍스처와 샘플러를 선언합니다.

대부분의 경우는 이 옵션이 적합하며, 구형 그래픽스 API(예: OpenGL ES)는 이 옵션만 지원합니다.

분리된 텍스처와 샘플러

많은 그래픽스 API와 GPU에서는 텍스처보다 적은 샘플러를 사용할 수 있으며, 연결된 텍스처+샘플러 구문으로 인해 더 복잡한 셰이더를 작성하지 못할 수도 있습니다. 예를 들어, Direct3D 11은 한 셰이더에 최대 128개의 텍스처와 16개의 샘플러를 지원합니다.

Unity는 DX11 스타일 HLSL 구문으로 텍스처와 샘플러를 선언할 수 있으며, 특수한 명명 규칙으로 일치시킵니다. “sampler”+TextureName 형식의 이름을 가진 샘플러는 샘플링 상태를 해당 텍스처에서 가져옵니다.

위 섹션의 셰이더 스니핏은 DX11-style HLSL 구문으로 재작성해도 같은 동작을 합니다.

Texture2D _MainTex;
SamplerState sampler_MainTex; // "sampler" + "_MainTex"
// ...
half4 color = _MainTex.Sample(sampler_MainTex, uv);

그러나 이렇게 하면 한 개 이상의 텍스처를 샘플링하면서 샘플러를 다른 텍스처에서 “재사용”하게 셰이더를 작성할 수 있습니다. 아래 예제에서는 3개의 텍스처에 하나의 샘플러만을 사용합니다.

Texture2D _MainTex;
Texture2D _SecondTex;
Texture2D _ThirdTex;
SamplerState sampler_MainTex; // "sampler" + "_MainTex"
// ...
half4 color = _MainTex.Sample(sampler_MainTex, uv);
color += _SecondTex.Sample(sampler_MainTex, uv);
color += _ThirdTex.Sample(sampler_MainTex, uv);

그러나 DX11-style HLSL 구문은 일부 구형 플랫폼(예: OpenGL ES 2.0)에서는 동작하지 않는다는 점에 유의하십시오. 자세한 내용은 Unity에서 HLSL 사용를 참조하십시오. #pragma target 3.5(셰이더 컴파일 타겟 참조)을 지정해 구형 플랫폼이 해당 셰이더를 건너뛰도록 할 수 있습니다.

Unity는 이 “분리된 샘플러” 접근 방법을 사용한 선언과 텍스처 샘플링에 도움이 될만한 여러 셰이더 매크로를 제공하고 있으니 빌트인 매크로를 참조하십시오. 위의 예제는 이 매크로를 사용해 이렇게 재작성할 수 있습니다.

UNITY_DECLARE_TEX2D(_MainTex);
UNITY_DECLARE_TEX2D_NOSAMPLER(_SecondTex);
UNITY_DECLARE_TEX2D_NOSAMPLER(_ThirdTex);
// ...
half4 color = UNITY_SAMPLE_TEX2D(_MainTex, uv);
color += UNITY_SAMPLE_TEX2D_SAMPLER(_SecondTex, _MainTex, uv);
color += UNITY_SAMPLE_TEX2D_SAMPLER(_ThirdTex, _MainTex, uv);

위는 Unity가 지원하는 모든 플랫폼에서 컴파일할 수 있지만 DX9 같은 구형 플랫폼에서는 3개의 샘플러를 사용하도록 폴백합니다.

인라인 샘플러 상태

“sampler”+TextureName 이름의 HLSL SamplerState 오브젝트 외에도 Unity는 샘플러 이름의 다른 패턴도 인식합니다. 간단하게 하드코드된 샘플링 상태를 셰이더에 바로 선언할 때 유용합니다. 예를 들면, 다음과 같습니다.

Texture2D _MainTex;
SamplerState my_point_clamp_sampler;
// ...
half4 color = _MainTex.Sample(my_point_clamp_sampler, uv);

“my_point_clamp_sampler” 이름은 포인트(가장 가까운) 텍스처 필터링과 클램프 텍스처 랩 모드를 사용하는 샘플러로 인식됩니다.

샘플러 이름은 “inline” 샘플러 상태로 인식됩니다(대소문자 구분).

  • “Point”, “Linear” 또는 “Trilinear”(필수)는 텍스처 필터링 모드를 설정합니다.
  • “Clamp”, “Repeat”, “Mirror” 또는 “MirrorOnce”(필수)는 텍스처 랩 모드를 설정합니다.
    • 랩 모드는 축(UVW)에 지정할 수 있습니다. 예를 들어, “ClampU_RepeatV”
  • “Compare”(선택)는 뎁스 비교용 샘플러를 설정합니다. HLSL SamplerComparisonState 타입과 SampleCmp/SampleCmpLevelZero 함수를 사용합니다.
  • “AnisoX”(X는 2/4/8 또는 16일 수 있음. 예: Ansio8)를 추가하여 이방성 필터링을 요청할 수 있습니다.

다음은 각각 sampler_linear_repeat 샘플링 텍스처와 sampler_point_repeat SamplerState의 예제로, 이름이 필터링 모드를 조절하는 방식을 보여줍니다.

다음은 각각 SmpClampPoint, SmpRepeatPoint, SmpMirrorPoint, SmpMirrorOncePoint, Smp_ClampU_RepeatV_Point SamplerState의 예제로, 이름이 랩 모드를 조절하는 방식을 보여줍니다. 이 마지막 예제에서는 가로(U)와 세로(V) 축에 대해 다른 랩 모드가 설정되었습니다. 모든 경우에 텍스처 좌표는 –2.0 - +2.0입니다.

분리된 텍스처+샘플러 구문과 마찬가지로 인라인 샘플러 상태가 모든 플랫폼에서 지원되지는 않습니다. 현재는 Direct3D 11/12 및 Metal에서 구현됩니다.

참고로, “MirrorOnce” 텍스처 랩 모드는 대부분의 모바일 GPU/API에서 지원되지 않고, 이런 경우 Mirror 모드로 폴백합니다.

“AnisoX” 필터링 모드는 플랫폼 기능과 일부 API에서 최선의 수단입니다. 실제 값은 지원되는 최대 이방성 수준에 기반하여 고정됩니다(이방성 필터링이 지원되지 않는 경우의 비활성화 포함).

 

https://docs.unity3d.com/kr/current/Manual/SL-SamplerStates.html

반응형
반응형

픽킹이란 2D 스크린 좌표를 3D 좌표로 변경한 후 동일한 공간 내에서 교차 판정 하는 것이다.

 

여기서 중요한 것은 2D 좌표를 3D 좌표로 변경한다는 것이고, 동일한 공간! 내에서 교차판정한다는 것이다.

동일한 공간이 중요하다.

지형의 좌표가 존재하는 공간이 월드 공간이기 때문에 반드시 월드 공간으로 바꿔줘야한다.

 

과정을 간단히 말하자면,

1. 윈도우 좌표를 3D 좌표로 변경시킨다.

2. 폴리곤과 충돌체크를 한다. (IntersectTriangle)

이다.

 

픽킹이 처음에 어렵게 느껴지는 이유는 이 IntersectTriangle 함수가 프로그램을 위해 최적화된 함수로 몇몇 과정들이 축소되어있기 때문이다.

 

 

( Picking에 관한 코드는 Dx SampleBrowser에도 존재 하니 그걸 참고하세용 ~ 저도 그걸 참고해서 했어용>,<! )

 

 

먼저 2D 좌표에서 3D 공간 Ray를 뽑아내는 것을 보겠다.

 

 

<설명>

 

1) 윈도우 좌표를 알아낸 후

 

2) 공식을 통해 3D 좌표로 변경시킨다.

 

3) m_vOrig 는 카메라의 위치이고, m_vDir은 Ray의 방향이다. 

m_vDir에 3D 벡터 Ray를 설정한다.

 

4) 카메라 공간 좌표를 월드 공간 좌표로 변경하기 위해 뷰행렬의 역행렬을 곱한다.

여기서 주의해야 할 점은 m_vOrig는 D3DXVec3TransformCoord이고, m_vDir은 D3DXVec3TransformNormal라는 점이다.

왜냐하면 Coord는 위치를 변환하는 것이고, Normal은 벡터를 변환하는 것이다.

 

5) m_vDir 을 정규화하면 Ray가 완성된다.

 

 

이제 폴리곤과 충돌체크를 하는 IntersectTriangle 함수를 알아보겠다.

앞서 말했듯 이 함수는 몇몇 식이 축약됬기 때문에 이해하기가 어렵다.

 

BOOL IntersectTriangle

(D3DXVECTOR3& v0,D3DXVECTOR3& v1,D3DXVECTOR3& v2, FLOAT* t,FLOAT* u,FLOAT* v);

 

m_vOrig는 월드 공간 상의 카메라의 원점이고, m_vDir은 Ray의 방향이다.

v0, v1, v2  삼각형 정점의 위치이다. 

t vOrig에서 v0까지의 거리이다.

u v0에서 v1의 비율이고, v v0에서 v2의 비율이다

 

 

 

점 p(벡터 p)가 v0,v1,v2내에 있는지 판단하는 방법은 벡터로 한다. 

만약, 삼각형을 △OAB라고 할 때, 벡터 P가 삼각형 내에 있을 조건

 

1) u ≥ 0

2) v ≥ 0

3) u + v ≤ 1 

 

이다. 때문에 u와 v를 구해 점 p가 폴리곤 내에 있는지 판단한다. 

 

 

 

 

위 그림을 보면

 

v = |Ob|/|OB| 이다. (왜냐하면, |OB|= |Ob| * v 니까.)

 

nA라는 A의 법선벡터를 구한다.

 

 

 

v = |Ob|/|OB|

 

이 식의 분모와 분자에 nAcosΘ 를 곱한다.

 

v = |Ob| nAcosΘ /|OB| nAcosΘ 

 

이것은 내적을 풀어쓴 것으로 

 

v = Ob · nA / OB · nA 

라고 할 수 있다.

 

그런데 nA에 투영했을 때, OP와 Ob의 정사영이 같으므로 

 

v = OP · nA / OB · nA

 

라고 할 수 있다. 이와 마찬가지로 

 

u = OP · nB / OA · nB

 

라고 할 수 있다.

 

 

N을  v0와 v2의 평면의 법선벡터라고 하자.

여기서 (vOrig – v0) · N = (P – v0) · N 의 정사영이 같음을 볼 수 있다.

따라서 N = vDir × (v2 – v0) 이다. 

 

 

t는 거리라고 했다.

 

tvec = vOrig – v0

e1 = v1 – v0

e2 = v2 – v0

 

라고 하자.

 

u = OP · nB / OA · nB

 

에서 OP는 거리이므로 tvec으로 고칠 수 있다. 그리고 nB는 위에서 법선벡터 N을 구했으므로 vDir x e2 라고 할 수 있다.

 

따라서, 

 

u = tvec · (vDir x e2) / e1 · (vDir x e2) 
v = tvec · (vDir x e1) / e2 · (vDir x e1) 
 
이렇게 구한 u와 v를 통해 p가 삼각형 내에 있는지 판단하는 것이다.
 
IntersectTriangle은 이 식을 풀어서 쓴 것이다.
 
마지막으로 거리 t 를 구하기 위해서 분모를 fDet로 놓는다.
 
fDet = e1 · (vDir x e2) = vDir · (e1 x e2)
 
[ fDet 가 0이면, Ray가 같은 평면이고, 0보다 작으면 뒤에서 쏜 Ray, 0보다 크면 앞에서 쏜 Ray이다. ]
[평면의 방정식이 0보다 크면 Ray가 앞에 있는 것이다.]
 

 

 
위의 식에서
 
|P - vOrig | = t * |vDir |
 
이다. 따라서
 
t = |P - vOrig |/ |vDir |
 
분모, 분자에 |N|cosΘ 를 곱하면
 
t = |P - vOrig | |N|cosΘ  / |vDir | |N|cosΘ 
 
이고, 이것은 내적을 풀어쓴 것이므로 정리하면
 
t = (P - vOrig) · N / vDir · N 
 
이다. 근데 (P - vOrig)과 –tvec의 법선벡터 N에 대한 정사영이 같으므로
 
t = -tvec · N / vDir · N 
 
이다.
 

 

 

ref : https://showmiso.tistory.com/140

반응형
반응형

흔히 쓰이는 렌더링 효과 중에는 한 단계에서 GPU가 자원 R에 자료를 기록하고, 이후의 한 단계에서 그 자원 R의 자료를 읽어서 사용하는 식으로 구현하는 것들이 많다. 그런데 GPU가 자원에 자료를 다 기록하지 않았거나 기록을 아예 시작하지도 않은 상태에서 자원의 자료를 읽으려 하면 문제가 생긴다. 이를 자원 위험 상황(Resource hazard)이라고 부른다.

 

이 문제를 해결하기 위해, Direct3D는 자원들에게 상태를 부여한다. 새로 생성된 자원은 기본 상태(default state)로 시작한다. 임의의 상태 전이를 Direct3D에게 '보고'하는 것은 전적으로 응용 프로그램의 몫이다. 

 

여러 리소스 상태들

이 덕분에, GPU는 상태를 전이하고 자원 위험 상황을 방지하는 데 필요한 일들을 자유로이 진행할 수 있다. 예를 들어 텍

응용 프로그램이 상태 전이를 Direct3D에게 보고함으로써, GPU는 자원 위험을 피하는 데 필요한 조치를 할 수 있다.(이를테면 모든 쓰기 연산이 완료되길 기다린 후에 자원 읽기를 시도하는 등)

 

상태 전이를 보고하는 부담을 프로그래머에게 부여한 것은 성능 때문이다. 응용 프로그램 개발자는 그러한 전이들이 언제 일어나는지 미리 알고 있다. 만일 이러한 전이를 자동으로 추적하게 한다면 성능에 부담이 생긴다.

 

자원 상태 전이는 전이 자원 장벽(Transition resource barrier)들의 배열을 설정해서 지정한다. 배열을 사용하는 덕분에, 한 번의 API 호출로 여러 개의 자원을 전이할 수 있다. 코드에서 자원 장벽은 D3D12_RESOURCE_BARRIER_DESC 구조체로 서술된다. 

 

다음 메서드를 호출하여 위 구조체를 사용한 자원 장벽을 설정할 수 있다.

 

다음은 호출 예를 보여주는 코드이다.

mCommandList->ResourceBarrier(1, 
&CD3DX12_RESOURCE_BARRIER::Transition(
CurrentBackBuffer(),
D3D12_RESOURCE_STATE_PRESENT,
D3D12_RESOURCE_STATE_RENDER_TARGET));

이 코드는 화면에 표시할 이미지를 나타내는 텍스처 자원을 제시 상태(Presentation state)에서 렌더 대상 상태로 전이한다. 자원 장벽이 명령 목록에 추가됨을 주목하기 바란다. 전이 자원 방벽이라는 것을, GPU에게 자원의 상태가 전이됨을 알려주는 하나의 명령이라고 생각하기 바란다. 명령을 통해서 자원 상태 전이를 알려주는 덕분에, GPU는 이후의 명령들을 실행할 때 자원 위험 상황을 피하는 데 필요한 단계들을 밟을 수 있다. 

 

 

ref : https://lipcoder.tistory.com/60

반응형
반응형

 

 

 

 

dx 는 왼손 법칙을 사용

opengl 은 오른손 법칙 사용

 

그래서 깊이가 서로 반대로 표현 되게 됩니다

 

 

깊이에 관련된 내용중 하나는 아래와 같은 것이 있습니다

 

 

동차 좌표란 투영행렬연산 까지 거친 좌표를 말하는데

투영행렬까지 연산을 하면  x,y 가  -1~1 그리고 z 는 0~1 사이 범위로 아직 가있지 않게 되고

이것을 동차 좌표라 합니다(동차 절단공간Homogeneous clip space)

 

이때 투영행렬가지 연산 된것을 z 로 나누게 되면 그제서야 직사각형 

 x,y 가  -1~1 그리고 z 는 0~1 

의 범위안에 들어오게 됩니다

 

 

나눈 좌표를 Normalized Coordination space 라 합니다

 

 

반응형
반응형

텍스쳐 한 장을 받는 쉐이더 스크립터를 만들어준다.

램버트 라이팅 세팅으로

 

Shader "Custom/Test"
{
    Properties
    {
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 200

        CGPROGRAM
        #pragma surface surf Lambert

        sampler2D _MainTex;

        struct Input
        {
            float2 uv_MainTex;
        };

        void surf (Input IN, inout SurfaceOutput o)
        {
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex);
            o.Albedo = c.rgb;
            o.Alpha = c.a;
        }
        ENDCG
    }
    FallBack "Diffuse"
}

 

----

 

큐브맵을 받을수 있는 프로퍼티를 뚫는다 .

 

 

큐브맵을 받는 형식은 Cube로

 

윈도우 - 렌더링 - 라이팅 세팅에 넣어야한다.

 

 

먼저

 

 

메터리얼에 큐브맵을 넣어준다.

 

 

메터리얼을 스카이박스메터리얼에 넣어준다.

★ 책에서 나온게 버전업 되면서 바뀌었다.

우리가 만든 메테리얼을 넣는게 아니라 검색해서 넣어야한다.

 

우리가 만든 메테리얼은 로봇에다가 넣을 것 이기 때문에

 

로봇 켈리 넣고,

메터리얼 넣고

 

 

sky박스가 반사되도록 만들것이다.

 

 

Input 에

 

 

 

월드 리플렉션이 있음 이걸 사용

 

이걸 똑같이 안쓰면 하드한 리플렉션 공식을 넣어야함

 

 

texCUBE (엔디비아 CG 용어)를 사용해서 이미지를 넣어야한다.

 

 

texCUBE(큐브텍스트 이미지 , 월드 리플렉션) = float4 로 반한

 

 

이미지션에 넣어서 테스트 하기

 

Shader "Custom/Test"
{
    Properties
    {
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _Cube ("CubeMap", Cube) = "white" {}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 200

        CGPROGRAM
        #pragma surface surf Lambert

        sampler2D _MainTex;
        samplerCUBE _Cube;

        struct Input
        {
            float2 uv_MainTex;
            float3 worldRefl;
        };

        void surf (Input IN, inout SurfaceOutput o)
        {
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex);
            float4 ref =  texCUBE(_Cube, IN.worldRefl);
            o.Albedo = c.rgb;
            o.Emission = ref.rgb;
            o.Alpha = c.a;
        }
        ENDCG
    }
    FallBack "Diffuse"
}

 

 

 

 

반사되는걸 확인 가능

 

이미션에 넣는 이유, 밝고 어두움을 반사하는데 빛을 넣는다고 밝아 지는게 아니기 때문에 (거울 예제)

 

지금은 흰색인 이유는 알베도에 흰색에 있고, 이미션에도 있어서 1이 넘어서 그럼

 

// 알베도랑 이미션을 같이 쓰면 밝아진다.

 

그래서 알베도를 0으로 만들고, 이미션에 반사된 값을 출력해보자

 

 

---

 

노멀을 넣으면 오류가 생긴다 .

 

 

 

 

이터널 데이터를 써줘야한다

 

 

이터널 데이터를 써주지 않으면

 

★ 월드 리플렉션이랑 월드 노멀을 같이 쓸수가 없다.

 

인풋에 넣어주고

 

 

 

노멀을 넣으면 월드 노멀을 넣ㅇ어줘야한다

 

 

 

노멀에 해당하는 반사벡터를 얻을려면 WorldReflctionVector 써줘야함

노멀을 먼저 쓰고 그걸 받아서 써주는 것이다 !

float4 ref = texCUBE(_Cube, WorldReflectionVector(IN, o.Normal));

 

 

----

Shader "Custom/Test"
{
    Properties
    {
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _Normal ("Normal (RGB)", 2D) = "white" {}
        _Cube ("CubeMap", Cube) = "white" {}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 200

        CGPROGRAM
        #pragma surface surf Lambert

        sampler2D _MainTex;
        samplerCUBE _Cube;
        sampler2D _Normal;
        struct Input
        {
            float2 uv_MainTex;
            float3 worldRefl;
            float2 uv_Normal;
            INTERNAL_DATA
        };

        void surf (Input IN, inout SurfaceOutput o)
        {
            o.Normal = UnpackNormal(tex2D(_Normal, IN.uv_Normal));
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex);
            float4 ref =  texCUBE(_Cube, WorldReflectionVector(IN, o.Normal));

            o.Albedo = 0;
            o.Emission = ref.rgb;
            o.Alpha = c.a;
        }
        ENDCG
    }
    FallBack "Diffuse"
}

 

 

 

 

 

 

----

 

총 과정

 

메터리얼 하나 받는 쉐이더 작성

기본 Lambert 라이트 모델 적용

큐브맵을 받게 프로퍼티 작성

타입을 Cube

변수선언시 타입을 samplerCUBE로

Input 구조체에 worldRefl 정의

texCUBE 함수를 사용해 큐브맵 적용 (_Cube, IN.worldRefl)

결과값이 re 값을 확인(Emission에서)

범프 텍스쳐 넣을 수 있게 속성정의

노멀이 적용된 반사벡터를 구하기 위해서 WorldReflectionVector함수 사용

결과 확인 (Emission)


노말맵을 추가시켰더니 에러가 난다. 에러 내용을 대충 훑어보면

 

Shader error in 'Custom/Post_Work1': Surface shader Input structure needs

INTERNAL_DATA for this WorldNormalVector or WorldReflectionVector usage at

line 200 (on d3d11)

 

INTERNAL_DATA , WorldNormalVector, WorldReflectionVector 관련해서

키워드를 얻을 수 있어서 유니티 홈페이지에서 찾아보았다.

 

정확히는 무슨 말인지는 모르겠지만 worldRefl을 사용할 때 노말 맵을 쓸 경우

WorldReflectionVector를 사용하는데, 픽셀당 반사 벡터를 사용하기 위해

Input구조체에서 INTERNAL_DATA를 선언해서 뭔가 컴파일해주는 듯..?

 

좀 더 쉽게 설명하면 탄젠트 좌표계를 월드 좌표계로 변환시켜주어야 하는데

그 과정에서 변환이 되지 않아 에러가 났던 것이고 INTERNAL_DATA를 통해서

변환해주는 듯하다. (자세한 것은 모르겠다..)

 

유니티가 PBR로 바뀌면서 이런 식으로 큐브 맵 사용이 변경되었다 한다.

그러면 일단 한번 수정해보자.

struct Input { float2 uv_MainTex, uv_NormalMap; float3 worldRefl; INTERNAL_DATA }; void surf (Input IN, inout SurfaceOutput o) { fixed4 c = tex2D (_MainTex, IN.uv_MainTex); o.Normal = UnpackNormal(tex2D(_NormalMap, IN.uv_NormalMap)); o.Emission = texCUBE(_CubeMap, WorldReflectionVector(IN, o.Normal)); o.Albedo = c.rgb; o.Alpha = c.a; }

헬멧 MaskMap 추가

만들었던 큐브맵 머티리얼을 헬멧 모델에 적용하여

금속 재질인 것처럼 표현하고 마스크 맵을 적용하여 부분적으로 적용되도록 해보겠다.

Shader "Custom/Post_Work1"
{
    Properties
    {
        _MainTex("Albedo (RGB)", 2D) = "white" {}
        _NormalMap("NormalMap", 2D) = "bump" {}
        _MaskMap("MaskMap", 2D) = "bump" {}    
        _CubeMap("CubeMap", cube) = "" {}
 
        [HDR]_Color("Color", color) = (1,1,1,1)
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
 
        CGPROGRAM
        #pragma surface surf Lambert 
        #pragma target 3.0
 
        sampler2D _MainTex, _NormalMap, _MaskMap;
        samplerCUBE _CubeMap;
 
        struct Input
        {
            float2 uv_MainTex, uv_NormalMap, uv_MaskMap;
            float3 worldRefl;
            INTERNAL_DATA
        };
 
        float4 _Color;
 
        void surf (Input IN, inout SurfaceOutput o)
        {
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex);
            fixed4 m = tex2D(_MaskMap, IN.uv_MaskMap);
 
            o.Normal = UnpackNormal(tex2D(_NormalMap, IN.uv_NormalMap));
            o.Emission = texCUBE(_CubeMap, WorldReflectionVector(IN, o.Normal)) * m.a * _Color;
            o.Albedo = c.rgb;
            o.Alpha = c.a;
        }
        ENDCG
    }
    FallBack "Diffuse"
}

Reflection Probe 사용하기

리플렉션 프로브란 해당 오브젝트를 배치하여 구역 내에 주변 static오브젝트들을

캡처하여 큐브 맵 데이터로 저장하는 기능이다.

 

 


void surf (Input IN, inout SurfaceOutput o)

{

fixed4 c = tex2D (_MainTex, IN.uv_MainTex);

fixed4 m = tex2D(_MaskMap, IN.uv_MaskMap);


o.Normal = UnpackNormal(tex2D(_NormalMap, IN.uv_NormalMap));


fixed3 wr = WorldReflectionVector(IN, o.Normal);

//fixed3 p = texCUBE(_CubeMap, wr);

fixed3 r = UNITY_SAMPLE_TEXCUBE(unity_SpecCube0, wr) * unity_SpecCube0_HDR.r;


o.Emission = r * m.a;

o.Albedo = c.rgb;

o.Alpha = c.a;

}

유니티에서 리플렉션 프로브로 큐브 맵을 받기 위해서는 UNITY_SAMPLE_TEXCUBE()를 사용해야 한다.

unity_SpecCube0, unity_SpecCube0_HDR은 리플렉션 프로브 데이터를 가지고 있으며,

unity_SpecCube가 아니라 unity_SpecCube0이 붙은걸 보면 뒤에 1도 존재한다는 것도 알 수 있고

HDR도 1이 존재한다.

 

이를 설명하기 위해서 오브젝트 Mesh Renderer 인스펙터 부분을 보면 Light Probes에

Blend Probes라는 항목이 존재하는데, 리플렉션 프로브 영역으로 이동할 때 리플렉션 이미지가 갑자기 바뀌는 것을 방지하기 위해 블렌딩 해주는 것이라고 한다.

 

 

 

 

 

ref : https://minquu.tistory.com/161

ref : https://bornsoul.tistory.com/15

반응형
반응형

반지름 r 인 구의 표면적 구하는 공식은

 

입니다.

평면에 수직으로 비친 구의 그림자는 원입니다.

이 그림자 원의 면적은

 

입니다.

즉, 반지름이 r 인 구의 표면적은 그림자 면적의 4배가 됩니다.

출처: 3Blue1Brown YouTube Channel

구의 표면적 구하는 공식이 생각나지 않을 때 그림자의 4배를 기억해보면 됩니다.

또한, 구의 지름 높이만큼 구를 둘러싼 원통의 표면적과도 같습니다.

아래 그림에서 원통 측면의 표면적은 원주율에 높이를 곱한 것이므로

입니다.

출처: 위키백과

구의 표면적 구하는 공식이 생각나지 않을 때 기억해보면 됩니다.

다음 그림을 보면 구와 원통의 관계를 알 수 있습니다.

지름과 높이가 구의 지름과 같은 원통측면의 표면적이 어떻게 구의 표면적과 같아지는지 그림으로 쉽게 설명이 됩니다.

출처: 3Blue1Brown YouTube Channel

구와 관련된 공식들을 정리해봤습니다.

구(sphere)의 지름(diameter): D = 2r

구의 둘레(circumference) : C = πD = 2πr

구의 표면적(surface area) : A = 4πr2

구의 체적(volume) : V = (4/3)πr3


 

빛의 성질-5 (Characteristics of Light-5): 빛의 방사와 조사(Radiance and Irradiance of Lights), 입체각(Solid Angle)

 

일단 기계공학 전공자의 입장에서는 빛이라는 것을 다를  장님 코끼리 다리 만지듯이 헷갈리는 것이   가지가 아닙니다.

요즘 강의나가는 대학의 박사과정 학생과 둘이서 몬가를 아주 욜심히 하고 있기에 구찮지만 빛에 대해 기본적으로 알아야  것이 많이 생기고 있습니다. 갑자기 색깔,  Color 대해서 엄청난 궁금증이 생긴 관계로… (논문이 될려나?? 만일 안되몬 이 짜슥이 내 죽일려고 할텐데...)  ^_^!

암튼 색깔이고 지랄이고 간에 빛이 밝다!” 혹은 빛이 어둡다!!”라고   무엇을 기준으로 하는지에 대한 것부터 알아야만 합니다.

여기 저기 빛의 세기에 관해 찾아보니 “Radiance” “Irradiance”라는 용어가 먼저 튀어나옵니다. ~ 몰랑몰랑~~ 일단 한국물리학회(The Koran Physics Society)에서 발간한 물리학 용어집을 찾아보니 “Radiance” “(복사)휘도라고 번역해놓았지만 아쉽게도 “Irradiance”라는 용어에 대해서는 물리학 용어집에서 번역어를 찾을 수가 없군요. 참고로 Journal of the Korean Physics Society는 SCI(SCI IF=0.493)입니다. 한 14~15년 전에 논문 3편 실은 기억이 있네요... 그 때는 SCI IF 1.0 이상이었는데... 쩝!! 만일 JKPS의 IF가 3.0 이상으로 올라가면 이 곳에 논문을 다시 낼 의향은 충분히 있습니다... ^_^!!

영어사전에서는 “Irradiance” 조사(照射), 조도(照度)”라고 번역하고 있습니다. 우리가 흔히 현광등과 같은 조명장치를 이야기   사용하는 한자인 비칠 ()” 사용하고 있습니다.

그럼 빛을 받는 것인가(수광)? 빛을 발하는 것인가(발광)?? “Radiance” “Irradiance” 분명 다른 의미일 것입니다. 그러니까 당연히 단어가 다르겠지요. 구글링(Gooling) 하니 다음과 같은 그림이 나오는군요.

 

몬지는 몰겠지만 [Fig.1] 보니 “Irradiance” 빛을 받는 것이고 “Radiance” 빛이 나가는 것이군요. 그렇다면 “Irradiance” 빛의 입사(들어오는)강도, “Radiance” 빛의 방사(나가는)강도 받아들이면 되겠습니다.

그렇다면 이젠  놈들의 정의와 단위에 대해서 생각해보아야 합니다. 만일 인터넷이라는 것이 없었다면  같이 무식한 인간은 어찌 하였을꼬??? 인터넷의 바다로 다시 퐁당~~

 

What is Solar Irradiance?

Irradiance is the amount of light energy from one thing hitting a square meter of another each second.

(출처https://www.nasa.gov/mission_pages/sdo/science/solar-irradiance.html)

 

 유명한 넘사벽인 NASA임에도 영어가 별로 내요 약간 애매모호한 표현입니다. 저도 영어를  못하지만  생각을 구겨 넣은 의역을 대충 해보면 어떤 광원으로부터 방출되는  에너지가 다른 어떤 표면에 대해서 단위시간당 단위면적당 입사되는(두들겨 패버리는) 총에너지량이다.” 정도로 받아들이면 되겠습니다.

 

그렇다면 단위는 당연히 J/(m2·s) 것이고, 따라서 W/ m2입니다.

가장 쉬운 예가 태양이라는 광원에서 지구의 지표면에 쏟아지는 태양광일 것입니다. 내가  있는 1.0 m2 지표면에 1.0 초당 쏟아지는 태양빛 에너지의  총량을 태양광 입사량,  “Solar Irradiance”라고 합니다.

이제 “Radiance” 알아보기 위해 구글의 이미지 검색을 하니 단색광(Monochromatic Ray) 대한 정의를 [Fig.2] 그림으로 표현하고 있습니다. 그런데  놈의 dW 뭐지? 굳이 우리말로 나타내자면 입체각(Solid Angle) 나타내는 것입니다.

각도(Angle) 측정에는  아시다시피 Degree(o) Radian(rad) 사용하지만 Steradian(sr)이라는 입체각도 사용합니다.

강의를 하다 보면 대학생들임에도 불구하고 학생들이 각도가 단위를 가지는 물리량으로 착각을 하는 경우가 상당히 많은데 각도는 단위를 가지지 않는 무차원(Dimensionless)입니다. 즉, 단순히 숫자를 나타내는 것입니다. 지금 내가 말하고 있는 숫자가 그냥 단순히 숫자를 나타내는 것이 아니고 각도의 의미로 사용하고 있다는 것을 상대방에게 알려주기 위해서 편의상 o, rad, sr 붙여주는 것에 불과합니다.

......

중략..

......

제 기준에서만 말하자면 “Radiance” “Irradiance”의 단위로부터 강도 혹은 세기(Intensity)라는 용어보다는 단위시간당(per unit time) 단위면적당(per unit area)의 에너지량이라는 용어가 더 어울릴 것 같습니다. 일종의 유속(Flux)입니다.

ref : https://blog.naver.com/choi_s_h/221405669446

 

 

 

반응형
반응형

루트 서명 예제

 

다음 섹션에서는 비어 있음부터 완전 가득 참까지 복잡성이 다양한 루트 서명을 보여 줍니다.

빈 루트 서명

빈 루트 서명은 별로 유용하지 않을 수 있지만, 입력 어셈블러만 사용하는 간단한 렌더링 패스와 설명자에 액세스하지 않는 최소 꼭짓점 및 픽셀 셰이더에 사용할 수 있습니다. 또한 혼합 단계, 렌더링 대상 및 깊이 스텐실 단계에서도 빈 루트 서명을 사용할 수 있습니다.

단일 상수

API 바인딩 슬롯에서는 이 매개 변수의 루트 인수가 명령 목록 기록 시에 바인딩됩니다. API 바인딩 슬롯 수는 루트 서명의 매개 변수 순서에 따라 암시적입니다(첫 번째는 항상 0). HLSL 바인딩 슬롯에서 셰이더는 루트 매개 변수가 표시되는 것을 알 수 있습니다. 형식(위 예제의 "uint")은 하드웨어에 알려지지 않으며 이미지의 주석으로만 표시됩니다. 하드웨어는 콘텐츠로 단일 DWORD만 알 수 있습니다.

명령 목록 기록 시간에 상수를 바인딩하려면 다음과 비슷한 명령을 사용할 수 있습니다.

syntax복사
pCmdList->SetComputeRoot32BitConstant(0,seed); // 0 is the parameter index, seed is used by the shaders

루트 상수 버퍼 뷰 추가

이 예제에서는 두 개의 루트 상수와 DWORD 슬롯 2개에 상응하는 루트 CBV(상수 버퍼 뷰)를 보여 줍니다.

상수 버퍼 뷰를 바인딩하려면 다음과 같은 명령을 사용합니다. 첫 번째 매개 변수(2)는 이미지에 표시되는 슬롯입니다. 일반적으로 상수 배열이 설정된 후 셰이더의 b0에서 CBV로 사용할 수 있게 됩니다.

syntax복사
pCmdList->SetGraphicsRootConstantBufferView(2,GPUVAForCurrDynamicConstants);

설명자 테이블 바인딩

이 예제에서는 두 설명자 테이블의 사용을 보여 줍니다. 하나는 CBV_SRV_UAV 설명자 힙에서 실행 시 사용할 수 있는 5개의 설명자 테이블을 선언하고 다른 하나는 샘플러 설명자 힙에서 실행 시 표시될 두 설명자의 테이블을 선언합니다.

명령 목록을 기록할 때 설명자 테이블을 바인딩하려면

syntax복사
pCmdList->SetComputeRootDescriptorTable(1, handleToCurrentMaterialDataInHeap);
pCmdList->SetComputeRootDescriptorTable(2, handleToCurrentMaterialDataInSamplerHeap);

루트 서명의 또 다른 기능은 크기가 4개 DWORD인 float4 루트 상수입니다. 다음 명령은 4개 중에서 가운데에 있는 두 DWORD만 바인딩합니다.

syntax복사
pCmdList->SetComputeRoot32BitConstants(0,2,myFloat2Array,1);  // 2 constants starting at offset 1 (middle 2 values in float4)

좀 더 복잡한 루트 서명

이 예제에서는 대부분의 항목 형식을 갖는 조밀한 루트 서명을 보여 줍니다. 설명자 테이블 중 2개(슬롯 3 및 6)에는 바인딩되지 않은 크기 배열이 포함됩니다. 여기서는 애플리케이션이 힙의 유효한 설명자에만 연결해야 합니다. 바인딩되지 않은 배열 또는 아주 큰 배열에는 하드웨어 계층 2보다 높은 리소스 바인딩 지원이 필요합니다.

2개의 정적 샘플러(루트 서명 슬롯을 요구하지 않고 바인딩됨)가 있습니다.

슬롯 9에서 UAV u4 및 UAV u5는 동일한 설명자 테이블 오프셋에서 선언됩니다. 별칭이 지정된 설명자는 이렇게 사용되며, 메모리에 한 설명자가 HLSL 셰이더에서 u4 및 u5 둘 다로 표시됩니다. 이 경우 셰이더는 fxC의 D3D10_SHADER_RESOURCES_MAY_ALIAS 옵션 또는 /res_may_alias 옵션으로 컴파일되어야 합니다. 설명자에 별칭을 지정하면 셰이더를 변경하지 않고도 여러 바인딩 요소에 하나의 설명자를 바인딩할 수 있습니다.

스트리밍 셰이더 리소스 뷰

이 루트 서명은 모든 SRV가 하나의 큰 배열 내/외부로 스트리밍되는 시나리오를 보여 줍니다. 실행 시 설명자 테이블은 루트 서명이 설정될 때 한 번만 설정할 수 있습니다. 그러면 첫 번째 일부 루트 인수를 통해 공급되는 상수를 통해 배열로 인덱싱하여 모든 텍스처 읽기가 수행됩니다. 단일 설명자 힙만 필요하며, 텍스처가 사용 가능한 설명자 슬롯 내/외부로 스트리밍될 때만 업데이트됩니다.

큰 힙의 설명자 오프셋은 상수 버퍼 뷰의 상수를 사용하여 셰이더에서 식별됩니다. 예를 들어, 셰이더에 재료 ID가 지정되면 해당 상수를 사용하여 하나의 큰 배열로 인덱싱함으로써 필요한 설명자(필수 텍스처 참조)에 액세스할 수 있습니다.

이 시나리오에는 리소스 바인딩 계층이 2보다 큰 하드웨어가 필요합니다.

 

 

ref : https://docs.microsoft.com/ko-kr/windows/win32/direct3d12/example-root-signatures

반응형
반응형

BSDF (Bidrectional ScatteringDistribution Function, 양반향 산란 분포 함수)

BSDF (Bidrectional ScatteringDistribution Function, 양반향 산란 분포 함수)
- 우리가 일반적으로 사용하는 shading model들은 BxDF라는 함수들을 특수화한 model들 이다.  BSDF는 빛이 어떤 물체에 부딪쳤을 때 얼마나 많은 빛이 반사되는가를 나타낸다.  BSDF는 반사현상을 위한 Reflected 요소와 투과현상을 위한 Transmitted 요소로 나뉘며  이를 각각 BRDF(B Reflectance D F, 양반향 반사율 분포 함수)과   BTDF(B Transmittance D F 양반향 투과율 분포 함수)라고 한다.

 

   즉, BSDF가 BRDF와 BTDF의 상위집합이다.

   

   BRDF는 불투명한 표면에서 빛이 반사하는 방식을 정의하는 4차 함수이며 BSSRDF를 간략화 하였다.   간단하게 말하자면 BSSRDF(Bidirectional Surface Scattering Reflectance Distribution Function)은 8차함수이며,
   표면 내부에서의 산란을 표현한다.

 

BRDF (Bidrectional Reflectance

 

Function, 양반향 반사율 분포 함수)
- 단순하게 말하자면 입사하는 빛에 따른 반사하는 빛의 비율에 대한 함수.

- BRDF는 빛이 표면에서 어떻게 반사되는지 설명해 주는 함수, BTDF는 표면에서 어떻게 투과되는지 설명해 주는 함수.

- BRDF의 양방향성 : 만약 BRDF가 실제 물리법칙을 따르는 함수로 만들어졌다면, 

  입사와 반사의 방향이 바뀌어도 그 함수값은 바뀌지 않는다.

 

- BRDF의 비등방성 : 입사와 반사된 방향이 고정되고 표면의 법선을 축으로 표면이 회전된다면

  해당 표면요소의 반사되는 비율은 변할 것이다.

  즉, 표면의 재질이 들어오는 빛의 방향에 따라 다른 반사율을 가진다는 뜻이다 (알루미늄이나 옷감등).

  하지만 다른 많은 재질들이 매끄러워 표면의 위치와 방향에 상관없이 같은 반사율을 가진다 (등방성 재질)

- 일반적인 BRDF를 질적으로 다른 세 개의 컴퍼넌트로 다루는 것이 편리하다.

  각각을 완전 거울 반영(perfect mirror specular)반사, 완전 산란 반사(perfect diffuse reflection), 그리고 광택반사(glossy)이다.

 

 

BRDF가 왜 중요한가?

예를 들어 물을 물처럼 보이기 위해 Lighting이라는 개념이 들어가는데 렘버트의 단순함 만으로는

사실적인 결과물을 얻기 힘들다. 렘버트는 빛이 입사하는 방향에 관계없이 모든 방향으로 같은 양의 빛을

반사한다고 가정하기 때문이다. (렘버트 모델은 상수 BRDF에 의해 완벽하게 분산 표면을 표현한다).

하지만 실제로 물을 본다면 물을 바라보는 위치에 따라 물의 빛의 반사정도나 투과정도가 다르다는 것을 알 수 있다.

즉, 특정 표면이 현재 내가 바라보는 시점과 빛과의 관계에 따른 특정값을 얻을 필요가 있는 것이다.

 

 

BRDF 이론중 특별히 중요한 미립면(microfacet) 이론.

평평해 보이는 면도 사실 세밀하게 거친 면이 있기에 거울처럼 완전 평평한 물체에서 나타나는 정반사가 

나타나틑게 아니라, 각 미립자간의 상호 반사나 표면 물질의 자체적인 산란으로 인해 빛의 반사가 희미해 진다.

이 미립자 BRDF 샘플의 공식을 보면 아래와 같다.

F는 프레넬, G는 기하감쇠, D는 미세면 분포함수이다.

 


BSSRDF (B Surface Scattering Reflectance D F, 양방향 표면 분산 반사 분포 함수)에 대한 글.

- 빛의 입사량에 대해 바깥으로의 복사휘도(radiance)에 관한 함수

- BRDF는 빛이 같은점에서 입출이 된다는 가정하에서 BSSRDF의 근사값이다.

 

 

bssrdf.pdf


 

 

bssrdf2.pdf


 

 

bssrdf3.pdf

 


    
Reference Link

- 3. 왜 물은 물처럼 보이는 걸까? (미세면 brdf)

- Fake BRDF만들기

- 9. May There Be Light

-

 

- Wiki, Bidirectional scattering distribution function

- Mental Ray를 이용한3S(Sub Surface Scattering)의 실체

- 반사함수(Reflectioin Function)

- ShadowGun의 BRDF 셰이더 

- Oren Nayar BRDF

- Microfacet BRDF

-

 

 

ref: https://mgun.tistory.com/1290#google_vignette 

반응형
반응형

One of the most useful effects that isn’t already present in Unity is outlines.

Screenshot from Left 4 Dead.
There are some scripts online that make the geometry bigger and then render it a second time, behind the first. This isn't what we want.

Artifacts from normal extrusion

What we need is a post-processing effect. We'll start by rendering only the objects we want outlined to an image.
To do this, we'll use culling masks, which use layers to filter what objects should be rendered.

Make a new 'Outline' layer
Then, we attach a script to our camera, which will create and render a second camera, masking everything that isn't to be outlined.

 

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class outline : MonoBehaviour
{
	public Shader DrawAsSolidColor;
	public Shader Outline;
	Material _outlineMaterial;
	Camera TempCam;

	void Start(){
		_outlineMaterial = new Material(Outline);

		//setup the second camera which will render outlined objects
		TempCam = new GameObject().AddComponent<Camera>();
	}
	
	//OnRenderImage is the hook after our scene's image has been rendered, so we can do post-processing.
	void OnRenderImage(RenderTexture src, RenderTexture dst){
		//set up the temporary camera
		TempCam.CopyFrom(Camera.current);
		TempCam.backgroundColor = Color.black;
		TempCam.clearFlags = CameraClearFlags.Color;

		//cull anything that isn't in the outline layer
		TempCam.cullingMask = 1 << LayerMask.NameToLayer("Outline");
		
		//allocate the video memory for the texture
		var rt = RenderTexture.GetTemporary(src.width,src.height,0,RenderTextureFormat.R8);
		
		//set up the camera to render to the new texture
		TempCam.targetTexture = rt;

		//use the simplest 3D shader you can find to redraw those objects
		TempCam.RenderWithShader(DrawAsSolidColor, "");
		
		//pass the temporary texture through the material, and to the destination texture.
		Graphics.Blit(rt, dst, _outlineMaterial);
		
		//free the video memory
		RenderTexture.ReleaseTemporary(rt);
	}
}

 

Note the line:

TempCam.cullingMask = 1 << LayerMask.NameToLayer("Outline");

<< is the bit-shift operator. This takes the bits from the number on the left, and shifts them over by the number on the right. If 'Outline' is layer 8, it will shift 0001 over by 8 bits, giving the binary value 100000000. The hardware can this value to efficiently mask out other layers with a single bitwise AND operation.

We'll also need a shader to redraw our objects. No need for lighting or anything complicated, just a solid color.

 

 

 

 

Shader "Unlit/NewUnlitShader"
{
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
            };

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                return fixed4(1,1,1,1);
            }
            ENDCG
        }
    }
}

 

 

Finally, let's make a shader that passes an image through as it received it. We'll use this file for outlines later.

Shader "Custom/Post Outline"
{
    Properties
    {
        //Graphics.Blit() sets the "_MainTex" property to the source texture
        _MainTex("Main Texture",2D)="black"{}
    }
    SubShader 
    {
        Pass 
        {
            CGPROGRAM
            sampler2D _MainTex;
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
             
            struct v2f 
            {
                float4 pos : SV_POSITION;
                float2 uvs : TEXCOORD0;
            };
             
            v2f vert (appdata_base v) 
            {
                v2f o;
                 
                //Despite only drawing a quad to the screen from -1,-1 to 1,1, Unity altered our verts, and requires us to use UnityObjectToClipPos.
                o.pos = UnityObjectToClipPos(v.vertex);
                 
                //Also, the UVs show up in the top right corner for some reason, let's fix that.
                o.uvs = o.pos.xy / 2 + 0.5;
                 
                return o;
            }
             
             
            half4 frag(v2f i) : COLOR 
            {
                //return the texture we just looked up
                return tex2D(_MainTex,i.uvs.xy);
            }
             
            ENDCG
 
        }
        //end pass        
    }
    //end subshader
}
//end shader

 


Put the outline component on the camera, drag the shaders to the component, and now we have our mask!

* Render just the geometry to be outlined

 

 

 

Once we have a mask, let's sample every pixel nearby, and if the mask is present, add some color to this pixel. This effectively makes the mask bigger and blurry.

Shader "Custom/Post Outline"
{
    Properties
    {
        _MainTex("Main Texture",2D)="black"{}
    }
    SubShader 
    {
        Pass 
        {
            CGPROGRAM
     
            sampler2D _MainTex;            
            
            //<SamplerName>_TexelSize is a float2 that says how much screen space a texel occupies.
            float2 _MainTex_TexelSize;

            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
             
            struct v2f 
            {
                float4 pos : SV_POSITION;
                float2 uvs : TEXCOORD0;
            };
             
            v2f vert (appdata_base v) 
            {
                v2f o;
				o.pos = UnityObjectToClipPos(v.vertex);
                o.uvs = o.pos.xy / 2 + 0.5;
                return o;
            }
                          
            half4 frag(v2f i) : COLOR 
            {
                //arbitrary number of iterations for now
                int NumberOfIterations=19;
 
                //turn "_MainTex_TexelSize" into smaller words for reading
                float TX_x=_MainTex_TexelSize.x;
                float TX_y=_MainTex_TexelSize.y;
 
                //and a final intensity that increments based on surrounding intensities.
                float ColorIntensityInRadius=0;
 
                //for every iteration we need to do horizontally
                for(int k=0;k < NumberOfIterations;k+=1)
                {
                    //for every iteration we need to do vertically
                    for(int j=0;j < NumberOfIterations;j+=1)
                    {
                        //increase our output color by the pixels in the area
                        ColorIntensityInRadius+=tex2D(
                                                      _MainTex, 
                                                      i.uvs.xy+float2
                                                                   (
                                                                        (k-NumberOfIterations/2)*TX_x,
                                                                        (j-NumberOfIterations/2)*TX_y
                                                                   )
                                                     ).r;
                    }
                }
 
                //output some intensity of teal
                return ColorIntensityInRadius*half4(0,1,1,1)*0.005;
            }
             
            ENDCG
 
        }
        //end pass        
    }
    //end subshader
}
//end shader


* Sampling surrounding pixels, we redraw the previous image but all colored elements are now bigger

 

 

Then, sample the input pixel directly underneath, and if it's colored, draw black instead:

*Hey, now it's looking like an outline!

 

Looking good! Next, we'll need to pass the scene to our shader, and have the shader draw the original scene instead of black.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class outline : MonoBehaviour
{

	public Shader DrawAsSolidColor;
	public Shader Outline;
	Material _outlineMaterial;
	Camera TempCam;
	
	void Start()
    {
		_outlineMaterial = new Material(Outline);
		TempCam = new GameObject().AddComponent<Camera>();
	}
	
	void OnRenderImage(RenderTexture src, RenderTexture dst){
		TempCam.CopyFrom(Camera.current);
		TempCam.backgroundColor = Color.black;
		TempCam.clearFlags = CameraClearFlags.Color;

		TempCam.cullingMask = 1 << LayerMask.NameToLayer("Outline");

		var rt = RenderTexture.GetTemporary(src.width,src.height,0,RenderTextureFormat.R8);
		TempCam.targetTexture = rt;

		TempCam.RenderWithShader(DrawAsSolidColor, "");

		_outlineMaterial.SetTexture("_SceneTex", src);
		Graphics.Blit(rt, dst, _outlineMaterial);

		RenderTexture.ReleaseTemporary(rt);
	}
}

 

Shader "Custom/Post Outline"
{
    Properties
    {
        _MainTex("Main Texture",2D)="black"{}
        _SceneTex("Scene Texture",2D)="black"{}
    }
    SubShader 
    {
        Pass 
        {
            CGPROGRAM
            sampler2D _MainTex;    
            sampler2D _SceneTex;
            float2 _MainTex_TexelSize;
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
             
            struct v2f 
            {
                float4 pos : SV_POSITION;
                float2 uvs : TEXCOORD0;
            };
             
            v2f vert (appdata_base v) 
            {
                v2f o;
				o.pos = UnityObjectToClipPos(v.vertex);
                o.uvs = o.pos.xy / 2 + 0.5;
                return o;
            }
                          
            half4 frag(v2f i) : COLOR 
            {                
            //if something already exists underneath the fragment, discard the fragment.
                if(tex2D(_MainTex,i.uvs.xy).r>0)
                {
                    return tex2D(_SceneTex,i.uvs.xy);
                }
                int NumberOfIterations=19;
 
                float TX_x=_MainTex_TexelSize.x;
                float TX_y=_MainTex_TexelSize.y;
 
                float ColorIntensityInRadius=0;
 
                for(int k=0;k < NumberOfIterations;k+=1)
                {
                    for(int j=0;j < NumberOfIterations;j+=1)
                    {
                        ColorIntensityInRadius+=tex2D(
                                                      _MainTex, 
                                                      i.uvs.xy+float2
                                                                   (
                                                                        (k-NumberOfIterations/2)*TX_x,
                                                                        (j-NumberOfIterations/2)*TX_y
                                                                   )
                                                     ).r;
                    }
                }

                //this value will be pretty high, so we won't see a blur. let's lower it for now.
                ColorIntensityInRadius*=0.005;
 
                //output some intensity of teal
                half4 color= tex2D(_SceneTex,i.uvs.xy)+ColorIntensityInRadius*half4(0,1,1,1);

                //don't want our teal outline to be white in cases where there's too much red
                color.r=max(tex2D(_SceneTex,i.uvs.xy).r-ColorIntensityInRadius,0);
                return color;
            }
             
            ENDCG
 
        }
        //end pass        
    }
    //end subshader
}
//end shader

 

 

 

 

 

 

여기까지는 평균내어 블러 처리 한것인데 하단 부터는 가우시안 블러를 적용하여 블러 처리 한 부분으로 변경한 것이다

 


This is almost where we want it, but we do have one more step! There are some problems with this outline right now. You might notice it looks a little off, and that the outline doesn't contour the corners nicely.

There's also the issue of performance - at 19x19 samples per pixel for the outline, this isn't a big issue. But what if we want a 40 pixel outline? 40x40 samples would be 1600 samples per pixel!

We're going to solve both of these issues with a gaussian blur.
In a Gaussian blur, a kernel(a weight table) is made and colors are added equal to the nearby colors times the weight.


Gaussian blurs look nice and natural, and they have a performance benefit.
If we start with a 1-dimensional Gaussian kernel, we can blur everything horizontally,


and then blur everything vertically after, to get the same result.


This means our 40 width outline will only have 80 samples per pixel.

I found some code online that will generate a Gaussian kernel. It's a bit beyond my understanding, but just know that this is computationally expensive, and shouldn't be done often. I'm running it on the script's start method.

 

//http://haishibai.blogspot.com/2009/09/image-processing-c-tutorial-4-gaussian.html
public static class GaussianKernel
{
	public static float[] Calculate(double sigma, int size)
	{
		float[] ret = new float[size];
		double sum = 0;
		int half = size / 2;
		for (int i = 0; i < size; i++)
		{
			ret[i] = (float) (1 / (Math.Sqrt(2 * Math.PI) * sigma) * Math.Exp(-(i - half) * (i - half) / (2 * sigma * sigma)));
			sum += ret[i];
		}
		return ret;
	}
}

 

 

 

The sigma is an arbitrary number, indicating the strength of the kernel and the blur.

The size is to stop generating tiny numbers in an infinite kernel. Technically, Gaussian kernels would have no zeroes, so we want to cut it off once it isn't noticeable. I recommend the width be 4 times the sigma.

We calculate the kernel, and pass it to the shader. I have it set to a fixed size, but you could pass a kernel texture instead to handle varying widths.

using System;
using UnityEngine;
public class outline : MonoBehaviour
{
	public Shader DrawAsSolidColor;
	public Shader Outline;
	Material _outlineMaterial;
	Camera TempCam;
	float[] kernel;
	void Start()
	{
		_outlineMaterial = new Material(Outline);
		TempCam = new GameObject().AddComponent<Camera>();

		kernel = GaussianKernel.Calculate(5, 21);
	}

	void OnRenderImage(RenderTexture src, RenderTexture dst)
	{
		TempCam.CopyFrom(Camera.current);
		TempCam.backgroundColor = Color.black;
		TempCam.clearFlags = CameraClearFlags.Color;

		TempCam.cullingMask = 1 << LayerMask.NameToLayer("Outline");

		var rt = RenderTexture.GetTemporary(src.width, src.height, 0, RenderTextureFormat.R8);
		TempCam.targetTexture = rt;

		TempCam.RenderWithShader(DrawAsSolidColor, "");

		_outlineMaterial.SetFloatArray("kernel", kernel);
		_outlineMaterial.SetInt("_kernelWidth", kernel.Length);
		_outlineMaterial.SetTexture("_SceneTex", src);

		//No need for more than 1 sample, which also makes the mask a little bigger than it should be.
		rt.filterMode = FilterMode.Point;

		Graphics.Blit(rt, dst, _outlineMaterial);
		TempCam.targetTexture = src;
		RenderTexture.ReleaseTemporary(rt);
	}
}

 

 

We make a pass with the kernel, sampling every pixel and adding our pixel's value by the kernel times the sampled value. Call GrabPass to grab the resulting texture, and then make a second pass. The second pass does the vertical blur.

Shader "Custom/Post Outline"
{
    Properties
    {
        _MainTex("Main Texture",2D)="black"{}
        _SceneTex("Scene Texture",2D)="black"{}
        _kernel("Gauss Kernel",Vector)=(0,0,0,0)
        _kernelWidth("Gauss Kernel",Float)=1
    }
    SubShader 
    {
        Pass 
        {
            CGPROGRAM
            float kernel[21];
            float _kernelWidth;
            sampler2D _MainTex;    
            sampler2D _SceneTex;
            float2 _MainTex_TexelSize;
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            struct v2f 
            {
                float4 pos : SV_POSITION;
                float2 uvs : TEXCOORD0;
            };
            v2f vert (appdata_base v) 
            {
                v2f o;
				o.pos = UnityObjectToClipPos(v.vertex);
				o.uvs = o.pos.xy / 2 + 0.5;
                return o;
            }
                          
            float4 frag(v2f i) : COLOR 
            {
                int NumberOfIterations=_kernelWidth;
				
                float TX_x=_MainTex_TexelSize.x;
                float TX_y=_MainTex_TexelSize.y;
                float ColorIntensityInRadius=0;

                //for every iteration we need to do horizontally
                for(int k=0;k<NumberOfIterations;k+=1)
                {
                        ColorIntensityInRadius+=kernel[k]*tex2D(
                                                      _MainTex, 
                                                      float2
                                                                   (
                                                                        i.uvs.x+(k-NumberOfIterations/2)*TX_x,
                                                                        i.uvs.y
                                                                   )
                                                     ).r;
                }
                return ColorIntensityInRadius;
            }
            ENDCG
 
        }
        //end pass

        //retrieve the texture rendered by the last pass, and give it to the next pass as _GrabTexture
        GrabPass{}
		
		//this pass is mostly a copy of the above one.
        Pass 
        {
            CGPROGRAM
            float kernel[21];
            float _kernelWidth;       
            sampler2D _MainTex;    
            sampler2D _SceneTex;
			
            sampler2D _GrabTexture;
            float2 _GrabTexture_TexelSize;

            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            struct v2f 
            {
                float4 pos : SV_POSITION;
                float2 uvs : TEXCOORD0;
            };
            v2f vert (appdata_base v) 
            {
                v2f o;
				o.pos = UnityObjectToClipPos(v.vertex);
                o.uvs = o.pos.xy / 2 + 0.5;
                 
                return o;
            }
            float4 frag(v2f i) : COLOR 
            {
                float TX_x=_GrabTexture_TexelSize.x;
                float TX_y=_GrabTexture_TexelSize.y;

                //if something already exists underneath the fragment, draw the scene instead.
                if(tex2D(_MainTex,i.uvs.xy).r>0)
                {
                    return tex2D(_SceneTex,i.uvs.xy);
                }

                int NumberOfIterations=_kernelWidth;
                float4 ColorIntensityInRadius=0;

                for(int k=0;k < NumberOfIterations;k+=1)
                {
                        ColorIntensityInRadius+=kernel[k]*tex2D(
                                                      _GrabTexture,
                                                      float2(i.uvs.x,
                                                             1-i.uvs.y+(k-NumberOfIterations/2)*TX_y)
                                                     );
                }

                //output the scene's color, plus our outline strength in teal.
                half4 color= tex2D(_SceneTex,i.uvs.xy)+ColorIntensityInRadius*half4(0,1,1,1);
                return color;
            }
             
            ENDCG
 
        }
        //end pass        
    }
    //end subshader
}
//end shader

 

 

The finished effect!

 

결과를 보면 좀더 밖으로 빠질 수록 자연스럽게 블러처리가 된 것을 볼 수 있다

 

Where to go from here


Try adding multiple colors.
You could also sample the added color from another texture to make a neat pattern.
Regenerate the kernel when the resolution changes to get an effect that scales up.

Help!

My outline looks blocky.
Most likely, your sigma is too high and your width too low, so the kernel is cut off earlier than it should be.
Or, your kernel isn't being generated or used correctly.

Performance problems/crashes
Are you using RenderTexture.GetTemporary() and RenderTexture.ReleaseTemporary()? Unity doesn't release normal RTs for some reason, so you need to use the temporary methods.
Check the profiler to see what's up.

Something is upside-down/too big/in the corner of the screen
Unity has inconsistencies and so does OpenGL. There is a pragma, #if UNITY_UV_STARTS_AT_TOP, that can be used.

Something isn't working.
Use the frame debugger to see what's happening to your graphics. Otherwise, check for any errors.

 

 

 

ref : https://willweissman.com/unity-outlines

http://haishibai.blogspot.com/2009/09/image-processing-c-tutorial-4-gaussian.html

https://gamedev.stackexchange.com/questions/144702/how-can-i-make-a-soft-outline-shader

https://docs.unity3d.com/kr/530/ScriptReference/Graphics.Blit.html (Graphics.Blit)

https://docs.unity3d.com/kr/2021.3/Manual/SL-BuiltinFunctions.html

 

 

 

반응형
반응형

DirectX SDK (June 2010) 을 Windows 7 에 설치하던 중에 Error Code S1023 이 뜹니다.

원인은 최신 버전의 Visual C++ 2010 X86/X64 Redistributable Package 가 설치되어서 발생되는 것입니다.

 

일단 이것들을 제어판에서 삭제합니다.

DOS 명령어에서 다음과 같이 입력해도 삭제됩니다.

MsiExec.exe /passive /X{F0C3E5D1-1ADE-321E-8167-68EF0DE699A5} MsiExec.exe /passive /X{1D8E6291-B0D5-35EC-8441-6616F567A0F7}

 

그 다음에 DirectX SDK 를 설치합니다.

http://www.microsoft.com/en-us/download/details.aspx?id=6812

 

그 다음에 최신 버전의 Visual C++ 2010 X86/X64 Redistributable Package 를 설치합니다.

http://www.microsoft.com/ko-kr/download/details.aspx?id=26999

 

참고



ref DirectX SDK (June 2010) 설치할 때 Error Code S1023

출처: 
https://appmaid.tistory.com/11 [App Maid] https://appmaid.tistory.com/11

반응형

'그래픽스(Graphics) > DirectX9~12' 카테고리의 다른 글

Dx12 기본지식 - 자원 상태 전이  (0) 2022.11.16
루트 서명 (Root Signature)  (0) 2022.09.04
키프레임 애니메이션  (0) 2016.08.06
밉맵 디테일 높이기  (0) 2013.06.10
Early Z  (0) 2013.06.08
반응형



라이트맵핑을 사용해 실감나는 조명 효과를 표현할 수 있지만 움직이는 개체는 적용할 수 없다.

라이트맵핑은 정적인 객체(Static Object)에만 영향을 미치기 때문이다.

그렇다고 실시간 조명을 이용해 움직이는 객체의 조명 효과를 부여하기에는 불가능하다.


이점을 개선하기 위해 유니티에서는 라이트 프로브(Light Probe) 기법을 제공한다.

스테이지의 라이트가 있는 곳 주변에 라이트 프로브를 배치하고 라이트 맵을 베이킹할 때

해당 라이트 프로브에 주변부의 광원 데이터를 미리 저장해 둔다.

라이트 프로브에 저장된 광원 데이터는 실행 시 근처를 지나가는 객체에 광원 데이터를 전달하여 

해당 물체의 색상과 보간(Interpolite)시켜 마치 실시간 조명과 같은 효과를 표현하는 방식이다.


<절대강자 유니티4/이재현> 발췌


http://bililic.com/220759932463








 프로브 프록시 볼륨

http://blog.naver.com/blue9954/220819325189




http://www.devblog.kr/r/8y0gFPAvJ2Z8y1vfYWHFXs9XobwcKq6QkAP2lrVXIYx60o


대마왕 님의 블로그에서 퍼온 자료입니다. 자세한 내용은 링크를 확인해 주세요.


기존의 라이트 프로브의 단점이었던 커다란 오브젝트의 라이트 프로브 문제점이 해결되었습니다. 예를 들어 대형 몬스터를 표현할때 기존의 라이트 프로브로는 몬스터 오브젝트 전체가 하나의 라이트 프로브만 영향받는 문제가 있어서 주변의 라이팅과 어울리지 않았지만 이번에 들어간 라이트 프로브 프록시 볼륨을 이용하면 훨씬 리얼한 라이팅 효과를 얻을수 있습니다.


반응형
반응형

키 프레임 애니메이션에 대한 쉬운 설명이 있어서 출처와 함께 소개합니다.

 

출처 <http://twinbraid.blogspot.kr/2016/01/blog-post_19.html>

 

 

 

애니메이션과 키프레임 용어

애니메이션은 움직이는 그림을 뜻하는데 그림이 살아 움직이는 건 아니고
여러장의 장면을 빠르게 보여줌으로써 움직이는 것처럼 보이게 한다
키 프레임의 경우 보통 중요한 컷을 말한다

애니메이션의 제작, 원화와 동화

애니메이션이 여러장의 그림을 나열하는 것은 알고 있을 것이다
그런데 그러한 그림을 노트에서 페이지 넘겨서 움직이는 졸라맨 그리듯이
무작정 순서대로 그리진 않는다
먼저 원화라고 Key Animation을 그린 후 그것을 연결하는 동화를 그린다
예를들어 공이 위에서 아래로 떨어지는 애니를 만든다면
원화가는 어디에서 공이 떨어질지에 대한 그림을 그리고
어느 바닥에 도착할지에 대한 그림을 그린다
그럼 총 두 장의 키 애니메이션이 만들어진다. 하지만 이 두 장으론 애니가 성립되지
않는다. 그것을 위해 동화맨들이 두 장을 바탕으로 중간에 연결되는 그림을 왕창
그리는 것이다.
만약 원화가가 한 장은 개를 그려놓고 한 장은 우주를 그려놓으면
동화맨으로썬 이 두 장 사이에 뭘 그리라는 건지 혼란에 빠질 것이다
그러므로 키 애니메이션은 거의 모든 중요정보를 담고있는
말 그대로 그 장면 장면의 키가 되어서 누가봐도 중간 장면을 예상할 수 있어야한다

키 프레임

애니메이션과 비교

3D 프로그램에서 동영상편집, 그리고 플래시에 이르기까지 키 프레임
거의 일상적 용어이며 위의 키 애니메이션 개념과 다르지 않다
프로그램상에서 원화가는 바로 당신을 뜻하며 동화가는 프로그램이다
예를들어 위의 공애니의 경우 공을 일정위치에 놓고 키 프레임을 하나 찍는다
그리고 또 다른 위치에 놓고 10초뒤 키 프레임을 하나 찍으면
그 중간 과정을 프로그램이 알아서 생성한다. 그럼으로써 애니메이션이 완성된다

컷 추가

프로그램상에서 타임라인의 기본은 노컷이다
완전 통짜로 되어 있어서 10초짜리 타임라인이라면 키 프레임이 들어가지 않는다면
한 장면을 10초간 보여줄 뿐이다. 여기서 키 프레임이 바로 컷의 역할을 한다
애니메이션이란게 성립할려면 최소한 2장면은 필요하다.
그래서 키 프레임이 반드시 2개 이상이 되었을때야 비로서 애니메이션이 성립하게 된다

속성

일반 애니메이션의 경우 움직임이 키의 요소지만
프로그램에선 변할 수 있는 것들은 모조리 키로 만들 수 있다
예를들면 불투명도에서 소리에 이르기까지 말이다
1초에서 불투명도를 100%로 놓은 키와 10초에서 불투명도를 0%로 놓은 키가 있다면
10초로 이르는 사이 서서히 투명해지는 애니메이션을 만들 수 있고
1초에서 볼륨을 0%로 해놓은 키와 10초에서 100%로 놓은 키가 있으면
볼륨이 서서히 커지는 효과의 애니메이션(?)을 만들 수 있는 것이다
이때 이것들은 하나의 키 프레임에서 처리하진 않고 속성들이 고유의 키 프레임을 갖는다
위와 같은 경우 키 프레임이 4개가 된다.
속성이 많으면 많을 수록 키 프레임 수도 팍팍 늘어나는데 사실 그렇게까지
많이 쓰진 않으며 각 키 프레임도 드래그로 조정 가능하게 하는 것은 기본이고
snap 기능, 복사 등등 최대한 노가다를 적게하도록 만들어져 있다. 그래도 노가다

그래프

키 프레임 자체는 잘 보인다. 그게 찍혀있으면 거기에 컷이 한장 있다는 소리고.
키 프레임을 클릭하면 수치창이 나와서 수치를 조정해줄 수 있다.
하지만 전체적인 움직임은 좀 알기 어려운 점이 있다
그래서 그러한 움직임을 직관적으로 보여주자고해서 나온 것이 그래프이다
키 프레임
와… 직관적이네요????
처음보면 무슨 개풀씨나락 까먹는 직관이냐고 생각할지 모르겠지만
우리의 수학이 더러운 주입식이라 그렇지 실제 사용에서 그래프는 매우 편리한 도구다.
저것만 봐도 쪼금이라도 키 프레임 지식이있다면 바로 초록색 수직라인은 현재 타임이고
검은 네모들은 키 프레임이고 각각의 색색 곡선들은 저위의 사각형 상자에 나와있는
방향화살표랑 색깔이 매치되는 것을 알아볼 것이다
예를들면 파란색이 저 상자의 위쪽 화살표니까 10초에서는 -7쯤 위치에 있다가
100초에 다가설수록 곡선형으로 수치가 증가해 7에 다다른다
즉 상자가 10초에서 100초가 되면서 위로 천천히 오르다가 점점 빠르게 오르다가
마지막에 가서는 완만하게 오르게 되는 것을 그래프로 한눈에 알 수 있다
보통은 그러한 움직임을 알려면 직접 플레이 해보는 수밖에 없지만 이처럼 그래프는
어떻게 진행되는 지를 한장으로 보여주는데
반하지 않을 수가 없다
(참고로 본인은 수학은 잼병에 그래프는 인류의 적이라고 생각했던 사람이다 한국교육 ㅅㅂ)
왠만한 프로그램에서는 타임라인을 잘 뒤져보면 그래프를 보여주는 옵션이 있는데
거기에 익숙해지면 작업이 엄청 편해지게 되는 것은 말할 것도 없다

3D 애니메이션

본인은 3D 애니메이션이라 하면 엄청나다는 생각만 가지고 있었고
그 실체는 역시 엄청날 것이다 라고만 생각했다
즉, 엄청난 거라고 미리 겁먹고 생각할 의지가 생기지 않았다
사실 나랑 관계없는 세계니 관여할 생각도 없었고
근데 재수없게도 약간 관계가 생겼다
그래서 그 엄청난 세계에 발디뎠는데.. 알고보니 사실 똑같았다
한 장면과 다른 장면을 찍어놓으면 프로그램이 알아서 중간과정 만드는거
위랑 하나도 안다르다.
리깅과 핸들을 만들고 마지막에 애니를 재생하면서 간신히 알아낸거지만..ㅡ,.ㅡ;
단지 똑같긴 한데 보통 2D랑 쪼끔 다른건 원하는 장면을 위한 포즈를 취하게 하는게
여간 힘든게 아니였다는랑 그걸 위해서 리깅과 핸들 같은 생소한 개념이 들어가서
헷갈렸다는 것 정도다.

결론

결국 키 프레임을 만드는 것은 변화 전과 변화 후의 장면을 만드는 것이다
우린 작곡가 처럼 오선지에 음표를 넣듯이 타임라인에 키프레임을 넣어주면 된다
1초에 도를 넣고 10초에 솔을 넣으면 컴터가 알아서 도레미파솔 이라고 연주해주는 것이다
물론 레 미 파 솔도 직접 키프레임으로 찍어 넣을 수 있다. 노가다가 그렇게 하고 싶다면

여타 프로그래밍이 그렇듯이 본질은 사실 단순한데
그걸 편하게 한다고 덕지덕지 붙이고 보니 실체는 안보이고 복잡한 외부기능들만
보여서 어려워지는 것이다.
개념만 이해하고 나면 이제 어떤 프로그램이더라도 애니메이션을 만드는데
각 프로그램의 세세한 것들만 좀 다를 뿐이지 큰 장애는 없을 것이다

Written with StackEdit.

반응형

'그래픽스(Graphics) > DirectX9~12' 카테고리의 다른 글

루트 서명 (Root Signature)  (0) 2022.09.04
DirectX SDK (June 2010) 설치 Error Code S1023  (0) 2019.07.25
밉맵 디테일 높이기  (0) 2013.06.10
Early Z  (0) 2013.06.08
Direct3D 9 에 래스터라이즈 규칙  (0) 2013.05.10
반응형



출처 : http://chulin28ho.tistory.com/256




 tex2dlod (sampler, float4(UV, 0,miplevel))

 

tex2Dlod 는 밉맵의 레벨을 불러온다. 일부러 텍스쳐를 흐리게 할 때 유용함.

단 이걸 사용하면 거리에 따른 밉맵 조절이 안되는 문제가 있다.

miplevel은 0 부터 사용한다. 숫자가 늘어날수록 밉 레벨이 늘어난다.

여기서의 miplevel은 2.5라고 넣는다면 2와 3 사이를 보간해 준다

#pragma target 3.0 필요

 

http://kblog.popekim.com/2011/04/tex2dlod.html

 

 

 

tex2dbias (sampler, float4(UV, 0,miplevel))

 

tex2Dbias 는 밉맵의 레벨을 불러온다. 일부러 텍스쳐를 흐리게 할 때 유용함.

음.. 여기서의 miplevel은 2.5 라고 넣는다면 지금의 밉레벨 + 2.5 ... 인건가

결과물을 봐도 bias가 더 나쁘고, 3.0도 요구하지 않는다.

 

즉 lod는 밉맵레벨을 고정하는거고

bias는 지금 레벨에 원하는 레벨을 더해줘서 결과물을 내보낸다..

하이브리드한테까지 물어봐서 결과냄. 도무지 이해가 안가길래..

 

 

 

 

 

참고 스레드

http://forum.unity3d.com/threads/tex2dlod-vs-tex2dbias.249140/

 

http://jyblues.blogspot.kr/2011/12/direct3d11-intrinsic-functions.html

 

tex2Dbias(s,t): t.w에 의해 mip map level을 정한 후 샘플러 s를 이용 2D 텍스쳐의 픽셀 색깔 정보를 얻는다.

tex2Dlod(s,t): t.w에 의해 mip map level을 정한 후 샘플러 s를 이용 2D 텍스쳐의 픽셀 정보를 얻는다. t.w에 의해 LOD가
              어느단계에서 변할지를 결정한다.







출처 : http://chulin28ho.tistory.com/258



둘은 상당히 비슷한 기능을 하죠. mipmap 제어라는...

그치만 공식의 작동법은 미묘하게 달라요.

lod가 shader3.0을 요구한다는 것도 다르고요...

 

프로그래머들에게 물어보면 공식에 대한 차이만 말해주니까요

자세한 느낌을 보기 위해 직접 테스트를 해 봤습니다.

 

 

 

예제를 만들어 봤습니다. 둘이 똑같아 보이죠?

근데 제 눈에는 살짝 오른쪽 텍스쳐가 추가 샘플링 된 것처럼 보입니다.

 

그래서 정말 그런가 테스트

 

 

 

 

 

오호라 과연 정말입니다.

tex2Dlod는 고정된 mipmap을 유지하지만, bias 는 이름값대로 추가로 바이어스를 걸어주고 있는 느낌입니다.

 

그럼 이번에는 값에 따른 변화를 테스트 하기 위해 다시 근접시킵니다.

 

 

 

음 겜브리오때는 밉맵을 수동 설정 가능했는데. 유니티는 방법이 없을까낭...

뭐 투덜대도 할 수 없으니까 이번에는 값을 비교해 보죠

 

지금 두 그림이 똑같아 보입니다만... 오른쪽이 밉맵 1 상태라고 보여집니다. 한 단계 낮은 이미지요.

 

어쨌거나 일단 비교.

 

 

lod/bias 값 1

 

 

lod/bias 값 1.5

 

 

lod/bias 값 2

 

 

lod/bias 값 2.5

 

 

lod/bias 값 3

 

 

lod/bias 값 3.5

 

 

lod/bias 값 4

 

 

lod/bias 값 4.5

 

 

lod/bias 값 5

 

 

lod/bias 값 5.5

 

 

 

lod/bias 값 6

 

 

음... 일단 오른쪽 bias의 값이 더 낮아 보입니다.

그 이유는... 현재 보이는 거리 때문에 밉맵이 한 단계 더 먹은 상태라서 그렇습니다.

그에 반해 tex2Dlod는 거리고 뭐고 상관 안하고 mipmap 값이 강제지정됩니다. 호옹이.

이런 차이로군요.

 

 

그래서 정말 그런가 추가 테스트

 

 

 

 

다시 6단계에서부터 추가 테스트. 이번에는 필터링을 개뿌연 Box 필터링에서 그나마 날카로운  Kaiser 필터링으로 바꿔 보았습니다. 카메라를 좀 근접시키니 두 이미지가 상당히 비슷하네요 그래도 lod가 더 선명해 보이는게, 1단계 앞인 느낌입니다.

 

 

거리를 멀게 하자 오호라. 역시 bias는 거리에 따라 mipmap이 더 먹습니다.

 

그렇다는것은...

 

 

 

 

거리만 가깝다면 bias가 더 선명하다는 말도 된단 말입니다. lod는 고정이니까. 오호호라...

 

즉  lod는 무조건 고정시키는 거고 bias는 말그대로 기존 값에 bias 시킨다는 말이겠습니다.

 

이 기능은 주로 싸구려 블러 효과로 사용됩니다만, 값을 반대로 처리하면 싸구려 샤픈 효과도 가능하겠죠.

반응형

'그래픽스(Graphics) > Shader' 카테고리의 다른 글

Object Outlines in Unity  (0) 2022.08.21
라이트 프로브(Light Probe)  (0) 2016.11.25
radiance, radiosity,irradiance  (0) 2013.07.25
SSS(Subsurface scattering) 정리  (0) 2013.07.14
Subsurface scattering  (0) 2013.07.14
반응형
http://cafe.naver.com/houdinilife/56




radiance : 광원에서 발광radiance하는 양이나 세기를 말하고
radiosity : 광원으로 부터 받은 빛을 surface의 단위면적당 얼마나 확산시키는것을 말하고...
irradiance : 광원으로부터 단위면적당 얼마만큼의 빛을 surface가 받았냐이다...



 radiance_equation.ppt



http://www.google.co.kr/url?sa=t&rct=j&q=&esrc=s&source=web&cd=3&ved=0CF8QFjAC&url=http%3A%2F%2Fwww.cs.ucl.ac.uk%2Fstaff%2Fucacajs%2Fbook_tmp%2FCGVE%2Fslides%2Fradiance_equation.ppt&ei=2Be1T4CaBYqWiQeFuLCOAw&usg=AFQjCNFAJz7qrgGKvuK6L1aDV40lNTfyfw&sig2=2L21l7kiSO7HynKZvFj--g

반응형
반응형




우선 시간이 지나 나도 까먹을 가능성이 짙기때문에 아래 내용중 중요한 내용을 써놓으면...




이미지 출처 : 위키(en)






대략  SSS(Subsurface scattering)은/는  빛이 사람표면에 반사될때 6%를 제외한 94% 가 표면에서 표면으로 빛이 반사되는것에 대한 거리를 구해야 이 알고리즘을

구현 할 수 있다고 하는것인데, 표면으로 흩어지는것들의 거리를 어케 찾는 것이 관건이는 것임다!


아래 설명은 뭐 여러가지 방법이 있겠지만 그중에서도 depth map 을 이용한 방법을 설명하고

왼쪽 상단에 보이는게 depth map 이고 depth map 을 생성하는 기준점이 light position 이라 한다면 


이것들의 거리를 텍스쳐의 offset 으로 구할 수 있다는것!!! 깊이는 반사지점 주위의 흩어진곳에서의 깊이를 대략 비교해

이게 같은 표면에 있는거냐 등을 조사하면 될것 같고, 대략 이것도 샘플링/kernel 로 들어가면 될듯

이것으로 보아 이 방식을 사용할 경우 deferred 와도 잘 연동될것으로 보이고, 실시간으로도 처리 가능할것으로 보이네요


으하~
 


이쯤되면 대략 예상되는것은 샘플링 개수와 어떠한 랜덤한 분포를 쓰느냐에 따라 달라질듯....





참고 사이트 : 

http://en.wikipedia.org/wiki/Subsurface_scattering   추천!!!!

http://chulin28ho.egloos.com/5591833  SSS에 대한것이 일단 무엇인지 보고싶다면 이곳으로

http://blog.naver.com/gogator100/80001535673







반응형
반응형
구현해보려고 돌아다니다 봤는데 이것만 봐도 도움이 되는듯
좀 더 디테일한 자료를 위해 구굴링 으~~~~



출처 : http://en.wikipedia.org/wiki/Subsurface_scattering


Subsurface scattering

From Wikipedia, the free encyclopedia
  (Redirected from Sub Surface Scattering)



Direct surface scattering (left), plus subsurface scattering (middle), create the final image on the right.

Example of Subsurface scattering made in Blender software.

Subsurface scattering (or SSS) is a mechanism of light transport in which light penetrates the surface of a translucent object, is scatteredby interacting with the material, and exits the surface at a different point. The light will generally penetrate the surface and be reflected a number of times at irregular angles inside the material, before passing back out of the material at an angle other than the angle it would have if it had been reflected directly off the surface. Subsurface scattering is important in 3D computer graphics, being necessary for the realistic rendering of materials such as marble, skin, and milk.

Contents

  [hide

Rendering Techniques[edit]

Most materials used in real-time computer graphics today only account for the interaction of light at the surface of an object. In reality, many materials are slightly translucent: light enters the surface; is absorbed, scattered and re-emitted — potentially at a different point. Skin is a good case in point; only about 6% of reflectance is direct, 94% is from subsurface scattering.[1] An inherent property of semitransparent materials is absorption. The further through the material light travels, the greater the proportion absorbed. To simulate this effect, a measure of the distance the light has traveled through the material must be obtained.

Depth Map based SSS[edit]


Depth estimation using depth maps

One method of estimating this distance is to use depth maps [2] , in a manner similar to shadow mapping. The scene is rendered from the light's point of view into a depth map, so that the distance to the nearest surface is stored. The depth map is then projected onto it using standard projective texture mapping and the scene re-rendered. In this pass, when shading a given point, the distance from the light at thepoint the ray entered the surface can be obtained by a simple texture lookup. By subtracting this value from the point the ray exited the objectwe can gather an estimate of the distance the light has traveled through the object.

The measure of distance obtained by this method can be used in several ways. One such way is to use it to index directly into an artist created 1D texture that falls off exponentially with distance. This approach, combined with other more traditional lighting models, allows the creation of different materials such as marble, jade andwax.

Potentially, problems can arise if models are not convex, but depth peeling [3] can be used to avoid the issue. Similarly, depth peeling can be used to account for varying densities beneath the surface, such as bone or muscle, to give a more accurate scattering model.

As can be seen in the image of the wax head to the right, light isn’t diffused when passing through object using this technique; back features are clearly shown. One solution to this is to take multiple samples at different points on surface of the depth map. Alternatively, a different approach to approximation can be used, known as texture-space diffusion.

Texture Space Diffusion[edit]

As noted at the start of the section, one of the more obvious effects of subsurface scattering is a general blurring of the diffuse lighting. Rather than arbitrarily modifying the diffuse function, diffusion can be more accurately modeled by simulating it in texture space. This technique was pioneered in rendering faces in The Matrix Reloaded,[4] but has recently fallen into the realm of real-time techniques.

The method unwraps the mesh of an object using a vertex shader, first calculating the lighting based on the original vertex coordinates. The vertices are then remapped using the UV texture coordinates as the screenposition of the vertex, suitable transformed from the [0, 1] range of texture coordinates to the [-1, 1] range of normalized device coordinates. By lighting the unwrapped mesh in this manner, we obtain a 2D image representing the lighting on the object, which can then be processed and reapplied to the model as a light map. To simulate diffusion, the light map texture can simply be blurred. Rendering the lighting to a lower-resolution texture in itself provides a certain amount of blurring. The amount of blurring required to accurately model subsurface scattering in skin is still under active research, but performing only a single blur poorly models the true effects.[5] To emulate the wavelength dependent nature of diffusion, the samples used during the (Gaussian) blur can be weighted by channel. This is somewhat of an artistic process. For human skin, the broadest scattering is in red, then green, and blue has very little scattering.

A major benefit of this method is its independence of screen resolution; shading is performed only once per texel in the texture map, rather than for every pixel on the object. An obvious requirement is thus that the object have a good UV mapping, in that each point on the texture must map to only one point of the object. Additionally, the use of texture space diffusion provides one of the several factors that contribute to soft shadows, alleviating one cause of the realism deficiency of shadow mapping.


반응형
반응형

오홍~



http://kblog.popekim.com/2013/06/blurrymipmap.html



벌써 5년넘게 써오고 있는 방법인데 생각보다 모르시는 분들이 많은 것 같아 이방법을 공유합니다.

밉맵?

일단 밉맵이 뭔지는 다 아시리라 생각하고 굳이 밉맵에 대해서는 설명하지 않겠습니다.  모르시는 분들은 여길 참고하세요.

문제점 및 일반적인 해결책

밉맵을 사용하다보면 정말 카메라를 가까이 들이밀지 않는한 텍스처의 디테일이 흐릿해 보이는 경우가 흔히 발생합니다.  보통 다음과 같은 방법들로 해결합니다.

흔히 쓰는 해결법 1 - 텍스처 크기 늘리기

밉레벨이 낮아질수록 텍스처 크기가 절반씩 줄어드는 거니 젤 높은 디테일의 밉멥 텍스처크기를 크게 키워주면 그만큼 흐려지는 현상이 덜합니다. 하지만 메모리를 많이 잡아먹는다는 단점이 있어서 정 필요한 때만 제한적으로 사용하곤 합니다. (왜 흔히 라고 한거지 그럼 -_-)

흔히 쓰는 해결법 2 - 밉맵 바이어스 쓰기

이걸 고치기 위해 흔히 쓰는 해결법은 밉맵 bias를 조절하는 방법입니다. 샘플러스테이트에서 정해주는 방법도 있고 셰이더에서 해주는 법도 있습니다. 뭐든 나쁜 방법은 아니고 가장 널리 쓰는 방법인데 여러가지 단점이 있습니다


  1. 고디테일의 텍스처(크기가 큼)를 더 많이 쓰도록 bias를 주므로 텍스처 캐쉬의 성능저하 (그만큼 넣어야할 데이터가 많으니)
  2. 밉맵이 원래 해결하려고 하는 거리에 따른 애일리어싱 문제가 쉽게 더 생긴다.
  3. 모든 경우에 적당히 잘 동작하는 bias 값을 찾기가 쉽지 않다.

흔히 쓰는 해결법 3 - 밉맵 생성시 사용하는 필터 다르게 사용하기

보통 bilinear 필터를 사용해서 밉맵을 만드는게 일반적입니다. 그럼 그냥 주변에 있는 이웃 픽셀들 2x2개 모아다가 균등하게 혼합하는게 전부입니다. 이 외에 kaiser 필터 등을 사용하면 좀더 낫다고 해서 그렇게 하는 사람들을 봤지만... 개인적으로는 별 효과가 없다고 생각합니다.


제 해결법 - sharpening filter

생각보다 매우 간단합니다. 그냥 밉맵 텍스처에 sharpening 필터 한번 더 먹여주면 됩니다. -_- 사실 밉맵들이 흐릿해 보이는 이유가 bilinear 필터링만 쓰면 그냥 경계를 뭉게버린다는건데 여기다 sharpening 필터 한번 먹여주면 경계부분은 다시 적당히 또렷하게 살아나거든요... 

오프라인 프로세스라 게임성능에 지장도 없고... 흔히 쓰는 해결법 2에서 말씀드렸던 단점들도 없습니다.. 그냥 밉맵만드실때 이런순서로 만들어 주시면 됩니다.
  1. 밉맵 0으로부터 밉맵 1 생성 (bilinear filter)
  2. 밉맵 1에 sharpening filter 적용
  3. 2번 결과물로부터 밉맵 2 생성(bilinear filter)
  4. 밉맵 2에 sharpening filter 적용
  5. 밉맵 끝까지 만들때까지 반복...

이 방법을 대충 포토샵으로 흉내낸걸 보여드리면 대충 이렇습니다. 오른쪽이 제 방법입니다.
















반응형

'그래픽스(Graphics) > DirectX9~12' 카테고리의 다른 글

DirectX SDK (June 2010) 설치 Error Code S1023  (0) 2019.07.25
키프레임 애니메이션  (0) 2016.08.06
Early Z  (0) 2013.06.08
Direct3D 9 에 래스터라이즈 규칙  (0) 2013.05.10
x파일에 대한 pdf  (0) 2013.03.11
반응형

http://en.wikipedia.org/wiki/ARB_assembly_language


ARB Assembly Instructions [edit]

ARB assembly supports the following instructions:

  • ABS - absolute value
  • ADD - add
  • ARL - address register load
  • DP3 - 3-component dot product
  • DP4 - 4-component dot product
  • DPH - homogeneous dot product
  • DST - distance vector
  • EX2 - exponential base 2
  • EXP - exponential base 2 (approximate)
  • FLR - floor
  • FRC - fraction
  • LG2 - logarithm base 2
  • LIT - compute light coefficients
  • LOG - logarithm base 2 (approximate)
  • MAD - multiply and add
  • MAX - maximum
  • MIN - minimum
  • MOV - move
  • MUL - multiply
  • POW - exponentiate
  • RCP - reciprocal
  • RSQ - reciprocal square root
  • SGE - set on greater than or equal
  • SLT - set on less than
  • SUB - subtract
  • SWZ - extended swizzle
  • TEX - Texture lookup
  • XPD - cross product

This is only a partial list of assembly instructions ; a reference can be found here : Shader Assembly Language (ARB/NV) Quick Reference Guide for OpenGL.

반응형
반응형

http://www.gamedev.net/topic/478820-derivative-instruction-details-ddx-ddy-or-dfdx-dfdy-etc/
Hi All, From my understanding the derivative instructions ddx,ddy,fwidth etc. Use 2x2 blocks of pixels to compute the derivative. Can someone please explain: 1.) What happens on triangle boundaries where a triangle only intersects one or 2 pixels of the 2x2 region 2.) The exact formula for the derivatives for each pixel in the 2x2 block. For example, given the block: a b c d the ddx derivative for pixel a/b/c/d could be ((b-a)+(d-c))/2 or it could be b-a for a/b and d-c for c/d. I have scoured the net and haven't found a good reference for this. I have found that if I draw a box and take the derivative of a complicated calculated value that *sometimes* i get artifacts on the border of the box's polygons. I imagine this is due to how it is computed on polygon boundaries. Any help would be appreciated. Cheers! Eric [Edited by - WizardOfOzzz on January 9, 2008 8:16:57 PM] 
    Sponsor:

    #2AndyTX   Members   -  Reputation: 798

    Like
    0Likes1Likes
    Like

    Posted 09 January 2008 - 02:42 PM

    Quote:
    Original post by WizardOfOzzz
    From my understanding the derivative instructions ddx,ddy,fwidth etc. Use 2x2 blocks of pixels to compute the derivative.

    That's correct.

    Quote:
    Original post by WizardOfOzzz
    1.) What happens on triangle boundaries where a triangle only intersects one or 2 pixels of the 2x2 region

    The shader is evaluated for all of the pixels in the 2x2 "quad", even if some of them fall outside of the triangle.

    Quote:
    Original post by WizardOfOzzz
    2.) The exact formula for the derivatives for each pixel in the 2x2 block. For example, given the block:
    a b
    c d

    IIRC the ddx(a) and ddx(b) will be (b-a), ddy(a) and ddy© will be (c-a) and so on.

    Quote:
    Original post by WizardOfOzzz
    I have found that if I draw a box and take the derivative of a complicated calculated value that *sometimes* i get artifacts on the border of the box's polygons.

    This problem can indeed occur if you're computing some function that is undefined or otherwise not well-behaved outside of the normal triangle interpolant range. Similar problems can occur with multi-sampling, but there you can often solve them using "centroid" interpolation. I don't recall exactly how derivatives interact with centroid interpolation but I wouldn't be surprised if it is implementation-dependent. 


    반응형

    '그래픽스(Graphics) > Shader' 카테고리의 다른 글

    Subsurface scattering  (0) 2013.07.14
    셰이더에서 사용되는 어쎔명령들  (0) 2013.06.08
    셰이더 변수,함수들  (0) 2013.06.03
    웹에서 셰이더 보기 웹 GLSL  (0) 2013.06.03
    SSAO( Screen Space Ambient Occlusion )  (0) 2013.05.20
    반응형

    http://eppengine.com/zbxe/3103


    early z test 는 pixel 단위의 culling 방식이다.

     

    간단히 이야기 하면, 각 픽셀을 연산이 되기전에 깊이테스트를 통해서 보이지 않는 pixel 에 대한 연산은

     

    적절히 skip 하기위한 pixel culling 방식이라고 이해하면 된다.

     

    하지만 Pipe Line 단계에서 Z test 는 pixel shader (fragment shader) 다음에 이루어진다.

     

    그렇다면, pipe 라인상에서는 z-test 가 pixel 연산 다음에 이루어 지는데, 어떻게 앞에서 처리 할 것 인가?

     

    결론부터 이야기 하면 하드웨어 단계에서 지원이 되어야만 가능한 부분이다.

     

    예를들어 Nvidia Geforce 8000 대의 gpu 의 경우 특정 상황에서는 자동적으로 early z 기능이 활성화 된다.

     

     

    Use

     

    다음의 순서를 따른다.

     

    1. 컬러쓰기를 disable 하고 write depth 만 enable 한다.

    (이럴경우 nvidia 의 fx 이상급 gpu 에서는 double speed z write 가 활성화 된다.)

     

    2. depth 를 clear 하지 않은 상태에서 ( depth buffer 를 clear 하지 않는다는 의미 ) 정상적인 rendering 을 실시한다.

    (이때 depth test 연산자를 equal 로 설정한다. )

     

    3. 1번 단계에서 기록된 depth buffer 값은 2번 단계를 거치면서 깊이비교에서 실패한 pixel 들을 자동적으로 연산에서 제외 시키게 된다. 

    ( early z )

     

    반응형

    '그래픽스(Graphics) > DirectX9~12' 카테고리의 다른 글

    키프레임 애니메이션  (0) 2016.08.06
    밉맵 디테일 높이기  (0) 2013.06.10
    Direct3D 9 에 래스터라이즈 규칙  (0) 2013.05.10
    x파일에 대한 pdf  (0) 2013.03.11
    NormalMapGenerator  (0) 2013.02.23
    반응형






    복사

    http://pusna25.blog.me/100187965288


    셰이더의 종류:

    • HLSL: DirectX에서 사용하는 셰이더 언어.
    • GLSL: OpenGl Shader Language의 약자로, OpenGL에서 지원하는 셰이더 언어. HLSL과 문법이 조금 다름.
    • CgFX: 엔비디아에서 지원하는 셰이더 언어로 HLSL과 거의 동일함.

     

    HLSL(High-Level Shading Languae):

    • 고수준 셰이딩 언어.
    • 버텍스와 픽셀 셰이더는 고정 기능 파이프라인을 대체하는 작은 커스텀 프로그램.
    • 그래픽 카드의 GPU에서 실행된다.
    • 간단히 말해서, 화면에 존재하는 각 픽셀의 위치와 색상을 계산하는 함수.

     

    정점 셰이더(vertex shader):

    • 3D 물체를 구성하는 정점들의 위치를 화면 좌표로 변환하는 것.

     

    픽셀 셰이더(pixel shader):

    • 화면에 출력할 최종 색상을 계산하는 것.

    간략하게 만든 3D 파이프라인:

    • 정점 데이터(위치 등)->정점 셰이더(정점 위치)->레스터라이저(픽셀 위치)->픽셀 셰이더(색상)->화면.

     

     HLSL 셰이더의 컴파일:

    • 상수 테이블:
      • 모든 셰이더는 내부의 변수를 보관하기 위한 상수 테이블을 가지고 있으며, D3DX 라이브러리는 애플리케이션이 셰이더의 상수 테이블에 접근할 수 있도록 하는 ID3DXConstantTalbe 인터페이스를 제공한다.
      • 즉, 이 인터페이스를 이용하면 애플리케이션(VS) 코드에서 셰이더 소스 코드 내의 변수 값을지정할 수 있다.
    • 상수로의 핸들 얻기:
      • 애플리케이션 코드에서 셰이더의 특정 변수를 지정하기 위해서는 먼저 변수를 참조 하는 방법이 필요하며, 이를 위해 D3DXHANDLE이 이용된다.
      • ID3DXConstantTalbe::GetConstantByName()이란 함수로 핸들을 얻는다.
    • 상수 값 설정하기:
      • 셰이더 코드 내의 변수를 연결하는 D3DXHANDLE을 얻은 다음에는 ID3DXConstantTalbe::SetXXX 메서드를 이용해 애플리케이션에서 셰이더의 변수 값을 지정할 수 있다.
      • 여기에서 XXX는 지정하려는 지정하려는 변수의 형을 의미하는 형 이름으로 대체된다. ex) SetFloat, SetBool 등...

     

    SetXXX() 함수:

    • SetBool():
      • 불 값을 지정.
      • bool b = true;
      • SetBool(Device, handle, b);
    • SetBoolArray():
      • 불 배열의 값을 지정.
      • bool b[3] = { true, false, true };
      • SetBoolArray(Device, handle, b, 3);
    • SetFloat():
      • 부동 소수  값을 지정.
      • float f = 3.14f;
      • SetFloat(Device, handle, f);
    • SetFloatArray():
      • 부동 소수 배열의 값을 지정.
      • float f[2] = { 1.0f, 2.0f };
      • SetFloatArray(Device, handle, f, 2);
    • SetInt():
      • 정수 값을 지정.
      • int x = 4;
      • SetInt(Device, handle, x);
    • SetIntArray():
      • 정수 배열의 값을 지정.
      • int x[4] = { 1,2,3,4 };
      • SetIntArray(Device, handle, x, 4);
    • SetMatrix():
      • 4x4 행렬의 값을 지정.
      • D3DXMATRIX M(...);
      • SetMatrix(Device, handle, &M);
    • SetMatrixArray():
      • 4x4 행렬 배열의 값을 지정.
      • D3DXMATRIX M[4];
      • ... 행렬 초기화.
      • SetMatrixArray(Device, handle, M, 4);
    • SetMatrixPointerArray():
      • 4x4 행렬 포인터의 배열 값을 지정.
      • D3DXMATRIX*  M(...);
      • ... 행렬 포인터를 할당하고 초기화.
      • SetMatrixPointerArray(Device, handle, M,  4);
    • SetMatrixTranspose():
      • 전치 4x4 행렬의 값을 지정.
      • D3DXMATRIX M(...);
      • D3DXMatrixTranspose(&M, &M);
      • SetMatrixTranspose(Device, handle, &M);
    • SetMatrixTransposeArray():
      • 전치 4x4 행렬의 배열 값을 지정.
      • D3DXMATRIX M[4];
      • ... 행렬을 초기화하고 전치.
      • SetMatrixTransposeArray(Device, handle, M, 4);
    • SetMatrixTransposePointerArray():
      • 4x4 전치 행렬의 포인터 배열 값을 지정.
      • D3DXMATRIX* M[4];
      • ... 행렬 포인터를 할당, 초기화하고 전치.
      • SetMatrixTransposePointerArray(Device, handle, M, 4);
    • SetVector():
      • D3DXVECTOR4 형 변수의 값을 지정.
      • D3DXVECTOR4  v(1.0f, 2.0f, 3.0f, 4.0f);
      • SetVector(Device, handle, &v);
    • SetVectorArray():
      • 벡터 배열의 변수 값을 지정.
      • D3DXVECTOR4 v[3];
      • ... 벡터를 초기화.
      • SetVectorArray(Device, handle, v, 3);
    • SetValue():
      • 구조체와 같이 임의의 크기를 가진 형의 값을 지정.
      • D3DXMATRIX M(...);
      • SetValue(Device, handle, (void*)&M, sizeof(M));
      • 위에서는 D3DXMATRIX 값을 지정하는 데 사용함.
    • SetDefaults():
      • 상수의 디폴트 값 지정.
      • SetDefaults(Device);

    변수 형:

    • 스칼라 형:
      • bool: True, False 값. HLSL은 True와 False 키워드를 제공.
      • int: 32비트 부호 정수.
      • half: 16비트 부동 소수점 수.
      • float: 32비트 부동 소수점 수.
      • double: 64비트 부동 소수점 수.
    • 벡터 형:
      • vector: float 성분을 가지는 4D 벡터.
      • vecot<T, n>: n-차원의 벡터. 각각의 성분은 T형의 스칼라이다. 차원 n은 반드시 1~4내에 있어야 한다.
        • ex) vector<double, 2> vec2;
      • float2 vec2;   // 2D 벡터.
      • float3 vec3;   // 3D 벡터.
      • float4 vec4;   // 4D 벡터. 처럼 미리 정의된 형을 이용할 수 있다.
    • 행렬 형:
      • matrix: 4x4 행렬. 각 항목은 float이다.
      • matirx<T, M, n>: m*n행렬. T는 스칼라형.
    • 배열:
      • float M[4][4];
      • half p[4];
      • vector v[12];
    • 구조체:
      • C++와 다르게 HLSL 구조체는 멤버함수를 가질 수 없다는 거 말고 동일함.
    • typedef 키워드:
      • C++의 typedef와 완전 동일 함.

     

    변수 접두어:

    • static:
      • 변수 선언에 static 키워드를 이용하면 셰이더 외부에서 변수에 접근할 수 없음을 지정.
      • 다른 말로, 셰이더 내의 지역 변수로 이용.
      • static 키워드를 붙이면 함수가 처음 실행될 때 한번만 초기화되며 나머지 함수가 호출되는 동안 값을 유지한다.
      • 초기화하지 않으면 0으로 초기화된다.
    • uniform:
      • 변수가 셰이더 외부, 예를 들어 C++ 애플리케이션에서 초기화되어 셰이더에 입력됨을 의미.
    • extern:
      • 셰이더 외부에서 변수에 접근할 수 있음을 의미.
      • 전역 변수만이 extern 키워들 가질 수 있다.
      • static이 아닌 전역 변수는 디폴트로 extern이다.
    • shared:
      • 이펙트 프레임웍에게 변수가 다수의 효과에 공유될 것임을 알린다.
      • 전역 변수만이 shared 키워드를 가진다.
    • volatile:
      • 이펙트 프레임웍에게 변수가 자주 수정될 것임을 알린다.
      • 전역 변수만이 volatile 키워드를 가진다.
    • const:
      • C++과 동일함.

     


    반응형
    반응형

    http://glsl.heroku.com/




    반응형
    반응형




    http://kyruie.tistory.com/31




    원문 : http://wiki.gamedev.net/index.php/D3DBook:Screen_Space_Ambient_Occlusion


    SSAO( Screen Space Ambient Occlusion )



    컴퓨터로 생성된 이미지에 사실성을 향상시키기 위한 방법들은 매우 많다. 그런 방법들 중 하나가 물체의 라이팅 방정식을 이용해 값을 구할때 그림자 효과를 계산하는 방법이다. 실시간 컴퓨터 그래픽에서 유용한 그림자 기법들은 매우 많으며, 그러한 각각 기법들은 장단점을 모두 보인다. 일반적으로, 그림자 기법들은 그림자 품질과 실행 효율 사이의 균형을 취하려 노력한다.

    그런 기법들중 하나가 바로 SSAOScreen Space Ambient Occlusion라고 불리는 기법이다. 이 기법은 Martin Mittring이 2007 SIGGRAPH 컨퍼런스에서 발표한 논문 "Finding Next Gen"에서 처음 논의되었다. 이 알고리즘의 기본 컨셉은  
     전역 조명 과정Ambient lighting term을 장면의 한 점이 얼마나 차폐되는지를 구하는 기반으로 바꾸는 것이다. 이 방법이 AO의 컨셉을 처음으로 이용하는 기법은 아니지만, 이후의 장chapter에서 보게 되겠찌만 SSAO는 꽤나 현명한 추정과단순함으로 매우 높은 성능을 유지하면서도 만족할만한 결과를 보여준다.



    그림 1. SSAO를 이용한 샘플 렌더링 화면

    이 번 장에서는, SSAO의 배경이 되는 이론을 살펴보고, Direct3d 10 파이프라인을 이용하여 이 기법을 구현하는 방법을 제공하며, 성능과 품질의 향상을 위해 구현 단계에서 사용할 수 있는 파라미터들에 대하여 논의할 것이다. 마지막으로, 주어진 구현을 이용한 데모에 대하여 논의하여 이를 통해 알고리즘의 성능에 대해서 몇 가지 사항을 알리고자 한다.

    알고리즘 이론

    이제 우리는 SSAO의 유래에 관한 배경지식에 대해서 살펴보았으므로, 기법에 대하여 더욱 자세하게 살펴볼 준비가 되었다. SSAO는 단 하나의 단순한 명제를 사용함으로써 이전의 기법들과는 다른점을 보인다: SSAO는 이전에 레스터화되기 이전의 장면 정보를 사용하는 대신 현재 장면에서 주어진 점의 차폐의 양을 구하는데 오직 깊이 버퍼만을 이용한다. 이를 위해 깊이 버퍼를 직접적으로 사용하는 방법이나 깊이 정보를 보관하기 위해 특별한 렌더타겟을 생성하는 방법 모두 가능하다. 깊이 정보는 주어진 점의 주변점을 구하는 즉시 세밀하게 조사하여 그 점이 얼마나 차폐되었는지 계산하는데 사용한다. 차폐 인수occlution factor은 한지점에 얼마만큼의 전역광을 적용할것인지, 그 양을 조절하는데 사용한다.

    SSAO 알고리즘에서 사용하는 차폐 인수을 생성하는 방법은 논리적으로 두 단계 과정으로 이루어져 있다. 먼저 우리는 장면의 현재 시점을 기준으로 깊이 텍스처를 생성해야하고, 이 깊이 텍스처를 이용하여 현 장면의 최종 화면에서 각 픽셀의 차폐 정도를 결정한다. 이 과정은 아래의 그림 2에서 볼 수 있다.

    그림2. SSAO 알고리즘의 개요
    깊이 버퍼만을 사용하는 이 단순함은 성능과 품질면에서 몇가지 효과가 있다. 장면 정보가 렌더타겟으로 레스터화 하는 경우, 장면을 나타내는데 사용하는 정보가 3차원에서 2차원으로 줄어들게 된다. 데이터 축소는 매우 효율적인 명령을 제공하는 표준 GPU 파이프라인 하드웨어를 통해 수행된다. 또한 장면의 전체 차원을 줄임으로, 2D 장면 표현을 장면의 가시 영역으로 한정하여 이 프레임에 보이지 않는 물체에 대한 불필요한 연산을 제거할 수 있게 된다.

    데이터 축소는 차폐 인수을 계산하는데 있어서 확실한 성능상의 이득을 제공하지만, 동시에 연산시에 필요한 정보 또한 제거한다. 이것은 우리가 계산으로 얻은 차폐 인수 값이 꼭 정확한 값이 아닐 수 있음을 의미하지만, 이후의 장에서 보게 되겠지만  전역 조명 과정은 근사치 일지라도 훌륭하게 장면의 현실감을 부여해 준다.

    텍스처에 장면의 깊이 정보를 저장한 뒤, 깊이 값의 직접 인접에 기반하여 각 점이 얼마나 차폐되었는지 결정해야 한다. 이 연산은 다른 AO 기법들과 꽤나 비슷하다. 그림 3에 보이는 바와같이 깊이 버퍼를 고려해야한다 :

    그림 3. 뷰view 방향이 아래쪽으로 향한 샘플 깊이 버퍼

    이상적으로 주어진 점을 중심으로 둘러싼 반지름 r인 구를 생성하고, 그 구와 깊이 버퍼에 있는 물체와 교차하는 부피를 구하기 구를 따라 통합해 나간다. 이 컨셉은 여기 그림 4에서 볼 수 있다.

    그림 4. 차폐를 계산하기 위한 이상적인 샘플링 구

    물론, 렌더된 이미지의 모든 픽셀에서 복잡한 3D 통합을 수행하는 것은 전적으로 비효율적이다. 대신, 이 구의 부피 내에 존재하는 3D 샘플링 커널을 이용하여 이 구를 추정할 것이다. 샘플링 커널은 명시된 지점의 깊이 버퍼를 살펴, 그 각 가상의 점이 깊이 표면에 의해 가려지는지 결정하는데 이용된다. 샘플링 커널의 예시는 그림 5에 나타나 있으며, 우리의 표면점에 어떻게 적용해야 하는지도 보여준다.

    그림 5. 단순화한 샘플링 커널과 깊이 버퍼 내에의 위치

    차폐 인수는 차폐가 발생한 샘플링 커널의 합으로 구할 수 있다. 구현 부분에서 살펴보겠지만, 이 개별적인 계산은 카메라부터의 거리, 차폐 지점과 기준점 간의 거리, 아티스가 지정한 비례축소 인수 등의 몇가지 다른 인수들에 따라 더 민감하게, 혹은 덜 민감하게 할 수 있다.

    구현

    알고리즘이 어떻게 기능하는지 이해했따면, 이제 구현하는 방법에 대해 논의해 보자. 알고리즘 이론 파트에서 논의했듯이, 장면의 깊이 정보가 담긴 소스가 필요하다. 간단하게 하기 위해, 우리는 깊이 정보를 저장하기 위해 서로다른 부동소수 버퍼를 사용할 것이다. 비록 조금 더 복잡할지는 모르겠지만, 더 효율적인 기법은 장면의 깊이 값을 얻기 위해 z-버퍼를 이용할 것이다. The following code snippet shows how to create the floating point buffer, as well as the render target and shader resource views that we will be binding it to the pipeline with: 

    01.// 깊이 버퍼 생성
    02.D3D10_TEXTURE2D_DESC desc;
    03.ZeroMemory( &desc, sizeof( desc ) );
    04.desc.Width = pBufferSurfaceDesc->Width;
    05.desc.Height = pBufferSurfaceDesc->Height;
    06.desc.MipLevels = 1;
    07.desc.ArraySize = 1;
    08.desc.Format = DXGI_FORMAT_R32_FLOAT;
    09.desc.SampleDesc.Count = 1;
    10.desc.Usage = D3D10_USAGE_DEFAULT;
    11.desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE;
    12. 
    13.pd3dDevice->CreateTexture2D( &desc, NULL, &g_pDepthTex2D );
    14. 
    15.// 렌더 타겟 리소스 뷰 생성
    16.D3D10_RENDER_TARGET_VIEW_DESC rtDesc;
    17.rtDesc.Format = desc.Format;
    18.rtDesc.ViewDimension = D3D10_RTV_DIMENSION_TEXTURE2D;
    19.rtDesc.Texture2D.MipSlice = 0;
    20. 
    21.pd3dDevice->CreateRenderTargetView( g_pDepthTex2D, &rtDesc, &g_pDepthRTV );
    22. 
    23.// 셰이더-리소스 뷰 생성
    24.D3D10_SHADER_RESOURCE_VIEW_DESC srDesc;
    25.srDesc.Format = desc.Format;
    26.srDesc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE2D;
    27.srDesc.Texture2D.MostDetailedMip = 0;
    28.srDesc.Texture2D.MipLevels = 1;
    29. 
    30.pd3dDevice->CreateShaderResourceView( g_pDepthTex2D, &srDesc, &g_pDepthSRV );


    깊이 정보를 생성한 후, 다음 단계는 최종 장면 내 각 픽셀의 차폐 인수를 계산하는 것이다. 이 정보는 두번째 단일 성분 부동소수 버퍼에 저장할 것이다. 이 버퍼를 생성하기 위한 코드는 부동소수 깊이 버퍼를 생성하기 위해 사용한 코드와 매우 유사하므로, 페이지 길이를 줄이기 위해 생략한다.

    이제 두 버퍼가 모두 생성되었으므로, 각 버퍼에 저장할 정보를 생성하는 부분을 상세히 살펴보자. 깊이 버퍼는 뷰 공간의 깊이값을 기본적으로 저장한다. 절단 공간 깊이clip space depth 대신 선형 뷰 공간 깊이linear view space depth를 사용하여 투시 투영perspective projection으로 인한 깊이 범위 왜곡을 방지한다. 뷰 공간 깊이는 입력 버텍스와 월드뷰world-view 행렬을 곱해서 구할 수 있다. 그런뒤 뷰 공간 깊이는 단일 성분 버텍스 속성으로 픽셀 셰이더로 전달된다. 

    01.fragment VS( vertex IN )
    02.{
    03.fragment OUT;
    04.// 절단 공간 좌표를 출력
    05.OUT.position = mulfloat4(IN.position, 1), WVP );
    06.// 뷰 공간 좌표를 계산
    07.float3 viewpos = mulfloat4( IN.position, 1 ), WV ).xyz;
    08.// 뷰 공간 깊이값을 저장
    09.OUT.viewdepth = viewpos.z;
    10.return OUT;
    11.}


    깊이값을 부동소수 버퍼에 저장하기 위해, 픽셀 셰이더에서는 근거리 클리핑 평면과 원거리 클리핑 평면간의 거리에 따라 깊이값을 확대/축소한다. 이것은 범위 [ 0, 1 ]을 가진 선형, 정규화된 깊이 값을 생성한다. 

    01.pixel PS( fragment IN )
    02.{
    03.pixel OUT;
    04. 
    05.// 뷰 공간 범위에 따라 깊이값을 확대/축소
    06.float normDepth = IN.viewdepth / 100.0f;
    07. 
    08.// 확대/축소된 값을 출력
    09.OUT.color = float4( normDepth, normDepth, normDepth, normDepth );
    10. 
    11.return OUT;
    12.}


    저장된 정규화된 깊이 정보를 가지고, 각 픽셀의 차폐 인수를 생성하기 위해 깊이 버퍼를 셰이더 리소스로 바인딩하고 각 차폐 버퍼에 저장한다. 차폐 버퍼 생성은 단일 전체 스크린 화면을 렌더링함으로써 초기화한다. 전체 스크린 화면의 버텍스들은 단지 단일 2-성분 속성을 가지고 있으며, 이는 깊이 버퍼 내의 자신의 위치에 대응하는 텍스처 좌표를 나타내고 있다. 버텍스 셰이더는 단순히 이 파라미터들을 픽셀 셰이더에 전달만 한다.

    1.fragment VS( vertex IN )
    2.{
    3.fragment OUT;
    4.OUT.position = float4( IN.position.x, IN.position.y, 0.0f, 1.0f );
    5.OUT.tex = IN.tex;
    6. 
    7.return OUT;
    8.}


    필셀 셰이더는 3D 샘플링 커널의 형태를 3-성분 벡터의 배열로 정의하는 것으로 시작한다. 벡터의 길이는 [ 0, 1 ] 범위 사이에서 다양히 변하며 각 차폐 테스트에서 약간의 변화를 주게 된다.

    01.const float3 avKernel[8] ={
    02.normalizefloat3( 1, 1, 1 ) ) * 0.125f,
    03.normalizefloat3( -1,-1,-1 ) ) * 0.250f,
    04.normalizefloat3( -1,-1, 1 ) ) * 0.375f,
    05.normalizefloat3( -1, 1,-1 ) ) * 0.500f,
    06.normalizefloat3( -1, 1 ,1 ) ) * 0.625f,
    07.normalizefloat3( 1,-1,-1 ) ) * 0.750f,
    08.normalizefloat3( 1,-1, 1 ) ) * 0.875f,
    09.normalizefloat3( 1, 1,-1 ) ) * 1.000f
    10.}


    다음으로, 픽셀 셰이더는 텍스처 룩업 내에서 샘플링 커널을 반사시키기 위한 렌덤 벡터를 찾는다. 이것은 사용한 샘플링 커널을 이용해 매우 다양한 변화를 줄 수 있으며, 이는 적은 수의 차폐 테스트를 하더라도 높은 수준의 결과를 제공할 수 있게 해준다. 이는 차폐를 계산하기 위한 깊이를 효과적으로 "흐트려jitter" 주어, 우리가 현재 픽셀의 주변 공간을 언더샘플링 한다는 사실을 숨겨준다.

    1.float3 random = VectorTexture.Sample( VectorSampler, IN.tex.xy * 10.0f ).xyz;random = random * 2.0f - 1.0f;


    이제 픽셀 셰이더가 현제 픽셀의 깊이값을 바탕으로 샘플링 커널에 적용하기 위한 확대/축소값을 계산할 것이다. 이 픽셀의 깊이값은 깊이 버퍼로부터 읽어들여 근거리 평면과 원거리 평면간의 거리를 곱함으로 뷰 공간으로 도로 확장된다. 그런 뒤 샘플링 커널의 x 와 y 성분을 위한 확대/축소값을 계산하는데, 이는 샘플링 커널의 희망 반지름( 미터 단위 )을 픽셀의 깊이값( 미터 단위 )로 나누면 된다. 이는 개별 샘플을 찾기위해 사용되는  텍스처 좌표를 확대/축소한다. z 성분의 확대/축소값은 희망 커널 반지름을 근거리 평면과 원거리 평면간의 거리로 나누어 구할 수 있다. 이는 모든 깊이값의 비교를 우리가 깊이 버퍼에 저장한것과 같은 정규화된 깊이 공간에서 이루어지도록 하게 해준다.

    1.float fRadius = vSSAOParams.y;
    2.float fPixelDepth = DepthTexture.Sample( DepthSampler, IN.tex.xy ).r;
    3.float fDepth = fPixelDepth * vViewDimensions.z;
    4.float3 vKernelScale = float3( fRadius / fDepth, fRadius / fDepth, fRadius / vViewDimensions.z );


    커널 확대/축소값이 구해지면, 개별 차폐 테스트를 수행할 수 있게 된다. 이것은 for 루프 내에서 샘플링 커널이 가르키는 각 점들을 계속해서 반복하는 것으로 이루어진다. 현재 픽셀의 텍스처 좌표는 렌덤하게 반사된 커널 벡터의 x와 y 성분을 통해 차감 계산되고 새 좌표에서 깊이값을 살펴보기 위해 사용된다. 이 깊이 값은 커널 벡터의 z 성분을 통해 차감 계산되고 현재 픽셀의 깊이와 비교된다. 
     
    01.float fOcclusion = 0.0f;
    02.for int j = 1; j < 3; j++ )
    03.{
    04.float3 random = VectorTexture.Sample( VectorSampler, IN.tex.xy * ( 7.0f + (float)j ) ).xyz;
    05.random = random * 2.0f - 1.0f;
    06. 
    07.for int i = 0; i < 8; i++ )
    08.{
    09.float3 vRotatedKernel = reflect( avKernel[i], random ) * vKernelScale;
    10.float fSampleDepth = DepthTexture.Sample( DepthSampler, vRotatedKernel.xy + IN.tex.xy ).r;
    11.float fDelta = max( fSampleDepth - fPixelDepth + vRotatedKernel.z, 0 );
    12.float fRange = abs( fDelta ) / ( vKernelScale.z * vSSAOParams.z );
    13.fOcclusion += lerp( fDelta * vSSAOParams.w, vSSAOParams.x, saturate( fRange ) );
    14.}
    15.}


    깊이값의 델타값( = 차이값 )은 어플리케이션의 선택가능한 범위값으로 정규화된다. 이것은 깊이값 차이의 관계 등급을 결정하기 위한 인수를 생성하기 위함이다. 차례로, 이 정보는 이 특정의 차폐 테스트의 범위를 수정할 수 있다. 예를 들어, 한 물체가 장면의 전경에 위치하고 다른 하나의 물체가 그 뒤에 부분적으로 가려져 있다면, 전경의 물체가 유일한 차폐물인 경우 뒷쪽 물체를 위해 불필요한 차폐 테스트를 계산할 필요가 없다. 반대로 배경의 물체에는 앞 물체의 가장자리를 따라 그림자 같은 후광이 나타날 것이다. The implementation of this scaling is to linearly interpolate between a scaled version of the delta value and a default value, with the interpolation amount based on the range value. 

    1.fOcclusion += lerp( ( fDelta * vSSAOParams.w ), vSSAOParams.x, saturate( fRange ) );


    최종 픽셀 색상을 내놓기 전의 마지막 단계는 모든 커널 샘플로부터 평균 차폐값을 계산하고, 그 값을 최대/최소 차폐 값 사이를 보간하는데 사용하는 것이다. 이 마지막 보간은 광범위한 차폐값을 압축해주고 보다 부드러운 출력을 제공해준다. 이 장의 데모 프로그램에서 주의할 것은, 사진의 차폐를 계산하는데 단지 16샘플만을 사용했다는 것이다. 만일 더 많은 샘플을 사용했다면, 출력 차폐 버퍼는 더 부드러운 결과를 보여줄 것이다. 이것은 다른 등급의 하드웨어들에서 성능과 품질을 조정하는 좋은 방법이 된다.
     
    1.OUT.color = fOcclusion / ( 2.0f * 8.0f );
    2. 
    3.// 범위 재매핑
    4.OUT.color = lerp( 0.1f, 0.6, saturate( OUT.color.x ) );


    생성한 차폐 버퍼를 가지고, 최종 렌더링 패스에서 셰이더 자원에 포함해 이를 이용할 수 있다. 렌더된 기하는 단수히 스크린 공간 텍스쳐 좌표를 계산하고, 차폐 버퍼를 샘플링한 뒤, 그 값을 이용하여 ambient 조건을 조정하면 된다. 예시로 제공되는 파일은 단순히 다섯 샘플의 평균을 이용하는 방법을 사용하였지만, 가우시안 브럴와 같은 좀더 세련된 방법을 대신 사용하는 것도 좋다.


    SSAO 데모

    데모 다운로드 : SSAO_Demo

    이번 장을 위해 만든 데모 프로그램은 단순히 다수의 정방면체를 우리의 SSAO 셰이더만을 이용하여 렌더링한 것이다. 이번 기법에서 논의된 조절가능한 파라미터들에 대해서는 화면상의 슬라이더 콘트롤러를 이용하여 실시간으로 바꿀 수 있다. 그림 6 이하는 차폐 버퍼의 모습과 최종 출력 렌더링의 결과를 볼 수 있다. 한가지 알릴 사실은 차폐 효과를 보다 과장하기 위하여 차폐 파라미터들을 조절했다. 

    그림 6. 데모 프로그램의 차폐 버퍼의 모습


    그림 7. 데모 프로그램의 최종 출력 렌더링의 모습

    결론 

    In this chapter we developed an efficient, screen space technique for adding realism to the ambient lighting term of the standard phong lighting model. This technique provides one implementation of the SSAO algorithm, but it is certainly not the only one. The current method can be modified for a given type of scene, with more or less occlusion for distant geometry. In addition, the minimum and maximum amounts of occlusion, interpolation techniques, and sampling kernels are all potential areas for improvement or simplification. This chapter has attempted to provide you with an insight into the inner workings of the SSAO technique as well as a sample implementation to get you started.










    http://www.eppengine.com/zbxe/programmig/2982



    SSAO 는 최근에 많이 이슈가 되고 있는 GI 기법중 하나이다.

     

    GI 라고 하면 단순히 모든 오브젝트가 빛을 발산하는 주체가 된다고만 생각하는데, (빛 반사를 통해.. )

     

    빛으로인해 생겨지는 그림자 역시 GI중 하나이다.

     

    SSAO 는 많은 사람들이 알고 있듯이 환경광 차폐를 화면공간에서 처리하는 기법으로

     

    크게 깊이를 이용한 기법, 깊이와 상방벡터를 이용하는 기법 두가지가 있다.

     

    환경광 차폐가 일어나는 경우에 대해서는 KGC2009 강연자료중 Lighting In Screen Space 의 ppt 자료를 참고.

     

    여하튼.. 위에서 이야기한 두가지 기법 모두 장단이 있기에 적절한 방식을 선택해서 사용하면 되겠다.

     

     

     

    uniform sampler2D som;  // Depth texture 

    uniform sampler2D rand; // Random texture 
    uniform vec2 camerarange = vec2(1.01024.0);
          
       float pw = 1.0/800.0*0.5
       float ph = 1.0/600.0*0.5;  

       float readDepth(in vec2 coord)  
       {  
         if (coord.x<0||coord.y<0return 1.0;
          float nearZ = camerarange.x;  
          float farZ =camerarange.y;  
          float posZ = texture2D(som, coord).x;   
          return (2.0 * nearZ) / (nearZ + farZ - posZ * (farZ - nearZ));  
       }   

       float compareDepths(in float depth1, in float depth2,inout int far)  
       {  

         float diff = (depth1 - depth2)*100//depth difference (0-100)
         float gdisplace = 0.2//gauss bell center
         float garea = 2.0//gauss bell width 2

         //reduce left bell width to avoid self-shadowing
         if (diff<gdisplace){ 
            garea = 0.1;
         }else{
            far = 1;
         }
         float gauss = pow(2.7182,-2*(diff-gdisplace)*(diff-gdisplace)/(garea*garea));

         return gauss;
       }  

       float calAO(float depth,float dw, float dh)  
       {  
         float temp = 0;
         float temp2 = 0;
         float coordw = gl_TexCoord[0].x + dw/depth;
         float coordh = gl_TexCoord[0].y + dh/depth;
         float coordw2 = gl_TexCoord[0].x - dw/depth;
         float coordh2 = gl_TexCoord[0].y - dh/depth;

         if (coordw  < 1.0 && coordw  > 0.0 && coordh < 1.0 && coordh  > 0.0){
         vec2 coord = vec2(coordw , coordh);
            vec2 coord2 = vec2(coordw2, coordh2);
            int far = 0;
         temp = compareDepths(depth, readDepth(coord),far);

            //DEPTH EXTRAPOLATION:
            if (far > 0){
              temp2 = compareDepths(readDepth(coord2),depth,far);
              temp += (1.0-temp)*temp2; 
            }
         }

         return temp;  
       }   
         
       void main(void)  
       {  
         //randomization texture:
         vec2 fres = vec2(20,20);
         vec3 random = texture2D(rand, gl_TexCoord[0].st*fres.xy);
         random = random*2.0-vec3(1.0);

         //initialize stuff:
         float depth = readDepth(gl_TexCoord[0]);  
         float ao = 0.0;

         for(int i=0; i<4; ++i) 
         {  
           //calculate color bleeding and ao:
           ao+=calAO(depth,  pw, ph);  
           ao+=calAO(depth,  pw, -ph);  
           ao+=calAO(depth,  -pw, ph);  
           ao+=calAO(depth,  -pw, -ph);

           ao+=calAO(depth,  pw*1.20);  
           ao+=calAO(depth,  -pw*1.20);  
           ao+=calAO(depth,  0, ph*1.2);  
           ao+=calAO(depth,  0, -ph*1.2);
         
           //sample jittering:
           pw += random.x*0.0007;
           ph += random.y*0.0007;

           //increase sampling area:
           pw *= 1.7;  
           ph *= 1.7;    
         }         

         //final values, some adjusting:
         vec3 finalAO = vec3(1.0-(ao/32.0));


         gl_FragColor = vec4(0.3+finalAO*0.7,1.0);  
       }  

    장점 : 따로 blur pass 를 실행할 필요가 없다. ( 랜덤맵 텍스쳐를 활용하기에 가능한 부분)

               시각적 품질이 나쁘지 않다.

               노멀 버퍼없이도 깔끔하다.

     

    단점 : 전통적 ssao 보다는 좀 느리다.

               역시 노멀 버퍼를 사용하지 않는 것 으로 인한 약간의 시각적 어색함이 존재.. 약간...








    http://ozlael.egloos.com/2963328



    SSAO (Screen Space Ambient Occlusion) 링크 모음 Game develop




    AO(Ambient Occlusion)는 사실적인 그림자 효과 라이팅의 방법 중 하나로써, 전역 조명 과정에서 한 점의 차폐 양을 계산 하는 것을 나타낸다. 이로써 장면 내의 입체 볼륨감을 더욱 부각시킬 수 있다. SSAO는 이를 Screen Space에서 수행하는 것이다. HBAO, SSDO등도 이와 한 뿌리다. 

    실제 적용 해보면 제일 애를 먹는 것이 half-resolution에서 AO 처리를 한 뒤 upscale을 하는 부분인데, 이는 inferred lighting의 DSF필터를 적용 하면 쉽게 해결 될 듯 하다.( DSF 적용 해보진 않음;; 언능 해봐야집)


    하지만 지글지글 문제는 해결이 안되지 싶은데.. 이놈때문에 엔진 디폴트로 AO는 꺼트린 상태다. 섬바뤼헬미~

    관련 링크 (문서 내 링크 중복도 많이 있다 =ㅈ=):

    http://www.gamedev.net/community/forums/topic.asp?topic_id=545825
    http://en.wikipedia.org/wiki/Screen_Space_Ambient_Occlusion
    http://www.gamedev.net/community/forums/topic.asp?topic_id=545825
    http://developer.amd.com/gpu_assets/S2008-Filion-McNaughton-StarCraftII.pdf
    http://www.gamerendering.com/2009/01/14/ssao/
    http://www.gamedev.net/community/forums/topic.asp?topic_id=550699
    http://www.vizerie3d.net/
    http://developer.download.nvidia.com/presentations/2008/SIGGRAPH/HBAO_SIG08b.pdf
    http://developer.download.nvidia.com/presentations/2008/GDC/GDC08_Ambient_Occlusion.pdf
    http://developer.download.nvidia.com/SDK/10.5/direct3d/Source/ScreenSpaceAO/doc/ScreenSpaceAO.pdf
    http://gamepro.tistory.com/539
    http://www.gamedev.net/reference/programming/features/simpleSSAO/

    반응형
    반응형


    http://blog.naver.com/sorkelf/40151293786


    Direct3D 9 에 래스터라이즈 규칙


    DirectX는 삼각형 폴리곤을 베이스로써 렌더링이 수행된다.

    당연하겠지만 잘 생각해보면 다음과같은 변환이 필요하다는것을 알게 된다


    삼각형 폴리곤의 각 버텍스는 부동소수점(float)로 표현된다. 소수점은 이론상으로는 연속된 값이다.

    이 버텍스가 여러가지로 수치변환되어 최종적으로는 스크린 좌표로 변환된다.

     

    이 스크린 좌표는 [ 정수 ]로, 스크린상의 점은 엄밀히 작은 정방형이다.

    정수는 아는대로 불연속한 것이다.

    연속이 어느새 불연속이 된것은 그다지 신경쓰지 않지만 실은 매우 중요한 것이다


    연속한 폴리곤을 불연속적인 픽셀로 바꾸려면 몇가지 룰이 필요하다.

    그 룰을 [ 레스터라이제이션 룰 (Rasterization Rule) ]이라고 한다. 

    예를 들면 아래 폴리곤에 있는 3개의 버텍스의 스크린 위치가 결정됐다고 했을대 그 주위와 내부는 어떻게 칠해질까를 생각해본다



       변을 포함하고 있는 어떤 파란 색으로 칠해질까? 만일 전부 칠해지나? 면적이 넓으면 칠해지나?

    이것들이 제대로 결정되어있지 않으면 외관이 완전히 변해버린다.


    이것은 특히 스크린 픽셀을 의식한 렌더링( 2D의 HUD나 포스트 이펙트 렌더링 같은 것)

    에 커다란 영향을 주게 된다


    여기에서는 이렇게 평범할수도 있지만 중요한 래스터라이제이션 룰에 대해 설명하고자 한다. 

    또한 언급이 없는 한 폴리곤은 스크린의 범위로 수치가 변환되고 있다고 한다. ( 단 소수점임)

    또한 사각형들은 화면의 도트 그 자체이다




    ① 스크린 도트와 버텍스의 위치 관계


       폴리곤이 여러가지 변환을 거쳐 스크린의 범위와 같은 값이 됐다고 하자. 단 이 값은 부동소수점 그대로이다. 이때의 폴리곤의 소수점 값과 스크린의 도트는 다음과 같은 위치 관계가 된다


     

    오렌지색 점이 폴리곤이 변환된 소수점 값이며, 빨간 숫자가 스크린좌표이다. (0이 기점인 것에 주의)

    소수점의 정수값(3.0이라던지)이 도트 중앙에 있는것이 포인트이다.


     DirectX에서는 [ 오렌지색 점이 폴리곤내에 포함되어있다면 기본적으로 렌더링한다 ] 라는

    룰이 적용되어 있다


    [ 기본적 ]이란것은, 단지 이 룰만 적용하는 것은 문제가 있다는 것이다.

    예를들면, 4X4의 작은 HUD를 표시하려고 할때의 이미지는 아래와 같다

    이것을 위에있던 그림과 맞춰보자

    잘 보면 가로 세로 5픽셀에 걸쳐져있다. 4X4로 할려고했더니 5X5?? 


    또 하나 별도의 문제. DirectX의 폴리곤은 삼각 폴리곤이다. 

    위의 사각 폴리곤을 삼각형으로 분할하면 어떻게 될까

      왼쪽 하단 폴리곤과 Right-Top 폴리곤의 경계선은 오렌지색의 점을 양쪽 모두 포함하고 있다.

    라는 것은 이 곳은 2번 칠해진다 라는 것이 된다. 


    포함하고 있는 부분을 단순히 칠한다라는 것만으로는 여러가지 문제가 생기게 되버린다는 것이다

    여기서 DirectX나 각종 GUI계에서는 [ Top - Left Filling Convention ] 이라는 룰을 채택한다



    ② Top-Left Filling Convention


     ①에 있는 문제를 해결하기 위해 DirectX에서는 Top-Left Filling Convention 이라는 룰을 적용하고 있다. 이것은、「Top-Left 있는 도트는 채택, Right-Bottom에 있는 도트는 채택하지 않음」이라는 심플한 룰이다. 여기서 말하는 Left-Top과 Right-Bottom이란 무엇인가?


        우선 [ Left ] 이란 삼각 폴리곤의 변이 폴리곤의 중앙으로부터 봤을때 왼쪽에 있는 측면을 말한다.

    [ Right ]는 그 반대이고, [ Top ]은 수평이며 중앙보다 위에있는 부분을 가리킨다. [ Bottom ]은 Top과 반대이다

     

     

       칠하려고했던 도트가 변에 대응(相当)하고 있는 경우, 그것이 Top-Left이면 채택, Right-Bottom이면 채택 하지 않는다. 이 룰을 위에서 봤던 사각 폴리곤에 적용하면 아래와 같이 된다

     

       파란색 셀은 왼쪽 하단의 폴리곤에 의해 칠해지는 곳이다. 이 폴리곤에는 왼쪽, 오른쪽, 하단이 있지만 그 가운데 오른쪽변과 아래쪽 변에 속해있는 셀은 칠하지 않는다.

    따라서 대각선의 부분과 가장 아래에있는 부분은 색칠 되지 않는다.

     

    오른쪽상단의 0,0 도트는 왼쪽 변과 오른쪽 변의 양쪽을 공유하고 있다.

    이 경우 채택하지 않는다.


        한편 빨간 셀은 오른쪽 상단의 폴리곤에 의해 칠해지는 셀이다. 여기에는 Top, Left, Right 변이 있다.

    오른쪽 변은 채택되지않기때문에 오른쪽 끝이 (4,4)도트가 칠해지지 않았고,  

    왼쪽 변( 대각선을 말함) 은 칠해진다.

     

    이것에 의해 Right-Bottom 폴리곤과의 경계선이 여러번 칠해지는 문제도 해결된다. 

    사각형의 크기도 생각한대로 4X4이다

      

     기본적으로는 이 룰에 따라 칠해지나, 예외도 있다



    ③ Top-Left Filling Convention가 적용되지 않는 경우


     그런데 이 룰이 적용되지 않는 경우가 있다. 예를들면 아래와같은 경우이다:

     

    방금전과 같은 크기의 사각 폴리곤이 조금 왼쪽 상단으로 이동했다.

    이 경우 TLFC 룰(Top-Left Filling Convention)을 적용하면, 오른쪽이 불필요하게 비어있다.

    DirectX는 이럴 경우 TLFC룰을 적용하지 않는다.

    이것을 위에 그림에서 대각선의 크로스한 부분에서 판별한다


     이곳이 픽셀의 경계선에 들어있지 않은 경우등, 특정 조건을 만족할 경우, TLFC룰은 사용되지 않는다

    이렇게 각 규칙에 따라 잘 움직이고 있으며 외관상으로 모순없는 렌더링이 가능한 것이다



    ④ 또 다른 문제「픽셀에서 벗어나는 문제」


     2D의 HUD등을 렌더링할때에는 가능하면 Dot by Dot 형태로 렌더링 하고 싶을 것이다.

    (Dot by Dot:화면의 1도트에 텍스처 1픽셀이 렌더링 된 상태)

    하지만 DirectX에서는 보이지 않는 룰에 의해 의도되지 않게 되는 경우가 있다


        매우 간단한 예로 재현해보자.

    2X2의 텍스처가 있다고 했을대 이것과 같은 크기의 사각 폴리곤도 있다고 하자.

    이것을 아래와 같이 스크린에 렌더링 한다고 하자

     

    이때, 실제 화상은 어떻게 될까? 아마 이렇게 될것이다


     

    뭔가 칙칙해졌다. 이것은 혼색(混色)이 되버렸기 때문이다. 왜 이렇게 된것일까? 

    이것은 텍스처로부터 샘플링 하는 UV가 관계하고있다.


       래스터라이즈가 수행되면, 스크린의 유효 도트에 대해서 UV가 계산된다. 구체적으로는 각 도트의 중심점(오렌지색의 점)에 대응한 값이 보간되어 계산된다. UV를 적어보면 아래와 같이 된다

     


     

    UV에 있는 색은 위의 그림과 같다. 각 UV 샘플링 점이 변 및 교점에 있는 것에 주목하도록.

     

    이 경우 샘플러의 설정에 의한 것도 있지만, 주변의 색 정보를 활용해서 중간색이 나오게 된다.

    그렇기 때문에 결과 화면같이 혼색된 색이 나와버리게 된다


      3D 모델을 렌더링 할때에는 애초에 Dot by Dot 가 되는것은 보통 없기 때문에, 이러한 것에 신경쓸 필요는 거의 없지만, 예를들어 포스트 이펙트를 셰이더에서 만들때 같은 경우에는 이 영향에 직격탄을 맞을 것이다.


      혼색되면 안되는 건 당연하다. 그럼 어떻게 막을까? 위의 그림에 답이 있지만 원래의 폴리곤의 좌표를 Top-Left로 0.5 이동시킨다. 그러면 원래의 색을 칠하고 싶은 위치와 폴리곤이 입혀지는 위치가 외관상 맞아 떨어진다



    이 UV에서 샘플링 하면, 정확히 텍스처의 색이 반영된다.

    원래의 폴리곤 좌표를 ( -0.5, -0.5) 오프셋 처리 하지 않으면 이론상 Dot by Dot가 되지 않는다.

    또한, 이것은 원래 폴리곤 좌표가 정수가 아니면 성립하지 않기 때문에 주의 하도록..



    ⑤ 어디서-0.5를 이동 시킬 것인가?

     

       이론은 알았지만 어디서 -0.5를 이동시키면 될 것인가? 사각 폴리곤을 좌표변환이 끝난 버텍스에서 작성하고있는 사람이라면 직접 버텍스 좌표를 오프셋 처리를 하면 된다.

    그렇지 않고 사각 폴리곤을 좌표변환이 끝난 버텍스를 사용하지 않고 3D 공간상의 폴리곤으로써 취급할 경우, 위치를 이동시킬 기회는 두번이 있는데....

       

        첫번째는 월드 행렬 변환이다. 이곳에 스크린에서 봤을때 (-0.5, -0.5)이동시키는 오프셋을 추가한다. 단 일반적으로 이건 꽤 어렵다.


       또 다른 방법은 셰이더 내에서 처리하는 것이다. 사각형 폴리곤 렌더링용 셰이더가 있다는 전제이지만, WVP행렬을 곱한 후의 버텍스에 대해서 직접 계산을 수행한다



     VS_OUT vs_main( VS_IN In )

    {

        VS_OUT Out = (VS_OUT)0;

        Out.pos = mul( In.pos, WVPMatrix );  // 투영공간으로 이동

        // 스크린 좌표에 대해서(-0.5, -0.5)의 오프셋
        Out.pos /= Out.pos.w;

        // 투영공간의 좌표를 한번 스크린 좌표로 해서、
        // 0.5씩 오프셋 처리를 하고 원래대로 돌아온다
        // 아래와 같이 작성해도 컴파일러가 최적화를 시켜준다
        Out.pos.x = (Out.pos.x * screenW - 0.5f) / screenW;
        Out.pos.y = (Out.pos.y * screenH + 0.5f) / screenH;

        return Out;
    }


    WVPMatrix(월드 X 뷰 X 프로젝션)를 로컬 좌표로 곱한 후에 각 성분을 w성분으로 나누면 

    버텍스 좌표는 (-1, -1, 0) ~ (1,1,1)이라는 작은 영역으로 제한된다. 

    이것이 늘어나 스크린좌표가 되는 것이다. 


    지금은 스크린 좌표 베이스에서 0.5 오프셋을 넣는것이기에 한번 스크린 의 폭과 높이를 좌표에 곱해 스크린 좌표로 변환해서 0.5 오프셋을 넣고 다시 스크린의 폭과 높이로 나누어 작은 영역으로 되돌린다. 


    y 성분은 스크린의 축과 투영공간의 축의 방향이 반대이기 때문에 덧셈을 하는것에 주의 한다



      Dot By Dot 표시는 2D 시대에는 당연한(애초에 그것밖에 없음)것 이었지만 3D가 베이스가 되는 DirectX에 있어서는 의외로 어려운 것이다. 하지만 래스터라이제이션 룰과 버텍스 보간의 내부를 역수로 취하면 가능 할 것이다


    MSDN에서 설명하는 래스터라이즈 규칙

    반응형

    '그래픽스(Graphics) > DirectX9~12' 카테고리의 다른 글

    밉맵 디테일 높이기  (0) 2013.06.10
    Early Z  (0) 2013.06.08
    x파일에 대한 pdf  (0) 2013.03.11
    NormalMapGenerator  (0) 2013.02.23
    x파일 뷰어  (0) 2013.02.17
    반응형

    http://goo.gl/3eW9r


    Alpha test is perhaps the simplest Direct3D 9 functionality to emulate. It does not require the user to set a alpha blend state. Instead the user can simply choose to discard a pixel based upon its alpha value. The following pixel shader does not draw the pixel if the alpha value is less than 0.5. 

    // 
    // PS for rendering with alpha test 
    // 
    float4 PSAlphaTestmain(PSSceneIn input) : COLOR0 
    {
    float4 color = tex2D( g_samLinear, g_txDiffuse, input.tex ) * input.colorD; 
    if( color.a < 0.5 ) 
    discard; 
    return color; 


    반응형
    반응형

    BLOG main image



    셰이더를 직접 작성할때는 아래 옵션을 셰이더 코드안에서 enable해주고


    .a   알파값을 1에서 0 으로 가게 하면 서서히 반투명처리가 된다




    _pD3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE ); //반투명 on

    _pD3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA ); //(1-a)*바닥색

    _pD3dDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA ); //a*덮일 색

    반응형
    반응형

    http://goo.gl/ZngnS


    x파일에 대한 문서.pdf


    반응형

    + Recent posts