Directx11教程二十七之Tessellation(曲面细分)

先看看本节教程的结构吧




一,曲面细分的介绍。

 这里先链接一篇关于曲面细分的文章  http://blog.csdn.net/qq_29523119/article/details/52914370,算是对曲面细分大概的科普吧.
这里看此放出D3D11的3D渲染管线图:



看红色画圈部分的都属于“Tessellation(曲面细分阶段)”,分别为:HullShader(HS) Stage,TessellatorStage,DomainShader(DS)Stage,

D3D11程序普通情况下渲染管线的流程是:



加入曲面细分后,渲染流程变为:




放出Shader代码:

ColorShader.fx
/*-------------常量缓存---------------------*/
cbuffer CBMatrix:register(b0)
{
	matrix World;
	matrix View;
	matrix Proj;
};


cbuffer CBTessellation:register(b1)
{
	float TessellationAmount;
	float3 pad;
};



/*--------------各个阶段输入输出的结构体--------------------*/


//从IA阶段输出的
struct VertexIn
{
	float3 Pos:POSITION;
	float4 color:COLOR;
};


//从VertexShader输出的
struct HullIn
{
	float3 Pos:POSITION;
	float4 color:COLOR;
};


//从HullShader输出的
struct DomainIn
{
	float3 Pos:POSITION;
	float4 color:COLOR;
};


//从DomainShader输出的
struct PixelIn
{
	float4 Pos:SV_POSITION;
	float4 color:COLOR;
};








/*--------------各个Shader阶段的函数--------------------*/

/*VertexShader*/
HullIn VS(VertexIn ina)
{
	HullIn outa;
	
	outa.Pos = ina.Pos;
	outa.color = ina.color;

	return outa;
}


/*HullShader */
//HullShader用到的从补丁常量函数输出的值  三角形
struct ConstantOutputType
{
	float edges[3] : SV_TessFactor;
	float inside : SV_InsideTessFactor;
};

//HullShader补丁常量缓存函数
ConstantOutputType ColorPathConstantFunction(InputPatch<HullIn, 3> inputPatch, uint patchId : SV_PrimitiveID)
{
	ConstantOutputType outa;

	//设置三角形三条边的曲面细分因子
	outa.edges[0] = TessellationAmount;
	outa.edges[1] = TessellationAmount;
	outa.edges[2] = TessellationAmount;

	//设置三角形里面的曲面细分因子
	outa.inside = TessellationAmount;

	return outa;
}




[domain("tri")]    //三角形
[partitioning("integer")]  //整数
[outputtopology("triangle_cw")]  //顺时针
[outputcontrolpoints(3)]  //三个控制点
[patchconstantfunc("ColorPathConstantFunction")]    // 补丁常量缓存函数名
DomainIn HS(InputPatch<HullIn, 3> patch, uint pointId : SV_OutputControlPointID, uint patchId : SV_PrimitiveID)
{
	DomainIn outa;

	//设置HullShader输出的顶点坐标
	outa.Pos = patch[pointId].Pos;

	//设置HullShader输出的颜色
	outa.color = patch[pointId].color;

	return outa;
}


/*DomainShader*/
[domain("tri")]
PixelIn DS(ConstantOutputType input, float3 uvwCoord : SV_DomainLocation, const OutputPatch<DomainIn, 3> patch)
{
	PixelIn outa;
	float3  vertexPosition;

	//获取新顶点的位置
	vertexPosition = uvwCoord.x * patch[0].Pos + uvwCoord.y * patch[1].Pos + uvwCoord.z * patch[2].Pos;

	//将坐标变到齐次裁剪空间
	outa.Pos = mul(float4(vertexPosition, 1.0f), World);
	outa.Pos = mul(outa.Pos, View);
	outa.Pos = mul(outa.Pos, Proj);

	outa.color = patch[0].color;

	return outa;

}


/*PixelShader*/
float4 PS(PixelIn outa) : SV_Target
{
	return outa.color;
}





说说上面HullShader和DomainShader关键字

(1) domain:补丁类型(the patch type),实参可以是tri,quad,或者isoline

(2)partitioning:指定曲面细分的细分模式,实参可以是integer,fractional_even,fractional_odd

