1. 나무 상자 예제, 텍스처 좌표 들과 좌표 지정 모드, 필터링 옵션 변경 후 실험
//hlsl 6개의 표본 추출기를 셰이더에 지정
SamplerState gsamPointWrap : register(s0);
SamplerState gsamPointClamp : register(s1);
SamplerState gsamLinearWrap : register(s2);
SamplerState gsamLinearClamp : register(s3);
SamplerState gsamAnisotropicWrap : register(s4);
SamplerState gsamAnisotropicClamp : register(s5);
//픽셀 셰이더에서 6개를 돌아가서면 적용
float4 PS(VertexOut pin) : SV_Target
{
float4 diffuseAlbedo = gDiffuseMap.Sample(gsamLinearWrap, pin.TexC) * gDiffuseAlbedo;
}
//각 표본 추출기에 적용된 필터 값
std::array<const CD3DX12_STATIC_SAMPLER_DESC, 6> CrateApp::GetStaticSamplers()
{
// Applications usually only need a handful of samplers. So just define them all up front
// and keep them available as part of the root signature.
//텍스처 점 필터링 적용, 밉맵 수준 점 필터링 적용
//순환 좌표 모드
const CD3DX12_STATIC_SAMPLER_DESC pointWrap(
0, // shaderRegister
D3D12_FILTER_MIN_MAG_MIP_POINT, // filter
D3D12_TEXTURE_ADDRESS_MODE_WRAP, // addressU
D3D12_TEXTURE_ADDRESS_MODE_WRAP, // addressV
D3D12_TEXTURE_ADDRESS_MODE_WRAP); // addressW
//텍스처 점 필터링 적용, 밉맵 수준 점 필터링 적용
//한정 좌표 모드
const CD3DX12_STATIC_SAMPLER_DESC pointClamp(
1, // shaderRegister
D3D12_FILTER_MIN_MAG_MIP_POINT, // filter
D3D12_TEXTURE_ADDRESS_MODE_CLAMP, // addressU
D3D12_TEXTURE_ADDRESS_MODE_CLAMP, // addressV
D3D12_TEXTURE_ADDRESS_MODE_CLAMP); // addressW
//텍스처 맵 겹선형 필터링, 밉맵 겹선형 필터링 (삼선형 필터링)
//순환 좌표 모드
const CD3DX12_STATIC_SAMPLER_DESC linearWrap(
2, // shaderRegister
D3D12_FILTER_MIN_MAG_MIP_LINEAR, // filter
D3D12_TEXTURE_ADDRESS_MODE_WRAP, // addressU
D3D12_TEXTURE_ADDRESS_MODE_WRAP, // addressV
D3D12_TEXTURE_ADDRESS_MODE_WRAP); // addressW
//텍스처 맵 겹선형 필터링, 밉맵 겹선형 필터링 (삼선형 필터링)
//한정 좌표 모드
const CD3DX12_STATIC_SAMPLER_DESC linearClamp(
3, // shaderRegister
D3D12_FILTER_MIN_MAG_MIP_LINEAR, // filter
D3D12_TEXTURE_ADDRESS_MODE_CLAMP, // addressU
D3D12_TEXTURE_ADDRESS_MODE_CLAMP, // addressV
D3D12_TEXTURE_ADDRESS_MODE_CLAMP); // addressW
//축소 확대 밉밉핑에 비등방 필터링 적용
//순환 좌표 모드
const CD3DX12_STATIC_SAMPLER_DESC anisotropicWrap(
4, // shaderRegister
D3D12_FILTER_ANISOTROPIC, // filter
D3D12_TEXTURE_ADDRESS_MODE_WRAP, // addressU
D3D12_TEXTURE_ADDRESS_MODE_WRAP, // addressV
D3D12_TEXTURE_ADDRESS_MODE_WRAP, // addressW
0.0f, // mipLODBias
8); // maxAnisotropy
//축소 확대 밉밉핑에 비등방 필터링 적용
//한정 좌표 모드
const CD3DX12_STATIC_SAMPLER_DESC anisotropicClamp(
5, // shaderRegister
D3D12_FILTER_ANISOTROPIC, // filter
D3D12_TEXTURE_ADDRESS_MODE_CLAMP, // addressU
D3D12_TEXTURE_ADDRESS_MODE_CLAMP, // addressV
D3D12_TEXTURE_ADDRESS_MODE_CLAMP, // addressW
0.0f, // mipLODBias
8); // maxAnisotropy, 비등방 1~16 값이 올라 갈수록 해상도는 좋아진다
return {
pointWrap, pointClamp,
linearWrap, linearClamp,
anisotropicWrap, anisotropicClamp };
}
2. Directx Texture Tool 이용
3. 다중 텍스처 처리, 나무 상자의 여섯 면에 두 개의 텍스처를 섞은 모습을 나타 내는 셰이더 작성
//HLSL code
Texture2D gMultitexturing : register(t1); //추가
float4 PS(VertexOut pin) : SV_Target
{
float4 diffuseAlbedo = gDiffuseMap.Sample(gsamLinearWrap, pin.TexC) * gDiffuseAlbedo;
float4 MultitexturingAlbedo = gMultitexturing.Sample(gsamLinearWrap, pin.TexC) * gDiffuseAlbedo;
//첫번째 텍스처와 두번째 텍스처 색을 곱 연산 후 반환
diffuseAlbedo = diffuseAlbedo * MultitexturingAlbedo;
//....
}
//C++ code
void CrateApp::LoadTextures()
{
auto woodCrateTex = std::make_unique<Texture>();
woodCrateTex->Name = "woodCrateTex";
woodCrateTex->Filename = L"../../Textures/WoodCrate01.dds";
ThrowIfFailed(DirectX::CreateDDSTextureFromFile12(md3dDevice.Get(),
mCommandList.Get(), woodCrateTex->Filename.c_str(),
woodCrateTex->Resource, woodCrateTex->UploadHeap));
mTextures[woodCrateTex->Name] = std::move(woodCrateTex);
//2번 째 텍스처 로드
auto woodCrateTex002 = std::make_unique<Texture>();
woodCrateTex002->Name = "woodCrateTex002";
woodCrateTex002->Filename = L"../../Textures/WoodCrate02.dds";
ThrowIfFailed(DirectX::CreateDDSTextureFromFile12(md3dDevice.Get(),
mCommandList.Get(), woodCrateTex002->Filename.c_str(),
woodCrateTex002->Resource, woodCrateTex002->UploadHeap));
mTextures[woodCrateTex002->Name] = std::move(woodCrateTex002);
}
void CrateApp::BuildRootSignature()
{
CD3DX12_DESCRIPTOR_RANGE texTable[2];
texTable[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0); // hlsl 에서 t0 담당
texTable[1].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 1); // hlsl 에서 t1 담당
// Root parameter can be a table, root descriptor or root constants.
CD3DX12_ROOT_PARAMETER slotRootParameter[5];
//각 매개변수에 맞게 초기화
slotRootParameter[0].InitAsDescriptorTable(1, &texTable[0], D3D12_SHADER_VISIBILITY_PIXEL);
slotRootParameter[1].InitAsConstantBufferView(0);
slotRootParameter[2].InitAsConstantBufferView(1);
slotRootParameter[3].InitAsConstantBufferView(2);
slotRootParameter[4].InitAsDescriptorTable(1, &texTable[1], D3D12_SHADER_VISIBILITY_PIXEL);
//...
}
void CrateApp::BuildDescriptorHeaps()
{
//
// Create the SRV heap.
//
D3D12_DESCRIPTOR_HEAP_DESC srvHeapDesc = {};
srvHeapDesc.NumDescriptors = 2; //2개로 증가
srvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
srvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
ThrowIfFailed(md3dDevice->CreateDescriptorHeap(&srvHeapDesc, IID_PPV_ARGS(&mSrvDescriptorHeap)));
//
// Fill out the heap with actual descriptors.
//
CD3DX12_CPU_DESCRIPTOR_HANDLE hDescriptor(mSrvDescriptorHeap->GetCPUDescriptorHandleForHeapStart());
//첫번째 텍스처를 힙에 지정
auto woodCrateTex = mTextures["woodCrateTex"]->Resource;
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
srvDesc.Format = woodCrateTex->GetDesc().Format;
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
srvDesc.Texture2D.MostDetailedMip = 0;
srvDesc.Texture2D.MipLevels = woodCrateTex->GetDesc().MipLevels;
srvDesc.Texture2D.ResourceMinLODClamp = 0.0f;
md3dDevice->CreateShaderResourceView(woodCrateTex.Get(), &srvDesc, hDescriptor);
//2번째 텍스처를 SRV 힙에 지정
hDescriptor.Offset(1, mCbvSrvDescriptorSize);
auto woodCrateTex002 = mTextures["woodCrateTex002"]->Resource;
srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
srvDesc.Format = woodCrateTex002->GetDesc().Format;
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
srvDesc.Texture2D.MostDetailedMip = 0;
srvDesc.Texture2D.MipLevels = woodCrateTex002->GetDesc().MipLevels;
srvDesc.Texture2D.ResourceMinLODClamp = 0.0f;
md3dDevice->CreateShaderResourceView(woodCrateTex002.Get(), &srvDesc, hDescriptor);
}
void CrateApp::DrawRenderItems(ID3D12GraphicsCommandList* cmdList, const std::vector<RenderItem*>& ritems)
{
UINT objCBByteSize = d3dUtil::CalcConstantBufferByteSize(sizeof(ObjectConstants));
UINT matCBByteSize = d3dUtil::CalcConstantBufferByteSize(sizeof(MaterialConstants));
auto objectCB = mCurrFrameResource->ObjectCB->Resource();
auto matCB = mCurrFrameResource->MaterialCB->Resource();
// For each render item...
for(size_t i = 0; i < ritems.size(); ++i)
{
auto ri = ritems[i];
cmdList->IASetVertexBuffers(0, 1, &ri->Geo->VertexBufferView());
cmdList->IASetIndexBuffer(&ri->Geo->IndexBufferView());
cmdList->IASetPrimitiveTopology(ri->PrimitiveType);
CD3DX12_GPU_DESCRIPTOR_HANDLE tex(mSrvDescriptorHeap->GetGPUDescriptorHandleForHeapStart());
tex.Offset(ri->Mat->DiffuseSrvHeapIndex, mCbvSrvDescriptorSize);
D3D12_GPU_VIRTUAL_ADDRESS objCBAddress = objectCB->GetGPUVirtualAddress() + ri->ObjCBIndex*objCBByteSize;
D3D12_GPU_VIRTUAL_ADDRESS matCBAddress = matCB->GetGPUVirtualAddress() + ri->Mat->MatCBIndex*matCBByteSize;
cmdList->SetGraphicsRootDescriptorTable(0, tex);
cmdList->SetGraphicsRootConstantBufferView(1, objCBAddress);
cmdList->SetGraphicsRootConstantBufferView(3, matCBAddress);
//두 번째 텍스처를 렌더링 파이프라인에 묶음
tex.Offset(1, mCbvSrvDescriptorSize);
cmdList->SetGraphicsRootDescriptorTable(4, tex);
cmdList->DrawIndexedInstanced(ri->IndexCount, 1, ri->StartIndexLocation, ri->BaseVertexLocation, 0);
}
}
4. 텍스처 회전
- 텍스처의 회전 시 축을 중심축으로 이동하는 행렬 -> 회전 행렬 -> 중심축의 이동의 역 행렬 순으로 곱한다
void CrateApp::UpdateObjectCBs(const GameTimer& gt)
{
auto currObjectCB = mCurrFrameResource->ObjectCB.get();
for(auto& e : mAllRitems)
{
// Only update the cbuffer data if the constants have changed.
// This needs to be tracked per frame resource.
if(e->NumFramesDirty > 0)
{
XMMATRIX world = XMLoadFloat4x4(&e->World);
static float totalRotation = 0.0f;
float rotationAnglePerFrame = XMConvertToRadians(0.01f);
totalRotation += rotationAnglePerFrame;
// 누적된 회전 각도를 0도부터 360도 사이로 유지합니다.
if (totalRotation >= XM_2PI) // XM_2PI는 360도에 해당하는 라디안 값입니다.
{
totalRotation -= XM_2PI;
}
// 회전 행렬 생성
XMMATRIX rotationMatrix = XMMatrixRotationZ(totalRotation);
//원점 이동 행렬
XMMATRIX centerTranslation = XMMatrixTranslation(-0.5f, -0.5f, 0.0f);
XMMATRIX rotatedTexture = centerTranslation * rotationMatrix * XMMatrixInverse(nullptr, centerTranslation);
XMMATRIX texTransform = XMLoadFloat4x4(&e->TexTransform);
XMMATRIX worldMatrix = XMMatrixMultiply(rotatedTexture, texTransform);
ObjectConstants objConstants;
XMStoreFloat4x4(&objConstants.World, XMMatrixTranspose(world));
XMStoreFloat4x4(&objConstants.TexTransform, XMMatrixTranspose(worldMatrix));
currObjectCB->CopyData(e->ObjCBIndex, objConstants);
//매 프레임 마다 회전 값을 계산 하기 위해서 e->NumFramesDirty 주석 처리
// Next FrameResource need to be updated too.
//e->NumFramesDirty--;
}
}
}
5. 3차원 삼각형 정점 들과 텍스처 좌표에 대한 상관 관계를 방정식으로 표현
$(u,v) = q_0 + s(q_1-q_0)+t(q_2-q_0)$
(a) u, v 와 $q_0, q_1, q_2$ 사용 하여 위의 방정식을 풀어서 (s, t) 를 u와 v로 표현
$q_0 = (u_0,v_0), q_1=(u_1,v_1), q_2=(u_2,v_2)$ 경우
$$(u,v) - (u_0,v_0) = s(u_1-u_0,v_1-v_0)+t(u_2-u_0, v_2-v_0)\\
\begin{bmatrix}
u_1-u_0 & u_2-u_0 \\
v_1-v_0 & v_2-v_0 \\
\end{bmatrix}
\begin{bmatrix}
s \\t
\end{bmatrix} = \begin{bmatrix}
u-u_0 \\
v-v_0 \\
\end{bmatrix}$$
(b) p를 u, v 함수로 표현
$p(u,v) = p(s(u,v), t(u,v))\\
=p_0+s(u,v)(p_1-p_0)+t(u,v)(p_2-p_0) $
(c) 벡터간의 기하학적 의미는 u 방향으로의 이동 속도, v 방향으로의 이동 속도를 뜻한다
$\partial p/\partial u$ : 텍스처 공간에서 u 방향의 이동 속도 뜻한다
$\partial p/\partial v$ : 텍스처 공간에서 v 방향의 이동 속도 뜻한다
'Directx12 3D 프로그래밍 입문 > 9.텍스처 적용' 카테고리의 다른 글
9.13 연습문제 6 (1) | 2023.10.17 |
---|---|
9.12 텍스처 요약 (0) | 2023.09.21 |
9.11 언덕 과 파도 예제 (0) | 2023.09.21 |
9.9 나무 상자 예제 (0) | 2023.09.18 |