三次貝爾賽曲面
基於DirectX11的曲面細分章節實現的矩形的三次貝塞爾曲面,特此做下筆記
一個矩陣,可以分爲水平方向和垂直方向,分別做貝塞爾曲線。
一個4*4控制點的面片,第i行的貝塞爾曲線函數
通過對每一行的貝塞爾曲線的基礎上,對同一列做列貝塞爾曲線,其中控制點p是行貝塞爾曲線的座標;
將所有列曲線上的頂點求出後,求得到了貝塞爾曲面。
由於並沒有新的控制點的產生,只是通過將原來的16個控制點求出曲面的控制點,所以該過程在域着色器完成。
對函數求偏導得到切向量和法向量
曲面函數
實現代碼
頂點着色器,外殼着色器只起到傳遞頂點的作用
域着色器
float4 BernsteinBasis(float t)
{
float invT = 1.0f - t;
return float4(
invT*invT*invT,
3*t*invT*invT,
3 * t * t * invT,
t * t * t);
}
float4 dBernsteinBasis(float t)
{
float invT = 1.0f - t;
return float4(
-3* invT * invT,
3 * invT * invT-6*t*invT,
3 * t * invT-3*t*t,
3 * t * t );
}
float3 CubicBezierSum(const OutputPatch<HullOut, 16> patch,float4 Bu,float4 Bv)
{
float3 sum = float3(0, 0, 0);
sum = Bv.x * (Bu.x * patch[0].PosL + Bu.y * patch[1].PosL + Bu.z * patch[2].PosL + Bu.w * patch[3].PosL);
sum += Bv.y * (Bu.x * patch[4].PosL + Bu.y * patch[5].PosL + Bu.z * patch[6].PosL + Bu.w * patch[7].PosL);
sum += Bv.z * (Bu.x * patch[8].PosL + Bu.y * patch[9].PosL + Bu.z * patch[10].PosL + Bu.w * patch[11].PosL);
sum += Bv.w * (Bu.x * patch[12].PosL + Bu.y * patch[13].PosL + Bu.z * patch[14].PosL + Bu.w * patch[15].PosL);
return sum;
}
[domain("quad")]
DS_OUTPUT DS_Bezier(
PatchTessQuad input,
float2 uv : SV_DomainLocation,
const OutputPatch<HullOut, 16> patch)
{
DS_OUTPUT Output;
float4x4 g_ViewProj = mul(g_view, g_proj);
float4 basisU = BernsteinBasis(uv.x);
float4 basisV = BernsteinBasis(uv.y);
float3 v = CubicBezierSum(patch,basisU,basisV);
float4 dbasisU = dBernsteinBasis(uv.x);
float4 dbasisV = dBernsteinBasis(uv.y);
float3 dpdu = CubicBezierSum(patch, dbasisU, basisV);
float3 dpdv = CubicBezierSum(patch, basisU, dbasisV);
Output.normal = cross(dpdu, dpdv);
float4 posW = mul(float4(v, 1.0f), g_world);
Output.posW = posW;
Output.PosH = mul(posW, g_ViewProj);
return Output;
}