float4 PS_Main(VS_OUT input) : SV_Target
{
//float4 color = g_tex_0.Sample(g_sam_0, input.uv);
// 색상을 초기화
// 흰색으로 초기화 한 이유는 빛을 잘 받는지 확인하기 위함.
float4 color = float4(1.f, 1.f, 1.f, 1.f);
LightColor totalColor = (LightColor)0.f;
for (int i = 0; i < g_lightCount; ++i)
{
// CalculateLightColor(빛 정보 연산)는 아래에 있음 참고
LightColor color = CalculateLightColor(i, input.viewNormal, input.viewPos);
totalColor.diffuse += color.diffuse;
totalColor.ambient += color.ambient;
totalColor.specular += color.specular;
}
// diffuse, ambient는 자신의 색상 (color.xyz)에 영향을 미치는(곱해지는) 방식이고
// specular는 전반적으로 더해지는 형식
color.xyz = (totalColor.diffuse.xyz * color.xyz)
+ totalColor.ambient.xyz * color.xyz
+ totalColor.specular.xyz;
return color;
}
이제 CalculateLightColor
빛을 계산하는 방법
#ifndef _UTILS_HLSLI_
#define _UTILS_HLSLI_
LightColor CalculateLightColor(int lightIndex, float3 viewNormal, float3 viewPos)
{
LightColor color = (LightColor)0.f;
float3 viewLightDir = (float3)0.f;
float diffuseRatio = 0.f;
float specularRatio = 0.f;
float distanceRatio = 1.f;
// lightType이 Directional Light일경우
if (g_light[lightIndex].lightType == 0)
{
viewLightDir = normalize(mul(float4(g_light[lightIndex].direction.xyz, 0.f), g_matView).xyz);
// mul(float4(g_light[lightIndex].direction.xyz, 0.f), g_matView) : world -> view로 좌표계 변환
// normalize : normal vector로 단위벡터 변경
diffuseRatio = saturate(dot(-viewLightDir, viewNormal));
// dot(-viewLightDir, viewNormal) : 내적 후
// saturate : 0 ~ 1 사이 값으로 변경
}
// lightType이 Point Light일경우
else if (g_light[lightIndex].lightType == 1)
{
float3 viewLightPos = mul(float4(g_light[lightIndex].position.xyz, 1.f), g_matView).xyz;
viewLightDir = normalize(viewPos - viewLightPos);
diffuseRatio = saturate(dot(-viewLightDir, viewNormal));
// 거리값에 대해 빛의 세기 반영
float dist = distance(viewPos, viewLightPos);
if (g_light[lightIndex].range == 0.f)
distanceRatio = 0.f;
else
distanceRatio = saturate(1.f - pow(dist / g_light[lightIndex].range, 2));
}
// lightType이 Spot Light일경우
else
{
// Spot Light
float3 viewLightPos = mul(float4(g_light[lightIndex].position.xyz, 1.f), g_matView).xyz;
viewLightDir = normalize(viewPos - viewLightPos);
diffuseRatio = saturate(dot(-viewLightDir, viewNormal));
if (g_light[lightIndex].range == 0.f)
distanceRatio = 0.f;
else
{
float halfAngle = g_light[lightIndex].angle / 2;
float3 viewLightVec = viewPos - viewLightPos;
float3 viewCenterLightDir = normalize(mul(float4(g_light[lightIndex].direction.xyz, 0.f), g_matView).xyz);
float centerDist = dot(viewLightVec, viewCenterLightDir);
distanceRatio = saturate(1.f - centerDist / g_light[lightIndex].range);
float lightAngle = acos(dot(normalize(viewLightVec), viewCenterLightDir));
if (centerDist < 0.f || centerDist > g_light[lightIndex].range) // 최대 거리를 벗어났는지
distanceRatio = 0.f;
else if (lightAngle > halfAngle) // 최대 시야각을 벗어났는지
distanceRatio = 0.f;
else // 거리에 따라 적절히 세기를 조절
distanceRatio = saturate(1.f - pow(centerDist / g_light[lightIndex].range, 2));
}
}
// specular 계산
float3 reflectionDir = normalize(viewLightDir + 2 * (saturate(dot(-viewLightDir, viewNormal)) * viewNormal));
float3 eyeDir = normalize(viewPos);
specularRatio = saturate(dot(-eyeDir, reflectionDir));
specularRatio = pow(specularRatio, 2); // 좀 더 극적인 효과를 위해서 pow를 넣음.
// pow값을 변경해 가면서 변화를 확인해 보자.
color.diffuse = g_light[lightIndex].color.diffuse * diffuseRatio * distanceRatio;
color.ambient = g_light[lightIndex].color.ambient * distanceRatio;
color.specular = g_light[lightIndex].color.specular * specularRatio * distanceRatio;
return color;
}
#endif
shared_ptr<Scene> SceneManager::LoadTestScene()
{
// ...
#pragma region Green Directional Light
{
shared_ptr<GameObject> light = make_shared<GameObject>();
light->AddComponent(make_shared<Transform>());
//light->GetTransform()->SetLocalPosition(Vec3(0.f, 150.f, 150.f));
light->AddComponent(make_shared<Light>());
light->GetLight()->SetLightDirection(Vec3(0.f, -1.f, 0.f));
light->GetLight()->SetLightType(LIGHT_TYPE::DIRECTIONAL_LIGHT);
light->GetLight()->SetDiffuse(Vec3(0.1f, 1.f, 0.1f));
light->GetLight()->SetAmbient(Vec3(0.f, 0.1f, 0.f));
light->GetLight()->SetSpecular(Vec3(0.1f, 0.1f, 0.1f));
scene->AddGameObject(light);
}
#pragma endregion
#pragma region Red Point Light
{
shared_ptr<GameObject> light = make_shared<GameObject>();
light->AddComponent(make_shared<Transform>());
light->GetTransform()->SetLocalPosition(Vec3(150.f, 150.f, 150.f));
light->AddComponent(make_shared<Light>());
//light->GetLight()->SetLightDirection(Vec3(0.f, -1.f, 0.f));
light->GetLight()->SetLightType(LIGHT_TYPE::POINT_LIGHT);
light->GetLight()->SetDiffuse(Vec3(1.f, 0.1f, 0.1f));
light->GetLight()->SetAmbient(Vec3(0.1f, 0.f, 0.f));
light->GetLight()->SetSpecular(Vec3(0.1f, 0.1f, 0.1f));
light->GetLight()->SetLightRange(10000.f);
//light->GetLight()->SetLightAngle(XM_PI / 4);
scene->AddGameObject(light);
}
#pragma endregion
#pragma region Blue Spot Light
{
shared_ptr<GameObject> light = make_shared<GameObject>();
light->AddComponent(make_shared<Transform>());
light->GetTransform()->SetLocalPosition(Vec3(-150.f, 0.f, 150.f));
light->AddComponent(make_shared<Light>());
light->GetLight()->SetLightDirection(Vec3(1.f, 0.f, 0.f));
light->GetLight()->SetLightType(LIGHT_TYPE::SPOT_LIGHT);
light->GetLight()->SetDiffuse(Vec3(0.f, 0.1f, 1.f));
//light->GetLight()->SetAmbient(Vec3(0.f, 0.f, 0.1f));
light->GetLight()->SetSpecular(Vec3(0.1f, 0.1f, 0.1f));
light->GetLight()->SetLightRange(10000.f);
light->GetLight()->SetLightAngle(XM_PI / 4);
scene->AddGameObject(light);
}
#pragma endregion
// ...