서의 공간
[T24.1] Lighting 본문
공통 개념
1. MakeIndependent() 함수는 각 정점을 면에 독립적으로 정의한다. 같은 위치에 있는 정점이라도, 면에 따라 중복해서 정점을 정의하여, 정점의 노멀이 면에 맞추어 결정되도록 한다. 그러니까, 0번 점과 4번 점이 동일 위치에 있지만 각 점들이 이루고 있는 면이 다른 면이라면 노멀도 달라야 한다는 의미다. 노멀을 달리하려면 이렇게 같은 위치에 대해 여러 정점을 정의해야 한다.
2. 빛을 표현하기 위해서, 광원(빛의 여러 속성의 색상)과 오브젝트(예: Box) 사이의 거리를 통해 오브젝트의 반사된 빛의 색상을 계산한다. 색상을 계산할 때, 빛에 비치는 면과 안 비치는 면을 구분하기 위해 노멀 벡터를 사용한다.
구체적으로 다음은 광원 오브젝트가 갖는 속성이다.
- 광원의 위치정보
- 주변광 색상
- 분산광 색상
- 분산광 세기
- 감쇠 매개변수들(상수항 계수, 1차항 계수, 2차항 계수 총 3개)
다음은 Box가 갖는 속성이다.
- 머티리얼 색상
- 반영광 세기
- 반영 지수(shininess를 조절한다)
3. 그래픽 파이프라인 디버깅에 대해서도 알아 볼 것.
IndexedTriangleList.h
더보기
#pragma once
#include <vector>
#include <DirectXMath.h>
template<class T>
class IndexedTriangleList
{
public:
IndexedTriangleList() = default;
IndexedTriangleList(std::vector<T> verts_in, std::vector<unsigned short> indices_in)
:
vertices(std::move(verts_in)),
indices(std::move(indices_in))
{
assert(vertices.size() > 2);
assert(indices.size() % 3 == 0);
}
void Transform(DirectX::FXMMATRIX matrix)
{
for (auto& v : vertices)
{
const DirectX::XMVECTOR pos = DirectX::XMLoadFloat3(&v.pos);
DirectX::XMStoreFloat3(
&v.pos,
DirectX::XMVector3Transform(pos, matrix)
);
}
}
// asserts face-independent vertices w/ normals cleared to zero
void SetNormalsIndependentFlat() noexcept(!IS_DEBUG)
{
using namespace DirectX;
assert(indices.size() % 3 == 0 && indices.size() > 0);
for (size_t i = 0; i < indices.size(); i += 3)
{
auto& v0 = vertices[indices[i]];
auto& v1 = vertices[indices[i + 1]];
auto& v2 = vertices[indices[i + 2]];
const auto p0 = XMLoadFloat3(&v0.pos);
const auto p1 = XMLoadFloat3(&v1.pos);
const auto p2 = XMLoadFloat3(&v2.pos);
const auto n = XMVector3Normalize(XMVector3Cross((p1 - p0), (p2 - p0)));
XMStoreFloat3(&v0.n, n);
XMStoreFloat3(&v1.n, n);
XMStoreFloat3(&v2.n, n);
}
}
public:
std::vector<T> vertices;
std::vector<unsigned short> indices;
};
Box.cpp
더보기
Box::Box(Graphics& gfx,
std::mt19937& rng,
std::uniform_real_distribution<float>& adist,
std::uniform_real_distribution<float>& ddist,
std::uniform_real_distribution<float>& odist,
std::uniform_real_distribution<float>& rdist,
std::uniform_real_distribution<float>& bdist)
:
r(rdist(rng)),
droll(ddist(rng)),
dpitch(ddist(rng)),
dyaw(ddist(rng)),
dphi(odist(rng)),
dtheta(odist(rng)),
dchi(odist(rng)),
chi(adist(rng)),
theta(adist(rng)),
phi(adist(rng))
{
namespace dx = DirectX;
if (!IsStaticInitialized())
{
struct Vertex
{
dx::XMFLOAT3 pos;
dx::XMFLOAT3 n;
};
auto model = Cube::MakeIndependent<Vertex>();
model.SetNormalsIndependentFlat();
AddStaticBind(std::make_unique<VertexBuffer>(gfx, model.vertices));
auto pvs = std::make_unique<VertexShader>(gfx, L"PhongVS.cso");
auto pvsbc = pvs->GetBytecode();
AddStaticBind(std::move(pvs));
AddStaticBind(std::make_unique<PixelShader>(gfx, L"PhongPS.cso"));
AddStaticIndexBuffer(std::make_unique<IndexBuffer>(gfx, model.indices));
const std::vector<D3D11_INPUT_ELEMENT_DESC> ied =
{
{ "Position",0,DXGI_FORMAT_R32G32B32_FLOAT,0,0,D3D11_INPUT_PER_VERTEX_DATA,0 },
{ "Normal",0,DXGI_FORMAT_R32G32B32_FLOAT,0,12,D3D11_INPUT_PER_VERTEX_DATA,0 },
};
AddStaticBind(std::make_unique<InputLayout>(gfx, ied, pvsbc));
AddStaticBind(std::make_unique<Topology>(gfx, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST));
}
else
{
SetIndexFromStatic();
}
AddBind(std::make_unique<TransformCbuf>(gfx, *this));
// model deformation transform (per instance, not stored as bind)
dx::XMStoreFloat3x3(
&mt,
dx::XMMatrixScaling(1.0f, 1.0f, bdist(rng))
);
}
PointLight
더보기
PointLight.h
#pragma once
#include "Graphics.h"
#include "SolidSphere.h"
#include "ConstantBuffers.h"
class PointLight
{
public:
PointLight(Graphics& gfx, float radius = 0.5f);
void SpawnControlWindow() noexcept;
void Reset() noexcept;
void Draw(Graphics& gfx) const noexcept(!IS_DEBUG);
void Bind(Graphics& gfx) const noexcept;
private:
struct PointLightCBuf
{
DirectX::XMFLOAT3 pos;
float padding;
};
private:
DirectX::XMFLOAT3 pos = { 0.0f, 0.0f, 0.0f };
mutable SolidSphere mesh;
mutable PixelConstantBuffer<PointLightCBuf> cbuf;
};
PointLight.cpp
#include "PointLight.h"
#include "Imgui/imgui.h"
PointLight::PointLight(Graphics & gfx, float radius)
:
mesh(gfx, radius),
cbuf(gfx)
{}
void PointLight::SpawnControlWindow() noexcept
{
if (ImGui::Begin("Light"))
{
ImGui::Text("Position");
ImGui::SliderFloat("X", &pos.x, -60.0f, 60.0f, "%.1f");
ImGui::SliderFloat("Y", &pos.y, -60.0f, 60.0f, "%.1f");
ImGui::SliderFloat("Z", &pos.z, -60.0f, 60.0f, "%.1f");
if (ImGui::Button("Reset"))
{
Reset();
}
}
ImGui::End();
}
void PointLight::Reset() noexcept
{
pos = { 0.0f, 0.0f, 0.0f };
}
void PointLight::Draw(Graphics & gfx) const noexcept(!IS_DEBUG)
{
mesh.SetPos(pos);
mesh.Draw(gfx);
}
void PointLight::Bind(Graphics & gfx) const noexcept
{
cbuf.Update(gfx, PointLightCBuf{ pos });
cbuf.Bind(gfx);
}
TransformCbuf
더보기
TransformCbuf.h
#pragma once
#include "ConstantBuffers.h"
#include "Drawable.h"
#include <DirectXMath.h>
class TransformCbuf : public Bindable
{
private:
struct Transforms
{
DirectX::XMMATRIX modelViewProj;
DirectX::XMMATRIX model;
};
public:
TransformCbuf(Graphics& gfx, const Drawable& parent);
void Bind(Graphics& gfx) noexcept override;
private:
static std::unique_ptr<VertexConstantBuffer<Transforms>> pVcbuf;
const Drawable& parent;
};
TransformCbuf.cpp
#include "TransformCbuf.h"
TransformCbuf::TransformCbuf(Graphics& gfx, const Drawable& parent)
:
parent(parent)
{
if (!pVcbuf)
{
pVcbuf = std::make_unique<VertexConstantBuffer<Transforms>>(gfx);
}
}
void TransformCbuf::Bind(Graphics& gfx) noexcept
{
const auto model = parent.GetTransformXM();
const Transforms tf =
{
DirectX::XMMatrixTranspose(model),
DirectX::XMMatrixTranspose(
model *
gfx.GetCamera() *
gfx.GetProjection()
)
};
pVcbuf->Update(gfx, tf);
pVcbuf->Bind(gfx);
}
std::unique_ptr<VertexConstantBuffer<TransformCbuf::Transforms>> TransformCbuf::pVcbuf;
Shader
더보기
PhongVS.hlsl
cbuffer CBuf
{
matrix model;
matrix modelViewProj;
};
struct VSOut
{
float3 worldPos : Position;
float3 normal : Normal;
float4 pos : SV_Position;
};
VSOut main(float3 pos : Position, float3 n : Normal)
{
VSOut vso;
vso.worldPos = (float3)mul(float4(pos, 1.0f), model);
vso.normal = mul(n, (float3x3)model);
vso.pos = mul(float4(pos, 1.0f), modelViewProj);
return vso;
}
PhongPS.hlsl
cbuffer LightCBuf
{
float3 lightPos;
};
static const float3 materialColor = { 0.7f, 0.7f, 0.9f };
static const float3 ambient = { 0.05f, 0.05f, 0.05f };
static const float3 diffuseColor = { 1.0f, 1.0f, 1.0f };
static const float diffuseIntensity = 1.0f;
static const float attConst = 1.0f;
static const float attLin = 0.045f;
static const float attQuad = 0.0075f;
float4 main(float3 worldPos : Position, float3 n : Normal) : SV_Target
{
// fragment to light vector data
// vToL은 빛 벡터
const float3 vToL = lightPos - worldPos;
// 빛 벡터의 길이
const float distToL = length(vToL);
// 빛 벡터의 단위벡터(빛 벡터의 방향)
const float3 dirToL = vToL / distToL;
// diffuse attenuation
// 분산광의 감쇠 매개변수, 빛이 거리의 역에 따라 감쇠하도록 만든다.
// attConst 상수항 계수, attLin 일차항 계수, attQuad 이차항 계수
// 실제 물리 법칙에서 빛은 거리의 제곱의 역에 따라 감쇠한다.
// 즉, attQuad = 1 이고, 다른 값은 0으로 두면 된다.
// 하지만 항상 눈으로 보기에 좋은 결과를 내지는 않는다.
const float att = 1.0f / (attConst + attLin * distToL + attQuad * (distToL * distToL));
// diffuse intensity
const float3 diffuse = diffuseColor * diffuseIntensity * att * max(0.0f, dot(dirToL, n));
// final color
return float4(saturate(diffuse + ambient), 1.0f);
}
'Graphics API > DirectX 11 - Chili' 카테고리의 다른 글
[T25] Assimp 라이브러리 (0) | 2020.12.05 |
---|---|
[T24.2] Lighting (0) | 2020.12.05 |
[T24.0] Lighting (0) | 2020.12.05 |
[T21.3] Box, Hill, Sphere, Cylinder, Skull, Wave (1) | 2020.12.01 |
[T21.2] Drawble System (0) | 2020.11.30 |
Comments