본문 바로가기
Directx12 3D 프로그래밍 입문/9.텍스처 적용

9.13 연습 문제

by ftftgop3 2023. 10. 10.

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);
    }
}

텍스처 2개 결합

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