서의 공간
[T24.2] Lighting 본문
ConstantBuffer.cpp
더보기
template<typename C>
class ConstantBuffer : public Bindable
{
public:
void Update(Graphics& gfx, const C& consts)
{
INFOMAN(gfx);
D3D11_MAPPED_SUBRESOURCE msr;
GFX_THROW_INFO(GetContext(gfx)->Map(
pConstantBuffer.Get(), 0u,
D3D11_MAP_WRITE_DISCARD, 0u,
&msr
));
memcpy(msr.pData, &consts, sizeof(consts));
GetContext(gfx)->Unmap(pConstantBuffer.Get(), 0u);
}
ConstantBuffer(Graphics& gfx, const C& consts, UINT slot = 0u)
:
slot(slot)
{
INFOMAN(gfx);
D3D11_BUFFER_DESC cbd;
cbd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
cbd.Usage = D3D11_USAGE_DYNAMIC;
cbd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
cbd.MiscFlags = 0u;
cbd.ByteWidth = sizeof(consts);
cbd.StructureByteStride = 0u;
D3D11_SUBRESOURCE_DATA csd = {};
csd.pSysMem = &consts;
GFX_THROW_INFO(GetDevice(gfx)->CreateBuffer(&cbd, &csd, &pConstantBuffer));
}
ConstantBuffer(Graphics& gfx, UINT slot = 0u)
:
slot(slot)
{
INFOMAN(gfx);
D3D11_BUFFER_DESC cbd;
cbd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
cbd.Usage = D3D11_USAGE_DYNAMIC;
cbd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
cbd.MiscFlags = 0u;
cbd.ByteWidth = sizeof(C);
cbd.StructureByteStride = 0u;
GFX_THROW_INFO(GetDevice(gfx)->CreateBuffer(&cbd, nullptr, &pConstantBuffer));
}
protected:
Microsoft::WRL::ComPtr<ID3D11Buffer> pConstantBuffer;
UINT slot;
};
TransformCbuf.cpp
더보기
#include "TransformCbuf.h"
TransformCbuf::TransformCbuf(Graphics& gfx, const Drawable& parent, UINT slot)
:
parent(parent)
{
if (!pVcbuf)
{
pVcbuf = std::make_unique<VertexConstantBuffer<Transforms>>(gfx, slot);
}
}
void TransformCbuf::Bind(Graphics& gfx) noexcept
{
const auto modelView = parent.GetTransformXM() * gfx.GetCamera();
const Transforms tf =
{
DirectX::XMMatrixTranspose(modelView),
DirectX::XMMatrixTranspose(
modelView *
gfx.GetProjection()
)
};
pVcbuf->Update(gfx, tf);
pVcbuf->Bind(gfx);
}
std::unique_ptr<VertexConstantBuffer<TransformCbuf::Transforms>> TransformCbuf::pVcbuf;
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, DirectX::FXMMATRIX view) const noexcept;
private:
/*
- Diffuse Light(분산광):
표면에 한 점을 빛이 때리면 광선들이 다양한 무작위 방향들로 흩어진다
공식: 빛의 세기(kd) x (입사광(ld) ⓧ 분산광 재질 색상(md))
표면에 들어오는 입사광과 분산광 재질 색상을 ⓧ 연산을 하면 반사된
분산광의 색상이 주어진다.
kd = max(L·n, 0) 이고 스칼라 값이다. 빛의 세기를 의미하고
이것을 분산광의 색상에 곱하면 반사된 분산광을 구할 수 있다.
- Ambient Light(주변광):
광원에서 간접적으로 표면에 도달한 빛.
간접적으로라는 것은 다른 표면에 적어도 한번 반사되었다는 뜻
공식: diffuse light + ambient light, ambient light = 입사광(la) ⓧ 주변광 재질 색상(ma)
- Phong lighting(퐁 조명) 또는 per pixel lighting(픽셀별 조명) :
법선의 보간과 조명 계산을 픽셀별로 수행하는 것
- Attenuation : 빛의 세기가 거리에 따라 감소하는 방식을 제어하는 감쇠 상수
- alingas(16) : HLSL에서는 data 멤버들이 4차원 벡터 단위로 채워 넣되
하나의 멤버가 두 개의 4차원 벡터에 걸쳐 나누어지면 안된다는 제약이 있다.
FLOAT3는 -> (x, y, z, padding) 형식으로 채워져야 한다.
*/
struct PointLightCBuf
{
alignas(16) DirectX::XMFLOAT3 pos;
alignas(16) DirectX::XMFLOAT3 ambient;
alignas(16) DirectX::XMFLOAT3 diffuseColor;
float diffuseIntensity;
float attConst;
float attLin;
float attQuad;
};
private:
PointLightCBuf cbData;
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)
{
Reset();
}
void PointLight::SpawnControlWindow() noexcept
{
if (ImGui::Begin("Light"))
{
ImGui::Text("Position");
ImGui::SliderFloat("X", &cbData.pos.x, -60.0f, 60.0f, "%.1f");
ImGui::SliderFloat("Y", &cbData.pos.y, -60.0f, 60.0f, "%.1f");
ImGui::SliderFloat("Z", &cbData.pos.z, -60.0f, 60.0f, "%.1f");
ImGui::Text("Intensity/Color");
ImGui::SliderFloat("Intensity", &cbData.diffuseIntensity, 0.01f, 2.0f, "%.2f", ImGuiSliderFlags_Logarithmic);
ImGui::ColorEdit3("Diffuse Color", &cbData.diffuseColor.x);
ImGui::ColorEdit3("Ambient", &cbData.ambient.x);
ImGui::Text("Falloff");
ImGui::SliderFloat("Constant", &cbData.attConst, 0.05f, 10.0f, "%.2f", ImGuiSliderFlags_Logarithmic);
ImGui::SliderFloat("Linear", &cbData.attLin, 0.0001f, 4.0f, "%.4f", ImGuiSliderFlags_Logarithmic);
ImGui::SliderFloat("Quadratic", &cbData.attQuad, 0.0000001f, 10.0f, "%.7f", ImGuiSliderFlags_Logarithmic);
if (ImGui::Button("Reset"))
{
Reset();
}
}
ImGui::End();
}
void PointLight::Reset() noexcept
{
cbData = {
{ 0.0f,0.0f,0.0f },
{ 0.05f,0.05f,0.05f },
{ 1.0f,1.0f,1.0f },
1.0f,
1.0f,
0.045f,
0.0075f,
};
}
void PointLight::Draw(Graphics & gfx) const noexcept(!IS_DEBUG)
{
mesh.SetPos(cbData.pos);
mesh.Draw(gfx);
}
void PointLight::Bind(Graphics & gfx, DirectX::FXMMATRIX view) const noexcept
{
auto dataCopy = cbData;
const auto pos = DirectX::XMLoadFloat3(&cbData.pos);
DirectX::XMStoreFloat3(&dataCopy.pos, DirectX::XMVector3Transform(pos, view));
cbuf.Update(gfx, dataCopy);
cbuf.Bind(gfx);
}
Box.cpp
더보기
#include "Box.h"
#include "BindableBase.h"
#include "GraphicsThrowMacros.h"
#include "Cube.h"
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,
DirectX::XMFLOAT3 material)
:
TestObject(gfx, rng, adist, ddist, odist, rdist)
{
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));
struct PSMaterialConstant
{
dx::XMFLOAT3 color;
float specularIntensity = 0.6f;
float specularPower = 30.0f;
float padding[3];
} colorConst;
colorConst.color = material;
AddBind(std::make_unique<PixelConstantBuffer<PSMaterialConstant>>(gfx, colorConst, 1u));
// model deformation transform (per instance, not stored as bind)
dx::XMStoreFloat3x3(
&mt,
dx::XMMatrixScaling(1.0f, 1.0f, bdist(rng))
);
}
DirectX::XMMATRIX Box::GetTransformXM() const noexcept
{
namespace dx = DirectX;
return dx::XMLoadFloat3x3(&mt) * TestObject::GetTransformXM();
}
Shader
더보기
PhongVS.hlsl
cbuffer CBuf
{
matrix modelView;
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), modelView);
vso.normal = mul(n, (float3x3)modelView);
vso.pos = mul(float4(pos, 1.0f), modelViewProj);
return vso;
}
PhongPS.hlsl
cbuffer LightCBuf
{
float3 lightPos;
float3 ambient;
float3 diffuseColor;
float diffuseIntensity;
float attConst;
float attLin;
float attQuad;
};
cbuffer ObjectCBuf
{
float3 materialColor;
float specularIntensity;
float specularPower;
};
float4 main(float3 worldPos : Position, float3 n : Normal) : SV_Target
{
// fragment to light vector data
const float3 vToL = lightPos - worldPos;
const float distToL = length(vToL);
const float3 dirToL = vToL / distToL;
// attenuation
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));
// reflected light vector
const float3 w = n * dot(vToL, n);
const float3 r = w * 2.0f - vToL;
// calculate specular intensity based on angle between viewing vector and reflection vector, narrow with power function
const float3 specular = att * (diffuseColor * diffuseIntensity) * specularIntensity * pow(max(0.0f, dot(normalize(-r), normalize(worldPos))), specularPower);
// final color
return float4(saturate((diffuse + ambient + specular) * materialColor), 1.0f);
}
Cylinder.cpp
더보기
#include "Cylinder.h"
#include "Prism.h"
#include "BindableBase.h"
Cylinder::Cylinder(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,
std::uniform_int_distribution<int>& tdist)
:
TestObject(gfx, rng, adist, ddist, odist, rdist)
{
namespace dx = DirectX;
if (!IsStaticInitialized())
{
struct Vertex
{
dx::XMFLOAT3 pos;
dx::XMFLOAT3 n;
};
auto model = Prism::MakeTesselatedIndependentCapNormals<Vertex>(tdist(rng));
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"IndexedPhongPS.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));
struct PSMaterialConstant
{
dx::XMFLOAT3A colors[6] = {
{1.0f,0.0f,0.0f},
{0.0f,1.0f,0.0f},
{0.0f,0.0f,1.0f},
{1.0f,1.0f,0.0f},
{1.0f,0.0f,1.0f},
{0.0f,1.0f,1.0f},
};
float specularIntensity = 0.6f;
float specularPower = 30.0f;
} matConst;
AddStaticBind(std::make_unique<PixelConstantBuffer<PSMaterialConstant>>(gfx, matConst, 1u));
}
else
{
SetIndexFromStatic();
}
AddBind(std::make_unique<TransformCbuf>(gfx, *this));
}
Shader(Cylinder)
더보기
IndexedPhongPS.hlsl
cbuffer LightCBuf
{
float3 lightPos;
float3 ambient;
float3 diffuseColor;
float diffuseIntensity;
float attConst;
float attLin;
float attQuad;
};
cbuffer ObjectCBuf
{
float3 materialColors[6];
float padding;
float specularIntensity;
float specularPower;
};
float4 main(float3 worldPos : Position, float3 n : Normal, uint tid : SV_PrimitiveID) : SV_Target
{
// fragment to light vector data
const float3 vToL = lightPos - worldPos;
const float distToL = length(vToL);
const float3 dirToL = vToL / distToL;
// attenuation
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));
// reflected light vector
const float3 w = n * dot(vToL, n);
const float3 r = w * 2.0f - vToL;
// calculate specular intensity based on angle between viewing vector and reflection vector, narrow with power function
const float3 specular = att * (diffuseColor * diffuseIntensity) * specularIntensity * pow(max(0.0f, dot(normalize(-r), normalize(worldPos))), specularPower);
// final color
return float4(saturate((diffuse + ambient + specular) * materialColors[(tid / 2) % 6]), 1.0f);
}
'Graphics API > DirectX 11 - Chili' 카테고리의 다른 글
[T26] Dynamic Vertex (0) | 2020.12.05 |
---|---|
[T25] Assimp 라이브러리 (0) | 2020.12.05 |
[T24.1] Lighting (0) | 2020.12.05 |
[T24.0] Lighting (0) | 2020.12.05 |
[T21.3] Box, Hill, Sphere, Cylinder, Skull, Wave (1) | 2020.12.01 |
Comments