DirectX11 渲染 学习笔记(2) 纹理/贴图映射

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/alex1997222/article/details/78090802

一个纹理就是映射到我们的图形和实体表面的数据

通常此数据是颜色值,它通过一种叫做纹理映射的处理,将一张图像映射到物体表面

纹理和其他游戏资源一样 将会在运行时载入。使用函数 D3D11CreateTextureFromFile

    D3DX11CreateTextureFromFileA(
        ID3D11Device*               pDevice,     //设备驱动
        LPCSTR                      pSrcFile,    //图像数据文件路径
        D3DX11_IMAGE_LOAD_INFO      *pLoadInfo,  //图像信息结构
        ID3DX11ThreadPump*          pPump,       //线程pump
        ID3D11Resource**            ppTexture,   //通过外部图片所加载的纹理对象地址调用 成功会有一个加载好的纹理
        HRESULT*                    pHResult);   

主要存在3类纹理接口

ID3D11Texture1D   处理1D或图像条类型纹理
ID3D11Texture2D   处理2D图像数据

ID3D11Texture3D   处理3D(表示体积) 图像数据


纹理贴图中的每个像素叫做纹理元素, 一个纹理元素对应一个RGB值

MIP分级机制是在相同的纹理下依次向低级别的版本递减

根据远近不同使用合适的分辨率

根据放大Magnification缩小Minification系数来决定物体的渲染程度


纹理的细节

有时需要知道来自载入的纹理的细节信息 比如尺寸和像素格式  描述结构体如下

typedef struct D3D11_TEXTURE2D_DESC
    {
    UINT Width;
    UINT Height;
    UINT MipLevels;
    UINT ArraySize;
    DXGI_FORMAT Format;
    DXGI_SAMPLE_DESC SampleDesc;
    D3D11_USAGE Usage;
    UINT BindFlags;
    UINT CPUAccessFlags;
    UINT MiscFlags;
    } 	D3D11_TEXTURE2D_DESC;


着色器资源视图:用于访问资源的着色器对象

ID3D11ShaderResourceView* colorMap_;
当我们载入图像到内存时,需要创建一个着色器资源视图对象

用于通过一个着色器来访问数据


采样状态变量:

一个采样状态允许我们访问一个纹理的采样状态信息

ID3D11SamplerState* colorMapSampler_;

创建纹理所需的变量:

