您的位置:首页 > 其它

Muli3D <8> 计算Shader中顶点属性相对于屏幕坐标的偏导数

2017-05-03 21:03 441 查看
记录一下,

在Muli3D中看到这样一个函数:

/// This functions computes the partial derivatives of a shader register with respect to the screen space coordinates.
/// @param[in] i_iRegister index of the source shader register.
/// @param[out] o_vDdx partial derivative with respect to the x-screen space coordinate.
/// @param[out] o_vDdy partial derivative with respect to the y-screen space coordinate.
void GetDerivatives( uint32 i_iRegister, vector4 &o_vDdx, vector4 &o_vDdy ) const;

// Partial derivative equations taken from
// "MIP-Map Level Selection for Texture Mapping",
// Jon P. Ewins, Member, IEEE, Marcus D. Waller,
// Martin White, and Paul F. Lister, Member, IEEE

void IMuli3DPixelShader::GetDerivatives( uint32 i_iRegister, vector4 &o_vDdx, vector4 &o_vDdy ) const
{
o_vDdx = vector4( 0, 0, 0, 0 );
o_vDdy = vector4( 0, 0, 0, 0 );
if( i_iRegister < 0 || i_iRegister >= c_iPixelShaderRegisters )
return;

const shaderreg &A = m_pTriangleInfo->ShaderOutputsDdx[i_iRegister];
const shaderreg &B = m_pTriangleInfo->ShaderOutputsDdy[i_iRegister];
// ShaderOutputs : Vertex shader output registers
const shaderreg &C = m_pTriangleInfo->pBaseVertex->ShaderOutputs[i_iRegister];

const float32 D = m_pTriangleInfo->fWDdx;
const float32 E = m_pTriangleInfo->fWDdy;
const float32 F = m_pTriangleInfo->pBaseVertex->vPosition.w;

const float32 fRelPixelX = m_pTriangleInfo->iCurPixelX - m_pTriangleInfo->pBaseVertex->vPosition.x;
const float32 fRelPixelY = m_pTriangleInfo->iCurPixelY - m_pTriangleInfo->pBaseVertex->vPosition.y;
const float32 fInvWSquare = m_pTriangleInfo->fCurPixelInvW * m_pTriangleInfo->fCurPixelInvW;

// Compute partial derivative with respect to the x-screen space coordinate.
switch( m_pVSOutputs[i_iRegister] )
{
case m3dsrt_vector4:
o_vDdx.w = ( (A.w * F - C.w * D) + (A.w * E - B.w * D) * fRelPixelY ) * fInvWSquare;
case m3dsrt_vector3:
o_vDdx.z = ( (A.z * F - C.z * D) + (A.z * E - B.z * D) * fRelPixelY ) * fInvWSquare;
case m3dsrt_vector2:
o_vDdx.y = ( (A.y * F - C.y * D) + (A.y * E - B.y * D) * fRelPixelY ) * fInvWSquare;
case m3dsrt_float32:
o_vDdx.x = ( (A.x * F - C.x * D) + (A.x * E - B.x * D) * fRelPixelY ) * fInvWSquare;
case m3dsrt_unused:
default:
break;
}

// Compute partial derivative with respect to the y-screen space coordinate.
switch( m_pVSOutputs[i_iRegister] )
{
case m3dsrt_vector4:
o_vDdy.w = ( (B.w * F - C.w * E) + (B.w * D - A.w * E) * fRelPixelX ) * fInvWSquare;
case m3dsrt_vector3:
o_vDdy.z = ( (B.z * F - C.z * E) + (B.z * D - A.z * E) * fRelPixelX ) * fInvWSquare;
case m3dsrt_vector2:
o_vDdy.y = ( (B.y * F - C.y * E) + (B.y * D - A.y * E) * fRelPixelX ) * fInvWSquare;
case m3dsrt_float32:
o_vDdy.x = ( (B.x * F - C.x * E) + (B.x * D - A.x * E) * fRelPixelX ) * fInvWSquare;
case m3dsrt_unused:
default:
break;
}
}


从函数的注释可以知道,这个函数主要的作用就是 《This functions computes the partial derivatives of a shader register with respect to the screen space coordinates.》

上面的 shader register,可以理解为 VS 输出的值的位置索引,那么这个就是计算 VS 输出的 值 关于 屏幕坐标x,y的偏导数,例如,VS输出了纹理左边,那么就可以计算出纹理坐标关于 屏幕坐标x,y的偏导数。

上面的代码其实就是一堆公式,下面的推导主要根据上面的注释提示的文章<MIP-Map Level Selection for Texture Mapping>和自己的一些理解:

现在用纹理坐标作为例子

1.

理解:深入探索透视纹理映射 : http://blog.csdn.net/aa20274270/article/details/51989103

知道 

s' = S / Q 

t' = T / Q

(如何理解,s' , t' 就是 投影变换之后 的 纹理坐标,s',t' 是与 1/z’ 成正比,这里的Q就是 z‘)

这里的S ,T 是与 x,y 与线性关系的, Q是z',那么也是与x,y 成线性关系的

得到

S = A * x + B * y + C

T = G * x + H * y + I

Q = D * x + E * y + F

现在 要求

∂s‘ / ∂x

 =
∂(S / Q) /  ∂x

 = ∂(   (A * x + B * y + C) / ( D * x + E * y +
F) ) / ∂x    (根据   (u/v)'=(u'v-uv')/ v^2
  ,把y 当 常量得到就是 )

=
   (A * x + B * y + C)' * ( D
* x + E * y + F) -  (A * x + B * y
+ C) *  ( D * x + E * y + F) ' 
 / Q^2

=
 A *  ( D * x + E * y + F)
-  (A * x + B * y + C) * D /  Q^2

 =
( (AE - BD) * y + AF - CD ) / Q^2

而对于 ∂s‘ / ∂y, 计算方式是一样的。

直接给出

∂s‘ / ∂y 

=  ( (BD
- AE) * x + BF - CE ) / Q^2



上面的

A, B, C, D, E, F ....其实都是未知的,那么怎么求这些东西,

个人理解:

理解完 Partial Derivatives(偏导数) : http://blog.csdn.net/aa20274270/article/details/70158853

之后,就可以理解到

其实上面的

S = A * x + B * y + C    -->   S = ∂S / ∂x * x  +  ∂S
/ ∂y  *  y  +  S0

Q
= D * x + E * y + F    -->   Q =
∂Q / ∂x * x  +  ∂Q / ∂y  *  y  +  Q0 

对应T也是一样的道理,现在应该差不多可以理解了吧。

上面的事那纹理坐标ST做例子,其实,对于任何的
与 x,y 成线性关系的东西,其实都是可以利用上面的来计算。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  3D数学