三次贝尔赛曲面
基于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;
}