三次贝塞尔曲面

三次贝尔赛曲面

基于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;
}

实现效果


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章