(3)outputtopology:通过曲面细分新创建的三角形的绕线方向
   (a) triangle_cw:顺时针绕线方向
   (b)triangle_ccw:逆时针绕线方向
   (c)line: 线性曲面细分

(4) outputcontrolpoints:HullShader(外壳着色器)执行的次数,每次输出一个控制点.系统值SV_OutputControlPointID给予了一个下标值,这个下标值标识了HullShader(外壳着色器)正在处理的输出控制点(0utputControlpoint)

(5)patchconstantfunc(补丁常量函数):HullShader常量函数的函数名字,为一个字符串

(6)maxtessfactor:驱动的控制线索指定了你的着色器可以使用的最大的曲面细分因子。如果知道这个值的上限,可以通过硬件进行潜在的优化,因此这个因子指明了曲面细分需要使用多少资源。被D3D11硬件支持最大的曲面细分因子为64.


三角形补丁曲面细分的例子(Triangle Patch Tessellation examples):






四边形补丁曲面细分的例子(Quad Patch Tessellation examples):






创建VertexShader,PixelShader,HullShader,DomainShader

bool ColorShaderClass::InitializeShader(ID3D11Device* d3dDevice, HWND hwnd, WCHAR* VSFileName, WCHAR* PSFileName, WCHAR* HSFileName, WCHAR* DSFileName)
{
	HRESULT result;
	ID3D10Blob* errorMessage;
	ID3D10Blob* VertexShaderBuffer;  
	ID3D10Blob* PixelShaderBuffer;
	ID3D10Blob* HullShaderBuffer;
	ID3D10Blob* DomainShaderBuffer;
	
	//第一,初始化参数
	errorMessage = NULL;
    VertexShaderBuffer=NULL;
	PixelShaderBuffer=NULL;

	//第二,编译VertexShader代码,并创建VertexShader
	result = D3DX11CompileFromFile(VSFileName, NULL, NULL, "VS", "vs_5_0", D3DCOMPILE_ENABLE_STRICTNESS, 0, NULL, &VertexShaderBuffer, &errorMessage, NULL);
	if (FAILED(result))
	{
		//存在错误信息
		if (errorMessage)
		{
			OutputShaderErrorMessage(errorMessage, hwnd, VSFileName);
		}
		//不存在错误信息,也就是没有找到Shader文件
		else
		{
			MessageBox(hwnd, L"can not find VS file", L"error", MB_OK);
		}
	}

	HR(d3dDevice->CreateVertexShader(VertexShaderBuffer->GetBufferPointer(),VertexShaderBuffer->GetBufferSize(),NULL,&md3dVertexShader));
	


	//第三,编译HullShader,并创建HullShader
	result = D3DX11CompileFromFile(HSFileName, NULL, NULL, "HS", "hs_5_0", D3DCOMPILE_ENABLE_STRICTNESS, 0, NULL, &HullShaderBuffer, &errorMessage, NULL);
	if (FAILED(result))
	{
		//存在错误信息
		if (errorMessage)
		{
			OutputShaderErrorMessage(errorMessage, hwnd, HSFileName);
		}
		//不存在错误信息,也就是没有找到Shader文件
		else
		{
			MessageBox(hwnd, L"can not find HS file", L"error", MB_OK);
		}
	}

	HR(d3dDevice->CreateHullShader(HullShaderBuffer->GetBufferPointer(), HullShaderBuffer->GetBufferSize(), NULL, &md3dHullShader));



	//第四,编译HullShader,并创建DomainShader
	result = D3DX11CompileFromFile(DSFileName, NULL, NULL, "DS", "ds_5_0", D3DCOMPILE_ENABLE_STRICTNESS, 0, NULL, &DomainShaderBuffer, &errorMessage, NULL);
	if (FAILED(result))
	{
		//存在错误信息
		if (errorMessage)
		{
			OutputShaderErrorMessage(errorMessage, hwnd, DSFileName);
		}
		//不存在错误信息,也就是没有找到Shader文件
		else
		{
			MessageBox(hwnd, L"can not find DS file", L"error", MB_OK);
		}
	}

	HR(d3dDevice->CreateDomainShader(DomainShaderBuffer->GetBufferPointer(), DomainShaderBuffer->GetBufferSize(), NULL, &md3dDomainShader));




	//第五,编译PixelShader,并创建PixelShader
	result = D3DX11CompileFromFile(PSFileName, NULL, NULL, "PS", "ps_5_0", D3DCOMPILE_ENABLE_STRICTNESS, 0, NULL, &PixelShaderBuffer, &errorMessage, NULL);
	if (FAILED(result))
	{
		//存在错误信息
		if (errorMessage)
		{
			OutputShaderErrorMessage(errorMessage, hwnd, PSFileName);
		}
		//不存在错误信息,也就是没有找到Shader文件
		else
		{
			MessageBox(hwnd, L"can not find PS file", L"error", MB_OK);
		}
	}

	HR(d3dDevice->CreatePixelShader(PixelShaderBuffer->GetBufferPointer(), PixelShaderBuffer->GetBufferSize(), NULL, &md3dPixelShader))



	//第六,填充输入布局形容结构体,创建输入布局
	D3D11_INPUT_ELEMENT_DESC VertexInputLayout[] =
	{
		{ "POSITION",0,DXGI_FORMAT_R32G32B32_FLOAT,0,0,D3D11_INPUT_PER_VERTEX_DATA,0 }, // 96位即12个字节
		{ "COLOR",0,DXGI_FORMAT_R32G32B32A32_FLOAT,0,12,D3D11_INPUT_PER_VERTEX_DATA,0 },
	};

	unsigned int numElements = sizeof(VertexInputLayout) / sizeof(VertexInputLayout[0]);         //布局数量
	
	HR(d3dDevice->CreateInputLayout(VertexInputLayout, numElements, VertexShaderBuffer->GetBufferPointer(), VertexShaderBuffer->GetBufferSize(), &md3dInputLayout));

	//第七,释放VertexShaderBuffer和PixelShaderBuffer
	VertexShaderBuffer->Release();
	VertexShaderBuffer = NULL;
	PixelShaderBuffer->Release();
	PixelShaderBuffer = NULL;

	//第八,设置矩阵(常量)缓存形容结构体,并创建矩阵常量缓存
	D3D11_BUFFER_DESC matrixBufferDesc;
	ZeroMemory(&matrixBufferDesc, sizeof(matrixBufferDesc));
	matrixBufferDesc.Usage = D3D11_USAGE_DEFAULT;
	matrixBufferDesc.ByteWidth = sizeof(CBMatrix);   //结构体大小,必须为16字节倍数
	matrixBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
	matrixBufferDesc.CPUAccessFlags = 0; 

	HR(d3dDevice->CreateBuffer(&matrixBufferDesc, NULL, &mCBMatrixBuffer));


	//第九,设置曲面细分(常量)缓存形容结构体,并创建曲面细分常量缓存
	D3D11_BUFFER_DESC TesselationBufferDesc;
	ZeroMemory(&TesselationBufferDesc, sizeof(TesselationBufferDesc));
	TesselationBufferDesc.Usage = D3D11_USAGE_DEFAULT;
	TesselationBufferDesc.ByteWidth = sizeof(CBTessellation);   //结构体大小,必须为16字节倍数
	TesselationBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
	TesselationBufferDesc.CPUAccessFlags = 0;

	HR(d3dDevice->CreateBuffer(&TesselationBufferDesc, NULL, &mCBTessellationBuffer));
    return true;
}


设定 VertexShader,PixelShader,HullShader,DomainShader

void ColorShaderClass::RenderShader(ID3D11DeviceContext* deviceContext, int indexCount)
{
	//设置顶点输入布局
	deviceContext->IASetInputLayout(md3dInputLayout);

	//设置VertexShader,PixelShader,hullShader,DomainShader
	deviceContext->VSSetShader(md3dVertexShader, NULL, 0);
	deviceContext->PSSetShader(md3dPixelShader, NULL, 0);
	deviceContext->HSSetShader(md3dHullShader, NULL, 0);
	deviceContext->DSSetShader(md3dDomainShader, NULL, 0);

	//渲染三角形
	deviceContext->DrawIndexed(indexCount, 0, 0);
}



这里我的EdgeTess和InsideTess都是4

程序运行图:






下面放出我的源代码链接:

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值