三次貝塞爾曲面

三次貝爾賽曲面

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

實現效果


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