Material (머티리얼)이란 메시에 적용하여 씬의 시각적인 모양을 조절할 수 있는 애셋입니다. 넓게 보면, 머티리얼이란 오브젝트에 적용할 수 있는 "페인트"라 보면 됩니다. 하지만 그것도 약간 오해의 소지가 있는데, 머티리얼이란 말 그대로 오브젝트가 어떤 재질로 만들어졌는지를 정의하는 것이기 때문입니다. 그 색이나 광택, 투과성 등을 정의할 수 있습니다.
보다 기술적인 용어로 풀자면, 씬에서의 빛이 표면에 닿으면, 머티리얼을 사용하여 그 빛과 표면의 상호작용을 계산합니다. 이러한 계산은 여러가지 이미지(텍스처)에서 온 데이터를 수학 표현식과 아울러 머티리얼 자체에 상속된 여러가지 프로퍼티 세팅을 통해 이루어집니다.
#pragma once
#include "yaResource.h"
#include "yaTexture.h"
#include "yaShader.h"
namespace ya
{
class Material : public Resource
{
public:
struct Data
{
std::wstring albedo; //difuuse
};
Material();
virtual ~Material();
virtual HRESULT Save(const std::wstring& path) override;
virtual HRESULT Load(const std::wstring& path) override;
void Bind();
void SetShader(graphics::Shader* shader) { mShader = shader; }
private:
graphics::eRenderingMode mMode;
Material::Data mData;
//Texture* mTexture;
graphics::Shader* mShader;
};
}
JavaScript
복사
입력 어셈블러 스테이지(Input Assembler 이하 IA) 는 렌더링 파이프라인의 젤 처음 스테이지이자
어플리케이션으로부터 넘겨받은 버텍스 버퍼나 인덱스 버퍼의 데이터를 읽어들여 [점],[선],[삼각형]등의 프리미티브를
조합하여 파이프라인의 다음 스테이지로 데이터를 흘려보내는 역할을 한다
그 밖에 셰이더에서의 처리에 필요한 [ 시스템 생성값]을 추가할수도 있다
[ 시스템 생성값 ]은 다른 입출력 Element와 마찬가지로 [ 시멘틱스]를 붙여 식별하며
입력어셈블러가 생성하는 시스템 생성값에는 [ 버텍스 ID ] [ 프리미티브ID ] [ 인스턴스 ID] 등이 있다.
아래는 입력 어셈블러 스테이지에서의 데이터들의 관계도를 나타낸 그림이다
입력 레이아웃 오브젝트
DirectX의 버텍스 버퍼에는 어플리케이션측에서 임의의 정보를 기록할 수 있다
그때문에 [ 어떤 버텍스버퍼의 어느 데이터가 포함되어 있고, 셰이더에 어떤 식으로 넘길것인가 ] 를 IA에 알려줄 필요가 있다
이때문에 필요한것이 [ Input Layout ] 이다
입력 레이아웃 오브젝트는 ID3D11InputLayout 인터페이스를 사용하며 이 인터페이스 자체는 딱히 기능이 있는것은 아니다
입력 레이아웃 오브젝트를 만들려면 입력 Element의 배열을 D3D11_INPUT_ELEMENT_DESC 구조체의 배열형태로 준비한다
아래는 버텍스 데이터 1개에 대한 정의를 선언하는 코드이다
D3D11_INPUT_ELEMENT_DESC inputLayoutDesces[2] = {};
inputLayoutDesces[0].AlignedByteOffset = 0;
inputLayoutDesces[0].Format = DXGI_FORMAT_R32G32B32_FLOAT;
inputLayoutDesces[0].InputSlot = 0;
inputLayoutDesces[0].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
inputLayoutDesces[0].SemanticName = "POSITION";
inputLayoutDesces[0].SemanticIndex = 0;
inputLayoutDesces[1].AlignedByteOffset = 12;
inputLayoutDesces[1].Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
inputLayoutDesces[1].InputSlot = 0;
inputLayoutDesces[1].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
inputLayoutDesces[1].SemanticName = "COLOR";
inputLayoutDesces[1].SemanticIndex = 0;
graphics::Shader* triangleShader = Resources::Find<graphics::Shader>(L"TriangleShader");
mesh->SetVertexBufferParams(2, inputLayoutDesces, triangleShader->GetVSBlob()->GetBufferPointer(), triangleShader->GetVSBlob()->GetBufferSize());
JavaScript
복사
D3D11_INPUT_ELEMENT_DESC inputLayoutDesces[3] = {};
inputLayoutDesces[0].AlignedByteOffset = 0;
inputLayoutDesces[0].Format = DXGI_FORMAT_R32G32B32_FLOAT;
inputLayoutDesces[0].InputSlot = 0;
inputLayoutDesces[0].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
inputLayoutDesces[0].SemanticName = "POSITION";
inputLayoutDesces[0].SemanticIndex = 0;
inputLayoutDesces[1].AlignedByteOffset = 12;
inputLayoutDesces[1].Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
inputLayoutDesces[1].InputSlot = 0;
inputLayoutDesces[1].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
inputLayoutDesces[1].SemanticName = "COLOR";
inputLayoutDesces[1].SemanticIndex = 0;
inputLayoutDesces[2].AlignedByteOffset = 28;
inputLayoutDesces[2].Format = DXGI_FORMAT_R32G32_FLOAT;
inputLayoutDesces[2].InputSlot = 0;
inputLayoutDesces[2].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
inputLayoutDesces[2].SemanticName = "TEXCOORD";
inputLayoutDesces[2].SemanticIndex = 0;
graphics::Shader* spriteShader = Resources::Find<graphics::Shader>(L"SpriteShader");
mesh->SetVertexBufferParams(3, inputLayoutDesces, spriteShader->GetVSBlob()->GetBufferPointer(), spriteShader->GetVSBlob()->GetBufferSize());
JavaScript
복사
SemanticName 해당 HLSL 에서 시멘틱스 이름이며
같은 시멘틱스 명이 여러개 있을 경우에는 다음 인자값(인덱스 값)으로 구별을 하며 필요없을때는 0을 설정한다
포맷은 DXGI_FORMAT enum형을 사용하며
데이터 위치로써 데이터가 있는 버텍스 버퍼를 등록할 입력슬롯 번호 와
버텍스 버퍼내에 있는 버텍스 데이터의 처음에서 데이터까지의 오프셋 값을 지정한다
긱 Element의 입력 슬롯 번호와 오프셋은 다음과 같이 된다
그 다음 버텍스 버퍼에 넘겨진 3D 오브젝트를 단순히 한번 렌더링 할 경우에는 D3D11_INPUT_PER_VERTEX_DATA와 0을
인자값으로 주면 되며 인스턴싱을 할 경우에는 D3D11_INPUT_PER_INSTANCE_DATA 와 그릴 회수를 설정한다 ( 추후 다시 설명)
입력 레이아웃 오브젝트 생성
void InputLayout::CreateInputLayout(UINT vertexCount, D3D11_INPUT_ELEMENT_DESC* layout
, const void* pShaderBytecodeWithInputSignature, SIZE_T BytecodeLength)
{
if (!(GetDevice()->CreateInputLayout(layout, vertexCount
, pShaderBytecodeWithInputSignature
, BytecodeLength
, mInputLayout.GetAddressOf())))
assert(NULL && "Create input layout failed!");
}
JavaScript
복사
위에 설정을 가지고 ID3D11Device::CreateInputLayout 함수를 호출하여 입력레이아웃 오브젝트를 생성한다
DirectX 11에서는 퍼포먼스를 향상시키기 위해 파이프라인의 설정에 관한 타당성 검증을 렌더링시가 아닌 가능한한 오브젝트를 생성할때에 수행한다 (IA 레이아웃이 필요한 이유)
렌더링 파이프라인이 올바르게 동작하려면 [ IA에 입력될 데이터의 구조 ] 와 [ 버텍스 셰이더 함수에의 입력데이터의 구조 ]가 일치해야 한다.
#include "ConstantBuffers.hlsli"
struct VS_Input
{
float3 pos : POSITION;
float4 color : COLOR;
float2 uv : TEXCOORD;
};
struct VS_Output
{
float4 pos : SV_Position;
float4 color : COLOR;
float2 uv : TEXCOORD;
};
VS_Output main(VS_Input input)
{
VS_Output output;
output.pos = float4(input.pos, 1.0f);
output.pos.x += position.x;
output.pos.y += position.y;
output.pos.z += position.z;
output.color = input.color;
output.uv = input.uv;
return output;
}
GLSL
복사
그 때문에 입력 레이아웃 오브젝트를 생성할때 위의 2개가 일치하고 있는지를 확인하기 위한
버텍스 셰이더의 [ 입력 시그니처 ] 가 필요하게 된다.
버텍스 셰이더의 [ 입력 시그니처 ] 는 컴파일된 버텍스 셰이더의 바이트코드에 포함되어 있기에
입력 레이아웃 오브젝트 생성시에는 버텍스 셰이더의 바이트 코드가 필요하다.
바이트코드는 지난 포스팅에서 다루었던 셰이더 오브젝트를 만들때의 얻을수 있는 ID3DBlob 인터페이스가 가지고 있다.
우리 엔진에서는 해당 바이트코드는 셰이더 클래스가 들고 있다.
graphics::Shader* triangleShader = Resources::Find<graphics::Shader>(L"TriangleShader");
mesh->SetVertexBufferParams(2, inputLayoutDesces, triangleShader->GetVSBlob()->GetBufferPointer(), triangleShader->GetVSBlob()->GetBufferSize());
GLSL
복사