For me
[DirectX12] 12) Light - 2 본문
Dir
viewLightDir = 처음에 세팅한 Direction에 View 행렬을 곱한후 단위벡터로 전환
diffuseRatio ( viewLightDir의 반대방향 과, view단위벡터 의 내적 )
Point
Dir과 다르게 Position, Distance 이 추가됨.
viewLightDir = 포지션 뷰에서 빛 포지션 뷰를 뺀 값 의 단위벡터
viewLightPos = 빛의 위치와 View 행렬을 곱한 값
Distance = 포지션뷰와 빛포지션 뷰의 거리
=> distanceRatio = 1 - (Distance / 최대거리)의 제곱
멀어지면 멀어질수록 어두워 지기 위해 위와같이 구현
Spot
Point의 viewLightPos 값을 구하는 과정까지 같은 과정
halfAngle = 최대각도 / 2
viewLightVec = viewPos - viewLightPos
가장 중앙으로 나아가는 빛의 방향(viewCenterLightDir) = DirLight의 viewLightDir과 같음
중앙으로 뻗어나갔을때 가장 먼 거리(centerDist) = viewLightVec과 viewCenterLightDir의 내적
distanceRatio = (1-centerDist / 최대거리)
시야각(lightAngle) = (viewLightVec의 단위벡터 와 viewCenterLightDir의 내적) 의 아크코사인
이후, 최대 거리를 벗어났는지, 최대 시야각을 벗어났는지에 대해서 체크하고 이후 거리에 따라 적절히 세기를 조절
reflectionDir = viewLightDir + 2*(-viewLightDir 과 노말벡터 내적한값) * 뷰의 노말벡터
eyeDir = Position View의 단위벡터
specularRatio = (-eyeDir 과 reflectionDir의 내적) 의 제곱
diffuse = diffuse * diffuseRatio * distanceRatio
ambient = ambient * distanceRatio
specular = specular * specularRatio * distanceRatio
Lighting Shader
Dir , Point Light 구현
물체의 diffuse, ambient, specular + 빛의 diffuse, ambient, specular 성분을 더함
#ifndef _LIGHTING_FX_
#define _LIGHTING_FX_
#include "params.fx"
#include "utils.fx"
struct VS_IN
{
float3 pos : POSITION;
float2 uv : TEXCOORD;
};
struct VS_OUT
{
float4 pos : SV_Position;
float2 uv : TEXCOORD;
};
struct PS_OUT
{
float4 diffuse : SV_Target0;
float4 specular : SV_Target1;
};
// [Directional Light]
// g_int_0 : Light index
// g_tex_0 : Position RT
// g_tex_1 : Normal RT
// Mesh : Rectangle
VS_OUT VS_DirLight(VS_IN input)
{
VS_OUT output = (VS_OUT)0;
output.pos = float4(input.pos * 2.f, 1.f);
output.uv = input.uv;
return output;
}
PS_OUT PS_DirLight(VS_OUT input)
{
PS_OUT output = (PS_OUT)0;
float3 viewPos = g_tex_0.Sample(g_sam_0, input.uv).xyz;
if (viewPos.z <= 0.f)
clip(-1);
float3 viewNormal = g_tex_1.Sample(g_sam_0, input.uv).xyz;
LightColor color = CalculateLightColor(g_int_0, viewNormal, viewPos);
output.diffuse = color.diffuse + color.ambient;
output.specular = color.specular;
return output;
}
// [Point Light]
// g_int_0 : Light index
// g_tex_0 : Position RT
// g_tex_1 : Normal RT
// g_vec2_0 : RenderTarget Resolution
// Mesh : Sphere
VS_OUT VS_PointLight(VS_IN input)
{
VS_OUT output = (VS_OUT)0;
output.pos = mul(float4(input.pos, 1.f), g_matWVP);
output.uv = input.uv;
return output;
}
PS_OUT PS_PointLight(VS_OUT input)
{
PS_OUT output = (PS_OUT)0;
// input.pos = SV_Position = Screen 좌표
float2 uv = float2(input.pos.x / g_vec2_0.x, input.pos.y / g_vec2_0.y);
float3 viewPos = g_tex_0.Sample(g_sam_0, uv).xyz;
if (viewPos.z <= 0.f)
clip(-1);
int lightIndex = g_int_0;
float3 viewLightPos = mul(float4(g_light[lightIndex].position.xyz, 1.f), g_matView).xyz;
float distance = length(viewPos - viewLightPos);
if (distance > g_light[lightIndex].range)
clip(-1);
float3 viewNormal = g_tex_1.Sample(g_sam_0, uv).xyz;
LightColor color = CalculateLightColor(g_int_0, viewNormal, viewPos);
output.diffuse = color.diffuse + color.ambient;
output.specular = color.specular;
return output;
}
// [Final]
// g_tex_0 : Diffuse Color Target
// g_tex_1 : Diffuse Light Target
// g_tex_2 : Specular Light Target
// Mesh : Rectangle
VS_OUT VS_Final(VS_IN input)
{
VS_OUT output = (VS_OUT)0;
output.pos = float4(input.pos * 2.f, 1.f);
output.uv = input.uv;
return output;
}
float4 PS_Final(VS_OUT input) : SV_Target
{
float4 output = (float4)0;
float4 lightPower = g_tex_1.Sample(g_sam_0, input.uv);
if (lightPower.x == 0.f && lightPower.y == 0.f && lightPower.z == 0.f)
clip(-1);
float4 color = g_tex_0.Sample(g_sam_0, input.uv);
float4 specular = g_tex_2.Sample(g_sam_0, input.uv);
output = (color * lightPower) + specular;
return output;
}
#endif
Light.h
#pragma once
#include "Component.h"
enum class LIGHT_TYPE : uint8
{
DIRECTIONAL_LIGHT,
POINT_LIGHT,
SPOT_LIGHT,
};
struct LightColor
{
Vec4 diffuse;
Vec4 ambient;
Vec4 specular;
};
struct LightInfo
{
LightColor color;
Vec4 position;
Vec4 direction;
int32 lightType;
float range;
float angle;
int32 padding;
};
struct LightParams
{
uint32 lightCount;
Vec3 padding;
LightInfo lights[50];
};
class Light : public Component
{
public:
Light();
virtual ~Light();
virtual void FinalUpdate() override;
void Render();
void RenderShadow();
public:
LIGHT_TYPE GetLightType() { return static_cast<LIGHT_TYPE>(_lightInfo.lightType); }
const LightInfo& GetLightInfo() { return _lightInfo; }
void SetLightDirection(Vec3 direction);
void SetDiffuse(const Vec3& diffuse) { _lightInfo.color.diffuse = diffuse; }
void SetAmbient(const Vec3& ambient) { _lightInfo.color.ambient = ambient; }
void SetSpecular(const Vec3& specular) { _lightInfo.color.specular = specular; }
void SetLightType(LIGHT_TYPE type);
void SetLightRange(float range) { _lightInfo.range = range; }
void SetLightAngle(float angle) { _lightInfo.angle = angle; }
void SetLightIndex(int8 index) { _lightIndex = index; }
private:
LightInfo _lightInfo = {};
int8 _lightIndex = -1;
shared_ptr<class Mesh> _volumeMesh;
shared_ptr<class Material> _lightMaterial;
shared_ptr<GameObject> _shadowCamera;
};
Light.cpp
#include "pch.h"
#include "pch.h"
#include "Light.h"
#include "Transform.h"
#include "Engine.h"
#include "Resources.h"
#include "Camera.h"
#include "Transform.h"
#include "Texture.h"
#include "SceneManager.h"
Light::Light() : Component(COMPONENT_TYPE::LIGHT)
{
uint8 layerIndex = GET_SINGLE(SceneManager)->LayerNameToIndex(L"UI");
}
Light::~Light()
{
}
void Light::FinalUpdate()
{
_lightInfo.position = GetTransform()->GetWorldPosition();
}
void Light::Render()
{
assert(_lightIndex >= 0);
GetTransform()->PushData();
float scale = 2 * _lightInfo.range;
GetTransform()->SetLocalScale(Vec3(scale, scale, scale));
_lightMaterial->SetInt(0, _lightIndex);
_lightMaterial->PushGraphicsData();
_volumeMesh->Render();
}
void Light::SetLightDirection(Vec3 direction)
{
direction.Normalize();
_lightInfo.direction = direction;
GetTransform()->LookAt(direction);
}
void Light::SetLightType(LIGHT_TYPE type)
{
_lightInfo.lightType = static_cast<int32>(type);
switch (type)
{
case LIGHT_TYPE::DIRECTIONAL_LIGHT:
_volumeMesh = GET_SINGLE(Resources)->Get<Mesh>(L"Rectangle");
_lightMaterial = GET_SINGLE(Resources)->Get<Material>(L"DirLight");
break;
case LIGHT_TYPE::POINT_LIGHT:
_volumeMesh = GET_SINGLE(Resources)->Get<Mesh>(L"Sphere");
_lightMaterial = GET_SINGLE(Resources)->Get<Material>(L"PointLight");
break;
case LIGHT_TYPE::SPOT_LIGHT:
_volumeMesh = GET_SINGLE(Resources)->Get<Mesh>(L"Sphere");
_lightMaterial = GET_SINGLE(Resources)->Get<Material>(L"PointLight");
break;
}
}
아래와 같이 불러낼 수 있다 (Dir Direction)
{
shared_ptr<GameObject> light = make_shared<GameObject>();
light->AddComponent(make_shared<Transform>());
light->AddComponent(make_shared<Light>());
light->GetLight()->SetLightDirection(Vec3(1.f, 0.f, 1.f));
light->GetLight()->SetLightType(LIGHT_TYPE::DIRECTIONAL_LIGHT);
light->GetLight()->SetDiffuse(Vec3(0.5f, 0.5f, 0.5f));
light->GetLight()->SetAmbient(Vec3(0.1f, 0.1f, 0.1f));
light->GetLight()->SetSpecular(Vec3(0.3f, 0.3f, 0.3f));
scene->AddGameObject(light);
}
'DirectX12' 카테고리의 다른 글
[DirectX12] 14) Normal Mapping (0) | 2023.01.18 |
---|---|
[DirectX12] 13) Shadow (0) | 2023.01.17 |
[DirectX12] 11) Light - 1 (이론) (1) | 2023.01.17 |
[DirectX12] 10) Camera (0) | 2023.01.17 |
[DirectX12] 9) Scene (0) | 2023.01.16 |