ImGui 활용한 DirectX 11 3D를 이용한 2D를 만드는 내용입니다.
본 내용은 똑같이 사용할 수 없음을 알립니다. (참고 및 공부자료로 만들어진 내용임을 밝힙니다.)
전 과정에 대해 이해를 해야 다음 이 부분에 대한 이해를 할 수 있음을 밝힙니다
이전 자료) https://ppatabox.tistory.com/33
1) sampler 1
저번 시간에 Uv이가 1이 넘어갈때 어떻게 처리될 것이냐 라는 옵션이 있다고 했는데
그 내용을 처리하는게 sampler이다.
쉐이더(Effect.hlsl)에서 sampler라는 게 들어갔는데
SamplerState Sampler : register(s0); //이기 밑에
Texture2D Texture : register(t0);
float4 PS(PixelInput input) : SV_TARGET
{
return Texture.Sample(Sampler, input.Uv); //여기에 들어간것
}
샘플링이 하는 역할
샘플러는 일단 샘플링을 하기 위한 옵션
예를들어 이미지가 50X50 이미지가 있다
그리고 정점이 렌더링 파이프라인에서 IA -> VS -> RS -> PS
에서 RS에서 PS올때 2D공간으로 바뀌면서 공간을 쫘악~ 채운다고 말했다.
채우고 난 사각형(공간)이 100X100이다
그럼 이미지는 50이고 그려져야 할 공간의 크기가 100인데
그렇다면 이미지는 2배가 늘어나서 확대가 돼야 한다.
반대로 그려져야 할 공간이 25X25 공간이라고 쳐보자
그러면 이미지는 축소가 돼야 한다.
이때 확대 축소를 할 때 2D 이미지가
작은 이미지를 키우려면 픽셀이 비워 보인다.
반대로 축소시킬 때는 픽셀을 버려야 한다.
이걸 어떻게 채울 것인가 없앨 것인가 라는
옵션을 결정하는 게
샘플러의 역할이다.
MIN(Minification) 축소
MAG(Magnification) 확대
MIP-mapping 밉맵
Mipmap
2
게임은 퍼포먼스가 중요한데 CPU나 GPU연산량을 치면 일반 3D게임 은 연산량이 엄청나다
다른것들은 아무리 써도 10%이네 쓰는데 요즘 게임은 50%이상 올라간다
그정도로 퍼포먼스가 중요하다
그러다 보니 게임을 만들때는 엄청난 꼼수가 있다,
시스템에서 지원해주는 퍼포먼스를 올리는 지원이 있다.
옛날에는 램이 비쌋는데 이때는 잘 안썻는데
지금은 램이 싸서 램의 용량 공간의 용량을 늘려서 시간을 사는
알고리즘에서 복잡도를 계산하는 게 있는데
(시간 / 공간 복잡도) 지금 공간 복잡도는 의미가 없어서 빠짐
지금은 용량을 희생해서 시간을 사는
텍스쳐 이미지를 하나 부르면 2^n에 맞게 디자인됨
다른 일반이미지(포토샵)는 퍼포먼스보다 정밀도가 중요한데
513이라고 치면 513을 그대로 불러들인다
하지만 DX는 가장 근소한 승수를 찾는다
그러면 513-> 512 가 찾아진다.
그러고 나면 512로 부터 8장을 만든다.
512 -> 256 -> 128 -> 64 -> 32 -> ............................크기를 줄이면서 8장을 뽑아낸다(자동)
그렇다면 512가 가장 정밀도가 높을 것이다.
그럼 플레이어가 가까이 있을때는 512를 보여주고
점점 멀어질 수록 정밀도가 떨어지는 것을 보여준다.
그러면서 렌더링 양을 줄인다 이게 MIPMAPPING
왠만하면 잘 안쓰는데
진짜 극한의 퍼포먼스를 요구하는게임이 아니라면
잘 안씀 그래도 그런 게임에서도 잘 사용은 안함
요즘에는 이것도 무시할 만한 퍼포먼스가 됨
우리는 이시간 다뤄도 mipmapping을 0으로 잡고 할것이다 ( 1장) 작업량 많아짐
2pass연산(펄업)
이렇게 들어갈 수 있는게 있는데
anistropic은 이곳에 안쓸꺼임 (MSAA) 옵션 중에서 이런게 있음
안티에일리징? TXAA등등 왜곡된 픽셀을 좀 줄여주는 옵션 (비등방성 필터)
2개의 픽셀이 있다고 치자
이게 2배가 늘어나야 한다고 하자
point는 그냥 기준에 있는 것을 가져다가 쓴다.
그럼 격자가 더 커진다
리니어는 좌우의 값을 평균을 취한다.
리니어 연산량 때문에 예전에는 포인트를 사용하다가
요즘에는 리니어로 만들고 있다.
-Graphic conferent-
Cgrapher
GDC
anistopic으로 점점 넘어가고 있는데
아직 좀 힘들 수 있다. 그래픽 카드가 엄청좋아지긴 했지만 그래도 엄청나게 연산처리때문에.. CPU나 GPU온도가 엄청나게 올라가는 걸 볼 수 있다.
잡아야 할 것은 전력효율과 온도 , 효율적인 연산처리 방법이지 않을까?
항상 이런것을 만들때는 인터페이스가 필요하다.
인터페이스가 있으면 이런것을 생성할 때 항상 Description이 따라 붙는다고 했는데
버텍스 버퍼 콘스탄스 버퍼도 description을 사용했었다.
0 초기화가 안되는 것들은 배열로 지정 되어 있으면 포인터 이기에
0초기화가 안된다.
예시로
D3D11_SAMPLER_DESC samplerDesc = { 0 };
저곳에 들어가 있는게 BorderColor 가 배열로 들어가 있다 그러면 포인터 인데
이러면 0초기화가 안된다.
그러니 수정하면
D3D11_SAMPLER_DESC samplerDesc;
빼주고
ZeroMemory로 해주자
D3D11_SAMPLER_DESC samplerDesc;
ZeroMemory(&samplerDesc, sizeof(D3D11_SAMPLER_DESC));
우리는 실시간으로 (좀 귀찮은 방식)
어떤 자료형을 써야 하는지 잘 감이 안온다.
samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
만약에 이러한게 있다고 하면 뒤에 저걸 어떻게 알았을까?
Filter에 F12누르면
이리 나오고 다음으로
D3D11_FILTER //F12또 눌러보면
쭈루룩 뭐가 나오는 걸 볼 수 있다.
위에서
D3D11_FILTER_MIN_MAG_MIP_POINT;
이것을 축소 확대 MIP을 포인트로 다 쓰겠다 라는 의미
보통 같은거 많이 쓴다.
축소, 확대, MIP리니어 같은
처리하는 것?Min_Linear_Mag_Point_Mip_Linear
Min은 linear | Mag은 point | MipMap은 linear
ConstantBuffer는 16바이트 패딩
Texture.h
#pragma once
class Texture
{
public:
Texture(wstring file);
~Texture();
void Position(float x, float y, float z = 0);
void Position(const D3DXVECTOR3& position);
void Position(D3DXVECTOR3* position);
void Scale(float x, float y, float z = 1);
void Scale(const D3DXVECTOR3& scale);
void Scale(D3DXVECTOR3* scale);
void Render();
private:
struct Vertex
{
D3DXVECTOR3 Location;
D3DXVECTOR2 Uv;
Vertex()
{
Location = D3DXVECTOR3();
Uv = D3DXVECTOR2();
}
Vertex(D3DXVECTOR3 location, D3DXVECTOR2 uv)
{
Location = location;
Uv = uv;
}
};
struct WVP
{
D3DXMATRIX World;
D3DXMATRIX View;
D3DXMATRIX Projection;
} wvp;
struct PS_Constant //값 넘겨주기
{
int Filter = 0; //이런식으로 초기화 해도됨
int Address = 0;
float Padding[2]; // 16바이트 맞춰주기
} sampler; //변수선언
private:
D3DXVECTOR3 position;
D3DXVECTOR3 scale;
private:
Shader* shader;
Vertex vertices[6];
VertexBuffer* vertexBuffer;
ConstantBuffer* wvpBuffer;
ConstantBuffer* samplerBuffer; //샘플러버퍼
ID3D11ShaderResourceView* srv;
ID3D11SamplerState* samplerFilter_Point; // 우리가 쓸 샘플러
ID3D11SamplerState* samplerFilter_Linear; // 우리가 쓸 샘플러
/*옵션 */
ID3D11SamplerState* samplerAddress_Wrap;
ID3D11SamplerState* samplerAddress_Mirror;
ID3D11SamplerState* samplerAddress_Clamp;
ID3D11SamplerState* samplerAddress_Border;
ID3D11SamplerState* samplerAddress_MirrorOnce;
};
Texture.cpp
#include "stdafx.h"
#include "Texture.h"
Texture::Texture(wstring file)
{
vertices[0] = Vertex(D3DXVECTOR3(-0.5f, -0.5f, 0), D3DXVECTOR2(0, 5));
vertices[1] = Vertex(D3DXVECTOR3(-0.5f, +0.5f, 0), D3DXVECTOR2(0, 0));
vertices[2] = Vertex(D3DXVECTOR3(+0.5f, -0.5f, 0), D3DXVECTOR2(5, 5));
vertices[3] = Vertex(D3DXVECTOR3(+0.5f, -0.5f, 0), D3DXVECTOR2(5, 5));
vertices[4] = Vertex(D3DXVECTOR3(-0.5f, +0.5f, 0), D3DXVECTOR2(0, 0));
vertices[5] = Vertex(D3DXVECTOR3(+0.5f, +0.5f, 0), D3DXVECTOR2(5, 0));
D3D11_INPUT_ELEMENT_DESC layoutDesc[] =
{
"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0,
"UV", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0
};
UINT elementCount = ARRAYSIZE(layoutDesc);
shader = new Shader(L"effect.hlsl");
shader->CreateInputLayout(layoutDesc, elementCount);
vertexBuffer = new VertexBuffer(vertices, 6, sizeof(Vertex));
wvpBuffer = new ConstantBuffer(&wvp, sizeof(WVP));
samplerBuffer = new ConstantBuffer(&sampler, sizeof(PS_Constant), 0, true); //slot 0 PS true
D3DXMatrixIdentity(&wvp.World);
D3DXMatrixIdentity(&wvp.View);
D3DXMatrixIdentity(&wvp.Projection);
D3DXVECTOR3 eye(0, 0, -1);
D3DXVECTOR3 lookAt(0, 0, 0);
D3DXVECTOR3 up(0, 1, 0);
D3DXMatrixLookAtLH(&wvp.View, &eye, &lookAt, &up);
D3DXMatrixTranspose(&wvp.View, &wvp.View);
D3DXMatrixOrthoOffCenterLH(&wvp.Projection, 0, (float)Width, 0, (float)Height, -1, +1);
D3DXMatrixTranspose(&wvp.Projection, &wvp.Projection);
wstring textureFile = L"../_Textures/" + file;
HRESULT hr = D3DX11CreateShaderResourceViewFromFile(Device, textureFile.c_str(), NULL, NULL, &srv, NULL);
assert(SUCCEEDED(hr));
D3D11_SAMPLER_DESC samplerDesc;
ZeroMemory(&samplerDesc, sizeof(D3D11_SAMPLER_DESC));
samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP; //U
samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP; //V
samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP; //W
hr = Device->CreateSamplerState(&samplerDesc, &samplerFilter_Point); //&desc포인트 &2차포인트
assert(SUCCEEDED(hr));
samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
hr = Device->CreateSamplerState(&samplerDesc, &samplerFilter_Linear);
assert(SUCCEEDED(hr));
/*각각 옵션들*/
samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
hr = Device->CreateSamplerState(&samplerDesc, &samplerAddress_Wrap);
assert(SUCCEEDED(hr));
samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_MIRROR;
samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_MIRROR;
samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_MIRROR;
hr = Device->CreateSamplerState(&samplerDesc, &samplerAddress_Mirror);
assert(SUCCEEDED(hr));
samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
hr = Device->CreateSamplerState(&samplerDesc, &samplerAddress_Clamp);
assert(SUCCEEDED(hr));
samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_BORDER;
samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_BORDER;
samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_BORDER;
float color[4] = { 1, 0, 0, 1 };
memcpy(samplerDesc.BorderColor, color, sizeof(float) * 4);
hr = Device->CreateSamplerState(&samplerDesc, &samplerAddress_Border);
assert(SUCCEEDED(hr));
samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_MIRROR_ONCE;
samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_MIRROR_ONCE;
samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_MIRROR_ONCE;
hr = Device->CreateSamplerState(&samplerDesc, &samplerAddress_MirrorOnce);
assert(SUCCEEDED(hr));
}
Texture::~Texture()
{
SAFE_RELEASE(srv);
SAFE_DELETE(vertexBuffer);
SAFE_DELETE(wvpBuffer);
SAFE_DELETE(shader);
}
void Texture::Position(float x, float y, float z)
{
Position(D3DXVECTOR3(x, y, z));
}
void Texture::Position(const D3DXVECTOR3 & position)
{
this->position = position;
}
void Texture::Position(D3DXVECTOR3 * position)
{
memcpy(position, this->position, sizeof(D3DXVECTOR3));
}
void Texture::Scale(float x, float y, float z)
{
Scale(D3DXVECTOR3(x, y, z));
}
void Texture::Scale(const D3DXVECTOR3 & scale)
{
this->scale = scale;
}
void Texture::Scale(D3DXVECTOR3 * scale)
{
memcpy(scale, this->scale, sizeof(D3DXVECTOR3));
}
void Texture::Render()
{
ImGui::SliderInt("Fliter", &sampler.Filter, 0, 1); //
ImGui::SliderInt("Address", &sampler.Address, 0, 4); //갯수 0~4까지 옵션들
D3DXMATRIX S, T;
D3DXMatrixScaling(&S, scale.x, scale.y, scale.z);
D3DXMatrixTranslation(&T, position.x, position.y, position.z);
wvp.World = S * T;
D3DXMatrixTranspose(&wvp.World, &wvp.World);
DeviceContext->PSSetSamplers(0, 1, &samplerFilter_Point); //PS그리는애 샘플러 넣어주고
DeviceContext->PSSetSamplers(1, 1, &samplerFilter_Linear); //1번에 리니어하나
ID3D11SamplerState* samplerState[5]; //배열로 (2차포인터 5개 니까 ) 포인터 배열(포인터를 배열에 넣었다)
samplerState[0] = samplerAddress_Wrap;
samplerState[1] = samplerAddress_Mirror;
samplerState[2] = samplerAddress_Clamp;
samplerState[3] = samplerAddress_Border;
samplerState[4] = samplerAddress_MirrorOnce;
DeviceContext->PSSetSamplers(2, 5, samplerState);//2번에 넣고 5개 2차포인터(포인터에 포인터니까 이름만)
DeviceContext->PSSetShaderResources(0, 1, &srv);
DeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
shader->Render();
vertexBuffer->Render();
wvpBuffer->Render();
samplerBuffer->Render(); //샘플러 버퍼 밀어주기 PS에다가 컨스탄트 값밀어주기
DeviceContext->Draw(6, 0);
}
cbuffer PS_Constant : register(b0) //PS_Constant 밀어둔거 받기
{
int Filter;
int Address;
}
.
.
float4 PS(PixelInput input) : SV_TARGET //리턴 타입이 float4
{
이런 cbuffer 자기 쉐이더에 필요한 것들은 바로 위로 올려놓아 주자 (보기 편해짐)
Effect.hlsl
struct VertexInput
{
float4 Position : POSITION0;
float2 Uv : UV0;
};
struct PixelInput
{
float4 Position : SV_POSITION;
float2 Uv : UV0;
};
cbuffer VS_Wvp : register(b0)
{
matrix World;
matrix View;
matrix Projection;
}
PixelInput VS(VertexInput input)
{
PixelInput output;
output.Position = mul(input.Position, World);
output.Position = mul(output.Position, View);
output.Position = mul(output.Position, Projection);
output.Uv = input.Uv;
return output;
}
cbuffer PS_Constant : register(b0) //PS_Constant 밀어둔거 받기
{배열로 쓸경우가 아니라면
int Filter; //끝 패딩 안써도됨 이렇게 만들어줌
int Address; // 2개 이름 일치 안해도됨 형식만
}
SamplerState Filter_Point : register(s0); //샘플러 포인트 0번
SamplerState Filter_Linear : register(s1); // 1번으로 들어감
SamplerState Sampler_Address[5] : register(s2); //옵션들 5개 2번
Texture2D Texture : register(t0);
float4 PS(PixelInput input) : SV_TARGET //리턴 타입이 float4
{
if(Address == 0)//샘플의 리턴이 색상임 float4 0이랑 같으면 포인트
return Texture.Sample(Sampler_Address[0], input.Uv);
else if (Address == 1) 아니라면 리니어로 샘플링
return Texture.Sample(Sampler_Address[1], input.Uv);
else if (Address == 2)
return Texture.Sample(Sampler_Address[2], input.Uv);
else if (Address == 3)
return Texture.Sample(Sampler_Address[3], input.Uv);
else if (Address == 4)
return Texture.Sample(Sampler_Address[4], input.Uv);
return float4(0, 0, 0, 1); //기본값
}
샘플러에서는 FIlter랑 Address만 알면 되는데
Address모드는 1보다 클때 0.5 넣으면 반절만 나오게 됨 이때는 의미 없음
//Vector2 부분 0.5를 사용할때 1이 안넘어가서 Address모드 의미 없음
vertices[0] = Vertex(D3DXVECTOR3(-0.5f, -0.5f, 0), D3DXVECTOR2(0, 0.5));
vertices[1] = Vertex(D3DXVECTOR3(-0.5f, +0.5f, 0), D3DXVECTOR2(0, 0));
vertices[2] = Vertex(D3DXVECTOR3(+0.5f, -0.5f, 0), D3DXVECTOR2(0.5, 0.5));
vertices[3] = Vertex(D3DXVECTOR3(+0.5f, -0.5f, 0), D3DXVECTOR2(0.5, 0.5));
vertices[4] = Vertex(D3DXVECTOR3(-0.5f, +0.5f, 0), D3DXVECTOR2(0, 0));
vertices[5] = Vertex(D3DXVECTOR3(+0.5f, +0.5f, 0), D3DXVECTOR2(0.5, 0));
2로 넣으면 반복됨 이게 어드레스 모드
vertices[0] = Vertex(D3DXVECTOR3(-0.5f, -0.5f, 0), D3DXVECTOR2(0, 2));
vertices[1] = Vertex(D3DXVECTOR3(-0.5f, +0.5f, 0), D3DXVECTOR2(0, 0));
vertices[2] = Vertex(D3DXVECTOR3(+0.5f, -0.5f, 0), D3DXVECTOR2(2, 2));
vertices[3] = Vertex(D3DXVECTOR3(+0.5f, -0.5f, 0), D3DXVECTOR2(2, 2));
vertices[4] = Vertex(D3DXVECTOR3(-0.5f, +0.5f, 0), D3DXVECTOR2(0, 0));
vertices[5] = Vertex(D3DXVECTOR3(+0.5f, +0.5f, 0), D3DXVECTOR2(2, 0));
이게 Address모드 이다
이게 1보다 클때 나머지 부분을 어떻게 채울 것이냐 라는 의미
10 넣어도 10장 나옴
D3D11_TEXTURE_ADDRESS
1번 반전
2번 끝에 대각선의 도장처럼 펼쳐둔거 (도장 찍고 펼친 느낌)
3번 선을 채우는 것인데 기본원래 검은색인데 빨간색으로 바꿔둠
samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_BORDER;
samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_BORDER;
samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_BORDER;
float color[4] = { 1, 0, 0, 1 }; //border색상
memcpy(samplerDesc.BorderColor, color, sizeof(float) * 4);
//배열끼리는 직접안됨(memcpy) 직접적으로 배열끼리 하면 주소가 되서 안된다 그냥 데이터 복사해줌
hr = Device->CreateSamplerState(&samplerDesc, &samplerAddress_Border);
assert(SUCCEEDED(hr));
MIRROR_ONCE 이건 clamp랑 같이 동작하는데 옵션을 키지 않는한 (필요없음)
추가참고링크)
다음내용 ) https://ppatabox.tistory.com/36
각주)
-
1. 정점에 UV의 비율에 따라 이미지를 잘라주는 기능
2. 비율에 따라 확대 및 축소해주는 기능 [본문으로]
-
렌더링 속도를 향상하고 연산을 줄이기 위한 목적, 기본 텍스쳐와 이를 연속적으로 미리 축소시킨 텍스쳐들로 이루어진 비트맵 이미지의 집합이다.
텍스쳐 크기가 512x512라면, 그것의 절반 크기인 256, 218, 64 이런식으로 1x1이 될 때까지의 텍스쳐를 미리 가지고 있다가, 실제 텍셀보다 거리가 멀어져서 맵핑될 픽셀이 줄면 해상도가 더 낮은 텍스쳐를, 그 보다 멀어지면 더 작은 텍스쳐를 불러서 맵핑 시켜준다.
밉맵 없이 Min/Mag 옵션으로 하는 것보다 미리 줄여놓은 텍스쳐를 가지고 있으면, 평균을 구하는 연산을 생략할 수 있다. 실제 밉맵을 사용하면 메모리는 30% 늘어난다고 한다. 런타임 성능은 좋아진다 [본문으로]
- 이웃 픽셀을 그대로 복사함(모자이크) 필터링을 하지않고 텍스쳐 좌표에서 가장 가까운 정수 주소(address)를 가진 텍셀의 색을 카피함, 텍스쳐에서 문자를 표시하거나 외곽선이 뭉개지지 않을경우에 사용 [본문으로]
- (1 - t) * A + t * B일때 t가 0일 경우 결과적으로는 A, point보다 더 부드럽게 나오며 연산량 높음, 텍스쳐 좌표에 가장 가까운 점의 상하 좌우에 있는 텍셀의 평균 가중치를 계산하여 보간함(일반적인 필터링) [본문으로]
- 이방성 필터링, 이방성(물체의 물리적 성질이 방향에 따라 다름) 3D 개체의 표면이 스크린평면과 임의의 각을 이룰때 3D 개체의 텍셀에서 볼 수 있는 왜곡 현상, 텍스쳐도 이러한 성질을 가지고 있는데, Anistorpic필터링은 이 왜곡을 보정하도록 하는 필터링, 가장 깔끔하게 보이지만 성능은 안좋음, (*MSAA(multi-Sampling Anti-Aliasing:멀티샘플링) [본문으로]
- 텍스쳐 좌표를 반복한다. [본문으로]
- 인접한 이미지를 반복한다. [본문으로]
- 텍스쳐 끝 부분의 픽셀이 늘어진다. [본문으로]
- 경계색을 설정한다. [본문으로]
- clamp+mirror모드 [본문으로]
- 확대/축소를 실시했을때 중간 픽셀의 처리 방법을 실시한다
비율이 늘어나고 줄어듬에 따라 빈 공간의 픽셀을 버릴것인지 채울것인지 [본문으로]
D3D11_SAMPLER_DESC samplerDesc = { 0 };
D3D11_SAMPLER_DESC samplerDesc;
D3D11_SAMPLER_DESC samplerDesc;
ZeroMemory(&samplerDesc, sizeof(D3D11_SAMPLER_DESC));
samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
D3D11_FILTER //F12또 눌러보면
D3D11_FILTER_MIN_MAG_MIP_POINT;
#pragma once
class Texture
{
public:
Texture(wstring file);
~Texture();
void Position(float x, float y, float z = 0);
void Position(const D3DXVECTOR3& position);
void Position(D3DXVECTOR3* position);
void Scale(float x, float y, float z = 1);
void Scale(const D3DXVECTOR3& scale);
void Scale(D3DXVECTOR3* scale);
void Render();
private:
struct Vertex
{
D3DXVECTOR3 Location;
D3DXVECTOR2 Uv;
Vertex()
{
Location = D3DXVECTOR3();
Uv = D3DXVECTOR2();
}
Vertex(D3DXVECTOR3 location, D3DXVECTOR2 uv)
{
Location = location;
Uv = uv;
}
};
struct WVP
{
D3DXMATRIX World;
D3DXMATRIX View;
D3DXMATRIX Projection;
} wvp;
struct PS_Constant //값 넘겨주기
{
int Filter = 0; //이런식으로 초기화 해도됨
int Address = 0;
float Padding[2]; // 16바이트 맞춰주기
} sampler; //변수선언
private:
D3DXVECTOR3 position;
D3DXVECTOR3 scale;
private:
Shader* shader;
Vertex vertices[6];
VertexBuffer* vertexBuffer;
ConstantBuffer* wvpBuffer;
ConstantBuffer* samplerBuffer; //샘플러버퍼
ID3D11ShaderResourceView* srv;
ID3D11SamplerState* samplerFilter_Point; // 우리가 쓸 샘플러
ID3D11SamplerState* samplerFilter_Linear; // 우리가 쓸 샘플러
/*옵션 */
ID3D11SamplerState* samplerAddress_Wrap;
ID3D11SamplerState* samplerAddress_Mirror;
ID3D11SamplerState* samplerAddress_Clamp;
ID3D11SamplerState* samplerAddress_Border;
ID3D11SamplerState* samplerAddress_MirrorOnce;
};
#include "stdafx.h"
#include "Texture.h"
Texture::Texture(wstring file)
{
vertices[0] = Vertex(D3DXVECTOR3(-0.5f, -0.5f, 0), D3DXVECTOR2(0, 5));
vertices[1] = Vertex(D3DXVECTOR3(-0.5f, +0.5f, 0), D3DXVECTOR2(0, 0));
vertices[2] = Vertex(D3DXVECTOR3(+0.5f, -0.5f, 0), D3DXVECTOR2(5, 5));
vertices[3] = Vertex(D3DXVECTOR3(+0.5f, -0.5f, 0), D3DXVECTOR2(5, 5));
vertices[4] = Vertex(D3DXVECTOR3(-0.5f, +0.5f, 0), D3DXVECTOR2(0, 0));
vertices[5] = Vertex(D3DXVECTOR3(+0.5f, +0.5f, 0), D3DXVECTOR2(5, 0));
D3D11_INPUT_ELEMENT_DESC layoutDesc[] =
{
"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0,
"UV", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0
};
UINT elementCount = ARRAYSIZE(layoutDesc);
shader = new Shader(L"effect.hlsl");
shader->CreateInputLayout(layoutDesc, elementCount);
vertexBuffer = new VertexBuffer(vertices, 6, sizeof(Vertex));
wvpBuffer = new ConstantBuffer(&wvp, sizeof(WVP));
samplerBuffer = new ConstantBuffer(&sampler, sizeof(PS_Constant), 0, true); //slot 0 PS true
D3DXMatrixIdentity(&wvp.World);
D3DXMatrixIdentity(&wvp.View);
D3DXMatrixIdentity(&wvp.Projection);
D3DXVECTOR3 eye(0, 0, -1);
D3DXVECTOR3 lookAt(0, 0, 0);
D3DXVECTOR3 up(0, 1, 0);
D3DXMatrixLookAtLH(&wvp.View, &eye, &lookAt, &up);
D3DXMatrixTranspose(&wvp.View, &wvp.View);
D3DXMatrixOrthoOffCenterLH(&wvp.Projection, 0, (float)Width, 0, (float)Height, -1, +1);
D3DXMatrixTranspose(&wvp.Projection, &wvp.Projection);
wstring textureFile = L"../_Textures/" + file;
HRESULT hr = D3DX11CreateShaderResourceViewFromFile(Device, textureFile.c_str(), NULL, NULL, &srv, NULL);
assert(SUCCEEDED(hr));
D3D11_SAMPLER_DESC samplerDesc;
ZeroMemory(&samplerDesc, sizeof(D3D11_SAMPLER_DESC));
samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP; //U
samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP; //V
samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP; //W
hr = Device->CreateSamplerState(&samplerDesc, &samplerFilter_Point); //&desc포인트 &2차포인트
assert(SUCCEEDED(hr));
samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
hr = Device->CreateSamplerState(&samplerDesc, &samplerFilter_Linear);
assert(SUCCEEDED(hr));
/*각각 옵션들*/
samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
hr = Device->CreateSamplerState(&samplerDesc, &samplerAddress_Wrap);
assert(SUCCEEDED(hr));
samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_MIRROR;
samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_MIRROR;
samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_MIRROR;
hr = Device->CreateSamplerState(&samplerDesc, &samplerAddress_Mirror);
assert(SUCCEEDED(hr));
samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
hr = Device->CreateSamplerState(&samplerDesc, &samplerAddress_Clamp);
assert(SUCCEEDED(hr));
samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_BORDER;
samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_BORDER;
samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_BORDER;
float color[4] = { 1, 0, 0, 1 };
memcpy(samplerDesc.BorderColor, color, sizeof(float) * 4);
hr = Device->CreateSamplerState(&samplerDesc, &samplerAddress_Border);
assert(SUCCEEDED(hr));
samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_MIRROR_ONCE;
samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_MIRROR_ONCE;
samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_MIRROR_ONCE;
hr = Device->CreateSamplerState(&samplerDesc, &samplerAddress_MirrorOnce);
assert(SUCCEEDED(hr));
}
Texture::~Texture()
{
SAFE_RELEASE(srv);
SAFE_DELETE(vertexBuffer);
SAFE_DELETE(wvpBuffer);
SAFE_DELETE(shader);
}
void Texture::Position(float x, float y, float z)
{
Position(D3DXVECTOR3(x, y, z));
}
void Texture::Position(const D3DXVECTOR3 & position)
{
this->position = position;
}
void Texture::Position(D3DXVECTOR3 * position)
{
memcpy(position, this->position, sizeof(D3DXVECTOR3));
}
void Texture::Scale(float x, float y, float z)
{
Scale(D3DXVECTOR3(x, y, z));
}
void Texture::Scale(const D3DXVECTOR3 & scale)
{
this->scale = scale;
}
void Texture::Scale(D3DXVECTOR3 * scale)
{
memcpy(scale, this->scale, sizeof(D3DXVECTOR3));
}
void Texture::Render()
{
ImGui::SliderInt("Fliter", &sampler.Filter, 0, 1); //
ImGui::SliderInt("Address", &sampler.Address, 0, 4); //갯수 0~4까지 옵션들
D3DXMATRIX S, T;
D3DXMatrixScaling(&S, scale.x, scale.y, scale.z);
D3DXMatrixTranslation(&T, position.x, position.y, position.z);
wvp.World = S * T;
D3DXMatrixTranspose(&wvp.World, &wvp.World);
DeviceContext->PSSetSamplers(0, 1, &samplerFilter_Point); //PS그리는애 샘플러 넣어주고
DeviceContext->PSSetSamplers(1, 1, &samplerFilter_Linear); //1번에 리니어하나
ID3D11SamplerState* samplerState[5]; //배열로 (2차포인터 5개 니까 ) 포인터 배열(포인터를 배열에 넣었다)
samplerState[0] = samplerAddress_Wrap;
samplerState[1] = samplerAddress_Mirror;
samplerState[2] = samplerAddress_Clamp;
samplerState[3] = samplerAddress_Border;
samplerState[4] = samplerAddress_MirrorOnce;
DeviceContext->PSSetSamplers(2, 5, samplerState);//2번에 넣고 5개 2차포인터(포인터에 포인터니까 이름만)
DeviceContext->PSSetShaderResources(0, 1, &srv);
DeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
shader->Render();
vertexBuffer->Render();
wvpBuffer->Render();
samplerBuffer->Render(); //샘플러 버퍼 밀어주기 PS에다가 컨스탄트 값밀어주기
DeviceContext->Draw(6, 0);
}
cbuffer PS_Constant : register(b0) //PS_Constant 밀어둔거 받기
{
int Filter;
int Address;
}
.
.
float4 PS(PixelInput input) : SV_TARGET //리턴 타입이 float4
{
struct VertexInput
{
float4 Position : POSITION0;
float2 Uv : UV0;
};
struct PixelInput
{
float4 Position : SV_POSITION;
float2 Uv : UV0;
};
cbuffer VS_Wvp : register(b0)
{
matrix World;
matrix View;
matrix Projection;
}
PixelInput VS(VertexInput input)
{
PixelInput output;
output.Position = mul(input.Position, World);
output.Position = mul(output.Position, View);
output.Position = mul(output.Position, Projection);
output.Uv = input.Uv;
return output;
}
cbuffer PS_Constant : register(b0) //PS_Constant 밀어둔거 받기
{배열로 쓸경우가 아니라면
int Filter; //끝 패딩 안써도됨 이렇게 만들어줌
int Address; // 2개 이름 일치 안해도됨 형식만
}
SamplerState Filter_Point : register(s0); //샘플러 포인트 0번
SamplerState Filter_Linear : register(s1); // 1번으로 들어감
SamplerState Sampler_Address[5] : register(s2); //옵션들 5개 2번
Texture2D Texture : register(t0);
float4 PS(PixelInput input) : SV_TARGET //리턴 타입이 float4
{
if(Address == 0)//샘플의 리턴이 색상임 float4 0이랑 같으면 포인트
return Texture.Sample(Sampler_Address[0], input.Uv);
else if (Address == 1) 아니라면 리니어로 샘플링
return Texture.Sample(Sampler_Address[1], input.Uv);
else if (Address == 2)
return Texture.Sample(Sampler_Address[2], input.Uv);
else if (Address == 3)
return Texture.Sample(Sampler_Address[3], input.Uv);
else if (Address == 4)
return Texture.Sample(Sampler_Address[4], input.Uv);
return float4(0, 0, 0, 1); //기본값
}
//Vector2 부분 0.5를 사용할때 1이 안넘어가서 Address모드 의미 없음
vertices[0] = Vertex(D3DXVECTOR3(-0.5f, -0.5f, 0), D3DXVECTOR2(0, 0.5));
vertices[1] = Vertex(D3DXVECTOR3(-0.5f, +0.5f, 0), D3DXVECTOR2(0, 0));
vertices[2] = Vertex(D3DXVECTOR3(+0.5f, -0.5f, 0), D3DXVECTOR2(0.5, 0.5));
vertices[3] = Vertex(D3DXVECTOR3(+0.5f, -0.5f, 0), D3DXVECTOR2(0.5, 0.5));
vertices[4] = Vertex(D3DXVECTOR3(-0.5f, +0.5f, 0), D3DXVECTOR2(0, 0));
vertices[5] = Vertex(D3DXVECTOR3(+0.5f, +0.5f, 0), D3DXVECTOR2(0.5, 0));
vertices[0] = Vertex(D3DXVECTOR3(-0.5f, -0.5f, 0), D3DXVECTOR2(0, 2));
vertices[1] = Vertex(D3DXVECTOR3(-0.5f, +0.5f, 0), D3DXVECTOR2(0, 0));
vertices[2] = Vertex(D3DXVECTOR3(+0.5f, -0.5f, 0), D3DXVECTOR2(2, 2));
vertices[3] = Vertex(D3DXVECTOR3(+0.5f, -0.5f, 0), D3DXVECTOR2(2, 2));
vertices[4] = Vertex(D3DXVECTOR3(-0.5f, +0.5f, 0), D3DXVECTOR2(0, 0));
vertices[5] = Vertex(D3DXVECTOR3(+0.5f, +0.5f, 0), D3DXVECTOR2(2, 0));
samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_BORDER;
samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_BORDER;
samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_BORDER;
float color[4] = { 1, 0, 0, 1 }; //border색상
memcpy(samplerDesc.BorderColor, color, sizeof(float) * 4);
//배열끼리는 직접안됨(memcpy) 직접적으로 배열끼리 하면 주소가 되서 안된다 그냥 데이터 복사해줌
hr = Device->CreateSamplerState(&samplerDesc, &samplerAddress_Border);
assert(SUCCEEDED(hr));
-
1. 정점에 UV의 비율에 따라 이미지를 잘라주는 기능
2. 비율에 따라 확대 및 축소해주는 기능 [본문으로]
-
렌더링 속도를 향상하고 연산을 줄이기 위한 목적, 기본 텍스쳐와 이를 연속적으로 미리 축소시킨 텍스쳐들로 이루어진 비트맵 이미지의 집합이다.
텍스쳐 크기가 512x512라면, 그것의 절반 크기인 256, 218, 64 이런식으로 1x1이 될 때까지의 텍스쳐를 미리 가지고 있다가, 실제 텍셀보다 거리가 멀어져서 맵핑될 픽셀이 줄면 해상도가 더 낮은 텍스쳐를, 그 보다 멀어지면 더 작은 텍스쳐를 불러서 맵핑 시켜준다.
밉맵 없이 Min/Mag 옵션으로 하는 것보다 미리 줄여놓은 텍스쳐를 가지고 있으면, 평균을 구하는 연산을 생략할 수 있다. 실제 밉맵을 사용하면 메모리는 30% 늘어난다고 한다. 런타임 성능은 좋아진다 [본문으로]
- 이웃 픽셀을 그대로 복사함(모자이크) 필터링을 하지않고 텍스쳐 좌표에서 가장 가까운 정수 주소(address)를 가진 텍셀의 색을 카피함, 텍스쳐에서 문자를 표시하거나 외곽선이 뭉개지지 않을경우에 사용 [본문으로]
- (1 - t) * A + t * B일때 t가 0일 경우 결과적으로는 A, point보다 더 부드럽게 나오며 연산량 높음, 텍스쳐 좌표에 가장 가까운 점의 상하 좌우에 있는 텍셀의 평균 가중치를 계산하여 보간함(일반적인 필터링) [본문으로]
- 이방성 필터링, 이방성(물체의 물리적 성질이 방향에 따라 다름) 3D 개체의 표면이 스크린평면과 임의의 각을 이룰때 3D 개체의 텍셀에서 볼 수 있는 왜곡 현상, 텍스쳐도 이러한 성질을 가지고 있는데, Anistorpic필터링은 이 왜곡을 보정하도록 하는 필터링, 가장 깔끔하게 보이지만 성능은 안좋음, (*MSAA(multi-Sampling Anti-Aliasing:멀티샘플링) [본문으로]
- 텍스쳐 좌표를 반복한다. [본문으로]
- 인접한 이미지를 반복한다. [본문으로]
- 텍스쳐 끝 부분의 픽셀이 늘어진다. [본문으로]
- 경계색을 설정한다. [본문으로]
- clamp+mirror모드 [본문으로]
- 확대/축소를 실시했을때 중간 픽셀의 처리 방법을 실시한다
비율이 늘어나고 줄어듬에 따라 빈 공간의 픽셀을 버릴것인지 채울것인지 [본문으로]
'Programming > DirectX 2D' 카테고리의 다른 글
[C++] DirectX Rect&Sprite 1편 [내용 확인] (0) | 2021.11.27 |
---|---|
[C++]DirectX 벡터와 배열과 범위 Array | Scale (0) | 2021.11.23 |
[C++]DirectX 객체 지향과 4대 속성 | What is OOP(Object-Oriented Programming) Four basic concepts (attributes) (0) | 2021.11.23 |