我们执行纹理映射,需要更新顶点结构使得包含两个浮点变量用于TU和TV贴图坐标

	D3D11_INPUT_ELEMENT_DESC solidColorLayout[]{
		{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
		{ "TEXCOORD" , 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }   //用于贴图坐标
	};


整个加载函数如下:

bool TextureDemo::LoadContent() {
	ID3DBlob* vsBuffer = 0;

	bool compileResult = compileD3DShader("SolidGreenColor.fx", "VS_Main", "vs_4_0", &vsBuffer);   //着色器编译 就是设置颜色
	if (compileResult == false) {
		MessageBox(0, "error loading vertex shader!!", "ERROR", MB_OK);
		return false;
	}

	//创建定点渲染
	HRESULT d3dResult;
	d3dResult = d3dDevice_->CreateVertexShader(vsBuffer->GetBufferPointer(), vsBuffer->GetBufferSize(), 0, &solidColorVS_);
	if (FAILED(d3dResult)) {
		if (vsBuffer)
			vsBuffer->Release();
		return false;    
	}

	/*。。。。。贴图的设置。。。。。*/
	D3D11_INPUT_ELEMENT_DESC solidColorLayout[]{
		{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
		{ "TEXCOORD" , 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }   //用于贴图坐标
	};

	unsigned int totalLayoutElements = ARRAYSIZE(solidColorLayout);

	d3dResult = d3dDevice_->CreateInputLayout(solidColorLayout, totalLayoutElements, vsBuffer->GetBufferPointer(), vsBuffer->GetBufferSize(), &inputLayout_);

	vsBuffer->Release();
	if (FAILED(d3dResult)) {
		return false;
	}
	
	//像素着色器设置
	ID3DBlob* psBuffer = 0;
	compileResult = compileD3DShader("SolidGreenColor.fx", "VS_Main", "vs_4_0", &psBuffer);
	if (compileResult == false) {
		MessageBox(0, "error loading pixel shader!!", "ERROR", MB_OK);
		return;
	}

	d3dResult = d3dDevice_->CreatePixelShader(vsBuffer->GetBufferPointer(), vsBuffer->GetBufferSize(), 0, &solidColorPS_);

	psBuffer->Release();
	if (FAILED(d3dResult)) {
		return false;
	}

	VertexPos vertices[]{

	{XMFLOAT3(1.0f, 1.0f, 1.0f), XMFLOAT2(1.0f,1.0f)},
	{XMFLOAT3(1.0f, -1.0f, 1.0f), XMFLOAT2(1.0f,0.0f)},
	{XMFLOAT3(-1.0f,-1.0f, 1.0f), XMFLOAT2(0.0f,0.0f)},
	{XMFLOAT3(-1.0f,-1.0f, 1.0f), XMFLOAT2(0.0f,0.0f)},
	{XMFLOAT3(-1.0f, 1.0f, 1.0f), XMFLOAT2(0.0f,1.0f)},
	{XMFLOAT3(1.0f, 1.0f, 1.0f), XMFLOAT2(1.0f,1.0f)}

	};

	//创建顶点缓存
	D3D11_BUFFER_DESC vertexDesc;
	ZeroMemory(&vertexDesc, sizeof(vertexDesc));

	vertexDesc.Usage = D3D11_USAGE_DEFAULT;
	vertexDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
	vertexDesc.ByteWidth = sizeof(vertexDesc) * 3;

	D3D11_SUBRESOURCE_DATA resourceData;
	ZeroMemory(&resourceData, sizeof(resourceData));

	resourceData.pSysMem = vertices;

	d3dResult = d3dDevice_->CreateBuffer(&vertexDesc, &resourceData, &vertexBuffer_);

	if (FAILED(d3dResult)) {
		return false;
	}

	//创建资源着色器视图
	d3dResult = D3DX11CreateShaderResourceViewFromFile(d3dDevice_, "decal.dds", 0, 0, &colorMap_, 0);

	if (FAILED(d3dResult)) {
		DXTRACE_MSG("Error loading resource view from file!!..");
		return false;
	}

    //。。。Continue。。。
	D3D11_SAMPLER_DESC colorMapDesc;
	ZeroMemory(&colorMapDesc, sizeof(colorMapDesc));   //清空内存
	
	colorMapDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;  
	colorMapDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
	colorMapDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;

	colorMapDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
	colorMapDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
	colorMapDesc.MaxLOD = D3D11_FLOAT32_MAX;

	d3dResult = d3dDevice_->CreateSamplerState(&colorMapDesc, &colorMapSampler_);
	
	if (FAILED(d3dResult)) {
		DXTRACE_MSG("Error loading sampler State");
		return false;
	}

	return true;
}


以上函数载入我们的贴图图像

载入和创建一个资源着色器对象:D3DX11CreateShaderResourceViewFromFile

HRESULT WINAPI
    D3DX11CreateTextureFromFileA(
        ID3D11Device*               pDevice,
        LPCSTR                      pSrcFile,
        D3DX11_IMAGE_LOAD_INFO      *pLoadInfo,
        ID3DX11ThreadPump*          pPump,
        ID3D11Resource**            ppTexture,
        HRESULT*                    pHResult);


设置采样状态;

D3D11_SAMPLER_DESC
    {
    D3D11_FILTER Filter;
    D3D11_TEXTURE_ADDRESS_MODE AddressU;
    D3D11_TEXTURE_ADDRESS_MODE AddressV;
    D3D11_TEXTURE_ADDRESS_MODE AddressW;
    FLOAT MipLODBias;
    UINT MaxAnisotropy;
    D3D11_COMPARISON_FUNC ComparisonFunc;
    FLOAT BorderColor[ 4 ];
    FLOAT MinLOD;
    FLOAT MaxLOD;
    } 	D3D11_SAMPLER_DESC;

上述结构指定采样纹理怎样过滤,纹理过滤描述从源数据怎样被读取和联合,使得用于着色器


多种采样方式:

点采样: 直接从纹理中取得单一的值作为采样结果,而不进行修改。映射在某像素周围最接近该像素的纹理元素

双线性采样:使得的纹理渲染效果更加平滑,减少渲染中的人为现象(就是锯齿效果)

三线性采样:物体远离或者靠近时,表面纹理能够平滑过渡

各向异性采样:不同的角度采用不同的处理方式


贴图地址模式:

    D3D11_TEXTURE_ADDRESS_MODE AddressU;    
    D3D11_TEXTURE_ADDRESS_MODE AddressV;
    D3D11_TEXTURE_ADDRESS_MODE AddressW;


纹理坐标值指定在一定范围内纹理的各个尺寸

纹理坐标范围指定处理超出范围的纹理的处理方式


纹理坐标模式:

enum D3D11_TEXTURE_ADDRESS_MODE
    {	D3D11_TEXTURE_ADDRESS_WRAP	= 1,
	D3D11_TEXTURE_ADDRESS_MIRROR	= 2,
	D3D11_TEXTURE_ADDRESS_CLAMP	= 3,
	D3D11_TEXTURE_ADDRESS_BORDER	= 4,
	D3D11_TEXTURE_ADDRESS_MIRROR_ONCE	= 5
    } 	D3D11_TEXTURE_ADDRESS_MODE;

重复将导致贴图重复使用于周围。例如,有一个正方形区域,将一张贴图在区域的水平方向重复显示两次

只需指定最右边的顶点U贴图坐标分量为20即可


镜像(MIRROR)将会导致贴图以镜像形式重复,这里CLAMP将会简单的使值在0.0-1.0的范围

CLAMP将会简单的使值在0.0 - 1.0 的范围 

MIRROR_ONCE 将会使得贴图的镜像形式出现一次

而MIRROR将会使用指定的镜像次数

BORDER 地址模式将会设置任何在0.0 - 1.0 范围之外的像素一个指定的边界颜色


添加贴图资源和设置采样状态:

PPSetShaderResource 和 PSSetSamplers

        virtual void STDMETHODCALLTYPE PSSetShaderResources( 
            /* [annotation] */ 
            __in_range( 0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT - 1 )  UINT StartSlot,  //开始插入资源
            /* [annotation] */ 
            __in_range( 0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT - StartSlot )  UINT NumViews,  //资源的数量
            /* [annotation] */ 
            __in_ecount(NumViews)  ID3D11ShaderResourceView *const *ppShaderResourceViews) = 0;    //资源数组

渲染代码如下:

void TextureDemo::Render() {

	if (d3dContext_ == 0)
		return;

	float clearColor[4] = { 0.0f, 0.0f, 0.25f, 1.0f };
	d3dContext_->ClearRenderTargetView(backBufferTarget_, clearColor);

	unsigned int stride = sizeof(VertexPos);
	unsigned int offset = 0;     //偏移量为0

	d3dContext_->IASetInputLayout(inputLayout_);
	d3dContext_->IASetVertexBuffers(0, 1, &vertexBuffer_, &stride, &offset);   

	d3dContext_->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

	d3dContext_->VSSetShader(solidColorVS_, 0, 0);
	d3dContext_->PSSetShader(solidColorPS_, 0, 0);

	//添加贴图资源和设置采样状态
	d3dContext_->PSSetShaderResources(0, 1, &colorMap_);
	d3dContext_->PSSetSamplers(0, 1, &colorMapSampler_);

	d3dContext_->Draw(6, 0);

	swapChain_->Present(0, 0);
}

着色器对象分别是colorMap_ 和 colorSampler_

为了在我们提供的渲染函数中的着色器输入中绑定这些对象 我们必须使用HLSL注册关键字register

用于注册的fx文件代码如下:

/*
    Beginning DirectX 11 Game Programming
    By Allen Sherrod and Wendy Jones

    Texture Mapping Shader
*/


Texture2D colorMap_ : register( t0 );
SamplerState colorSampler_ : register( s0 );


struct VS_Input
{
    float4 pos  : POSITION;
    float2 tex0 : TEXCOORD0;
};

struct PS_Input
{
    float4 pos  : SV_POSITION;
    float2 tex0 : TEXCOORD0;
};


PS_Input VS_Main( VS_Input vertex )
{
    PS_Input vsOut = ( PS_Input )0;
    vsOut.pos = vertex.pos;
    vsOut.tex0 = vertex.tex0;

    return vsOut;
}


float4 PS_Main( PS_Input frag ) : SV_TARGET
{
    return colorMap_.Sample( colorSampler_, frag.tex0 );


















展开阅读全文

没有更多推荐了,返回首页