다수의 Instance를 1번의 DP call(Draw Primitive Call)을 통해 1개의 Object를 이용해서 한번에 그리는 것
FPS 최적화
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 40, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "mTransform", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 1, 0, D3D11_INPUT_PER_INSTANCE_DATA, 1 },
{ "mTransform", 1, DXGI_FORMAT_R32G32B32A32_FLOAT, 1, 16, D3D11_INPUT_PER_INSTANCE_DATA, 1 },
{ "mTransform", 2, DXGI_FORMAT_R32G32B32A32_FLOAT, 1, 32, D3D11_INPUT_PER_INSTANCE_DATA, 1 },
{ "mTransform", 3, DXGI_FORMAT_R32G32B32A32_FLOAT, 1, 48, D3D11_INPUT_PER_INSTANCE_DATA, 1 },
{ "POSCOLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 1, 64, D3D11_INPUT_PER_INSTANCE_DATA, 1 },
};
Instance로 넘어가는 Data는 D3D11_INPUT_PER_INSTANCE_DATA 속성으로 설정
InstanceDataStepRate는 해당 Instance를 몇 번 그릴 것인가
pContext->DrawIndexedInstanced(m_dxobj.m_iNumIndex, m_ParticleList.size(), 0, 0, 0);
Draw Call 시 Instance의 개수를 추가로 넘기면 됨
struct VS_INPUT
{
float3 p : POSITION;
float4 c : COLOR;
float2 t : TEXCOORD;
row_major matrix mTransform : mTransform;
float4 pc : POSCOLOR;
uint InstanceId : SV_InstanceID;
};
이 때, GPU에서는 SV_InstanceID라는 값을 Instance마다 제공
만약 상수버퍼에 SRT에 대한 Matrix를 저장했다면 SV_InstnaceID를 통해 접근 가능
Instancing을 통해 다수의 Instance를 그리는 것과 Constant Buffer에 다수의 Instance의 SRT정보를 넘겨서 그리는 것은 차이가 있음
Constant Buffer에 Instance의 SRT정보를 저장해서 Draw를 한다고 해도 Vertex들이 Topology Primitive로 연결될 때 서로 다른 Instace들이 묶이므로 Instance 단위로 그릴 수 없을 것임
Point Particle과 Geometry Shader를 이용할 경우 Stream-Output Stage를 통해 Buffer에 동적으로 Particle을 추가함으로써 폭죽과 같은 효과를 낼 수 있음
void GSLauncherHandler( VSParticleIn input, inout PointStream<VSParticleIn> ParticleOutputStream )
{
if(input.fTimer <= 0)
{
float3 vRandom = normalize( RandomDir( input.Type ) );
//time to emit a new SHELL
VSParticleIn output;
output.vPos = input.vPos + input.vVel*g_fElapsedTime;
output.vVel = input.vVel + vRandom*8.0;
output.fTimer = P_SHELLLIFE + vRandom.y*0.5;
output.Type = PT_SHELL;
ParticleOutputStream.Append( output );
//reset our timer
input.fTimer = g_fSecondsPerFirework + vRandom.x*0.4;
}
else
{
input.fTimer -= g_fElapsedTime;
}
//emit ourselves to keep us alive
ParticleOutputStream.Append( input );
}
void GSShellHandler( VSParticleIn input, inout PointStream<VSParticleIn> ParticleOutputStream )
{
if(input.fTimer <= 0)
{
VSParticleIn output;
float3 vRandom = float3(0,0,0);
//time to emit a series of new Ember1s
for(int i=0; i< g_fNumEmber1s; i++)
{
vRandom = normalize( RandomDir( input.Type + i ) );
output.vPos = input.vPos + input.vVel*g_fElapsedTime;
output.vVel = input.vVel + vRandom*15.0;
output.fTimer = P_EMBER1LIFE;
output.Type = PT_EMBER1;
ParticleOutputStream.Append( output );
}
//find out how many Ember2s to emit
for(i=0; i<abs(vRandom.x)*g_fMaxEmber2s; i++)
{
vRandom = normalize( RandomDir( input.Type + i ) );
output.vPos = input.vPos + input.vVel*g_fElapsedTime;
output.vVel = input.vVel + vRandom*15.0;
output.fTimer = P_EMBER2LIFE + 0.4*vRandom.x;
output.Type = PT_EMBER2;
ParticleOutputStream.Append( output );
}
}
else
{
GSGenericHandler( input, ParticleOutputStream );
}
}
이 때, 재미있는건 위 함수는 마지막에 무조건 OutputStream.Append()를 수행하지만 아래 함수에서는 시간이 다 경과된다면 수행하지 않는 것을 볼 수 있는데 이를 통해 동적으로 Point Particle의 생성-삭제를 수행할 수 있음
Shader는 기본적으로 Random함수를 지원하지 않음
Texture1D g_txRandom : register(t1);// 텍스처 저장 레지스터(1번)
float3 RandomDir(float fOffset)
{
float tCoord = (g_fGlobalTime + fOffset) / 300.0;
float4 vColor = g_txRandom.SampleLevel( g_samPoint, tCoord, 0 );
return vColor.xyz;
}
대신 Texture에 미리 Random Value를 저장해놓은 후 time값을 이용해 가져오는 방법도 존재
조명은 크게 지역조명-전역조명, 직접조명-간접조명으로 분류
Graphics에서는 직접조명-간접조명을 주로 다룸
전역 조명 : Radiosity, Ray Trancing, Precomputed Radiance Transfer, Poton Mapping, Caustics 등 존재
태양광, 방향 존재, 위치 존재 하지 않음
전구, 방향 존재하지 않음(사방으로 퍼짐), 위치 존재
손전등, 방향 존재, 위치 존재
광원에서 출발한 빛이 다른 Object에 반사되어 자신 Object에게 들어오게 된 조명
: Material의 color. 즉 Object가 표현할 수 있는 색의 범위. 일반적으로는 그냥 흰색 사용
: Light의 Color.
: 1개 이상의 광원들에 대한 연산의 합
: 램버트 조명 공식
Final Color = Texture Color Material Color Light Color
명도 : 0~1사이의 흑백 표현
채도 : 색상
반사 재질의 Object에 사용
거울에 반사된 빛을 바라본다면 빛의 영향을 받겠지만, 거울과 무관한 방향을 바라본다면 빛의 영향을 받지 않는다
광원의 방향, Vertex Normal, 시선의 방향을 모두 계산하기보다는 간단하게 광원과 Vertex, 시선과 Vertex 두 Vector의 평균을 Normal과 내적하여 계산량을 줄이는 방법
: 모든 Specular 조명의 합
: 반사지수. 0~1사이 값으로 최대 조명치의 값은 건들지 않지만 만약 최대 조명보다 약한 조명이라면 n = 1보다 더 낮은 값을 반환하므로 조명이 급격하게 어두워지는 연산을 내며, 이를 통해 HighLight 효과를 낼 수 있음
Shader에서는 reflect(a, b)라는 함수 지원
x < min이면 0, x > max 이면 1, 그 사이면 0~1사이의 값을 반환하는 Shader 함수
거리에 따른 빛의 감쇠, Spot Light의 각도 등에서 사용 가능
Fresnel, Geometry Attenuation, Roughness를 이용한 계산 식. 대표적인 반사 공식
물의 반사 계수를 계산하는 공식
호수는 보는 각도에 따라 멀리서보면 하늘이, 가까이에서 보면 물 속이 보이게 된다
Unblocking, Masking, Shadowing 등 기하적인 요인으로 인해 빛의 세기가 달라지는 현상
피사체의 뒤에서 강한 조명을 주어 피사체의 경계를 뚜렷하게 보여주는 것
빨간 배경에 붉은 피사체를 둘 경우 Rim Light가 없다면 그 경계가 잘 구분가지 않을 것이다