您的位置:首页 > 其它

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

2016-10-27 01:18 288 查看
先看看本节教程的结构吧



一,曲面细分的介绍。

 这里先链接一篇关于曲面细分的文章 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

程序运行图:



下面放出我的源代码链接:
http://download.csdn.net/detail/qq_29523119/9665102
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: