Esempio n. 1
0
void ParametricSurface<Real>::ComputePrincipalCurvatureInfo (Real u, Real v,
        Real& curv0, Real& curv1, Vector3<Real>& dir0,
        Vector3<Real>& dir1)
{
	// Tangents:  T0 = (x_u,y_u,z_u), T1 = (x_v,y_v,z_v)
	// Normal:    N = Cross(T0,T1)/Length(Cross(T0,T1))
	// Metric Tensor:    G = +-                      -+
	//                       | Dot(T0,T0)  Dot(T0,T1) |
	//                       | Dot(T1,T0)  Dot(T1,T1) |
	//                       +-                      -+
	//
	// Curvature Tensor:  B = +-                          -+
	//                        | -Dot(N,T0_u)  -Dot(N,T0_v) |
	//                        | -Dot(N,T1_u)  -Dot(N,T1_v) |
	//                        +-                          -+
	//
	// Principal curvatures k are the generalized eigenvalues of
	//
	//     Bw = kGw
	//
	// If k is a curvature and w=(a,b) is the corresponding solution to
	// Bw = kGw, then the principal direction as a 3D vector is d = a*U+b*V.
	//
	// Let k1 and k2 be the principal curvatures.  The mean curvature
	// is (k1+k2)/2 and the Gaussian curvature is k1*k2.

	// Compute derivatives.
	Vector3<Real> derU = PU(u,v);
	Vector3<Real> derV = PV(u,v);
	Vector3<Real> derUU = PUU(u,v);
	Vector3<Real> derUV = PUV(u,v);
	Vector3<Real> derVV = PVV(u,v);

	// Compute the metric tensor.
	Matrix2<Real> metricTensor;
	metricTensor[0][0] = derU.Dot(derU);
	metricTensor[0][1] = derU.Dot(derV);
	metricTensor[1][0] = metricTensor[0][1];
	metricTensor[1][1] = derV.Dot(derV);

	// Compute the curvature tensor.
	Vector3<Real> normal = derU.UnitCross(derV);
	Matrix2<Real> curvatureTensor;
	curvatureTensor[0][0] = -normal.Dot(derUU);
	curvatureTensor[0][1] = -normal.Dot(derUV);
	curvatureTensor[1][0] = curvatureTensor[0][1];
	curvatureTensor[1][1] = -normal.Dot(derVV);

	// Characteristic polynomial is 0 = det(B-kG) = c2*k^2+c1*k+c0.
	Real c0 = curvatureTensor.Determinant();
	Real c1 = ((Real)2)*curvatureTensor[0][1]* metricTensor[0][1] -
	          curvatureTensor[0][0]*metricTensor[1][1] -
	          curvatureTensor[1][1]*metricTensor[0][0];
	Real c2 = metricTensor.Determinant();

	// Principal curvatures are roots of characteristic polynomial.
	Real temp = Math<Real>::Sqrt(Math<Real>::FAbs(c1*c1 - ((Real)4)*c0*c2));
	Real mult = ((Real)0.5)/c2;
	curv0 = -mult*(c1+temp);
	curv1 = mult*(-c1+temp);

	// Principal directions are solutions to (B-kG)w = 0,
	// w1 = (b12-k1*g12,-(b11-k1*g11)) OR (b22-k1*g22,-(b12-k1*g12)).
	Real a0 = curvatureTensor[0][1] - curv0*metricTensor[0][1];
	Real a1 = curv0*metricTensor[0][0] - curvatureTensor[0][0];
	Real length = Math<Real>::Sqrt(a0*a0 + a1*a1);
	if (length >= Math<Real>::ZERO_TOLERANCE)
	{
		dir0 = a0*derU + a1*derV;
	}
	else
	{
		a0 = curvatureTensor[1][1] - curv0*metricTensor[1][1];
		a1 = curv0*metricTensor[0][1] - curvatureTensor[0][1];
		length = Math<Real>::Sqrt(a0*a0 + a1*a1);
		if (length >= Math<Real>::ZERO_TOLERANCE)
		{
			dir0 = a0*derU + a1*derV;
		}
		else
		{
			// Umbilic (surface is locally sphere, any direction principal).
			dir0 = derU;
		}
	}
	dir0.Normalize();

	// Second tangent is cross product of first tangent and normal.
	dir1 = dir0.Cross(normal);
}
Esempio n. 2
0
Void TriangleMesh::UpdateTangentsFromGeometry( GPUDeferredContext * pContext )
{
    Assert( m_pIL != NULL && m_pVB != NULL );
    Assert( m_pIL->IsBound() && m_pVB->IsBound() );

    Bool bHasNormals = m_pIL->HasField( GPUINPUTFIELD_SEMANTIC_NORMAL, 0 );
    if ( !bHasNormals )
        return;
    Bool bHasTangents =  m_pIL->HasField( GPUINPUTFIELD_SEMANTIC_TANGENT, 0 );
    Bool bHasBiNormals = m_pIL->HasField( GPUINPUTFIELD_SEMANTIC_BINORMAL, 0 );
    if ( !bHasTangents && !bHasBiNormals )
        return;

    // Begin update
    Byte * pFirstVertex = NULL;
    if ( m_pVB->CanUpdate() ) {
        Assert( m_pVB->HasCPUData() );
        pFirstVertex = m_pVB->GetData( m_iVertexOffset );
    } else {
        Assert( m_pVB->CanLock() );
        UInt iByteSize = 0;
        pFirstVertex = (Byte*)( m_pVB->Lock( GPURESOURCE_LOCK_WRITE, 0, &iByteSize, pContext ) );
        Assert( iByteSize == m_pVB->GetSize() );
    }

    // Update
    UInt iVertexSize = m_pVB->GetElementSize();

    UInt iOffset, iSize;
    const Byte * arrPositions = NULL;
    const Byte * arrNormals = NULL;
    Byte * arrTangents = NULL;
    Byte * arrBiNormals = NULL;

    m_pIL->GetFieldRange( &iOffset, &iSize, GPUINPUTFIELD_SEMANTIC_POSITION, 0 );
    arrPositions = ( pFirstVertex + iOffset );
    m_pIL->GetFieldRange( &iOffset, &iSize, GPUINPUTFIELD_SEMANTIC_NORMAL, 0 );
    arrNormals = ( pFirstVertex + iOffset );
    if ( bHasTangents ) {
        m_pIL->GetFieldRange( &iOffset, &iSize, GPUINPUTFIELD_SEMANTIC_TANGENT, 0 );
        arrTangents = ( pFirstVertex + iOffset );
    }
    if ( bHasBiNormals ) {
        m_pIL->GetFieldRange( &iOffset, &iSize, GPUINPUTFIELD_SEMANTIC_BINORMAL, 0 );
        arrBiNormals = ( pFirstVertex + iOffset );
    }

    UInt i, iTriangleCount = GetTriangleCount();

        // Start using temp storage
    RenderingFn->SelectMemory( TEXT("Scratch") );
    Matrix4 * arrDerivateNormals = New Matrix4[m_iVertexCount];

        // Compute derivate normals (dN/dX)
    _ComputeDerivateNormals( arrDerivateNormals, m_iVertexCount, iTriangleCount,
                             arrPositions, arrNormals, iVertexSize );

        // Perform update
    const Vector4 * pNormal;
    Vector4 *pTangent, *pBiNormal;

    Vector4 vU, vV;
    Scalar fS01, fS10, fSAvg;
    Matrix2 matS;
    Scalar fTrace, fDet, fDiscr, fRootDiscr;
    Scalar fMinCurvature; //, fMaxCurvature;
    Vector2 vEigen0, vEigen1;
    Vector4 vTangent, vBinormal;

    for( i = 0; i < m_iVertexCount; ++i ) {
        iOffset = ( i * iVertexSize );
        pNormal = (const Vector4 *)( arrNormals + iOffset );

        // Compute J = [U V] such that (U,V,N) is orthonormal
        Vector4::MakeComplementBasis( vU, vV, *pNormal );

        // Compute shape matrix S = tJ * dN/dX * J, enforce symmetry
        fS01 = ( vU * (arrDerivateNormals[i] * vV) );
        fS10 = ( vV * (arrDerivateNormals[i] * vU) );
        fSAvg = ( fS01 + fS10 ) * 0.5f;
        matS.m00 = ( vU * (arrDerivateNormals[i] * vU) ); matS.m01 = fSAvg;
        matS.m10 = fSAvg;                                 matS.m11 = ( vV * (arrDerivateNormals[i] * vV) );

        // Eigenvalues of S are principal curvatures (k0 and k1)
        fTrace = ( matS.m00 + matS.m11 );
        fDet = matS.Determinant();
        fDiscr = ( fTrace * fTrace - 4.0f * fDet );
        fRootDiscr = MathFn->Sqrt( MathFn->Abs(fDiscr) );
        fMinCurvature = (fTrace - fRootDiscr) * 0.5f;
        //fMaxCurvature = (fTrace + fRootDiscr) * 0.5f;

        // Eigenvectors of S (W0 and W1)
        vEigen0.X = matS.m01;
        vEigen0.Y = fMinCurvature - matS.m00;
        vEigen1.X = fMinCurvature - matS.m11;
        vEigen1.Y = matS.m10;

        // Deduce principal directions (S*W=k*W => k=J*W) and assign them as tangent & binormal
        if ( vEigen0.NormSqr() >= vEigen1.NormSqr() ) {
            vEigen0.Normalize();
            vTangent = ( (vU * vEigen0.X) + (vV * vEigen0.Y) );
            vBinormal = ( (*pNormal) ^ vTangent );
        } else {
            vEigen1.Normalize();
            vTangent = ( (vU * vEigen1.X) + (vV * vEigen1.Y) );
            vBinormal = ( (*pNormal) ^ vTangent );
        }

        // Update
        if ( bHasTangents ) {
            pTangent = (Vector4*)( arrTangents + iOffset );
            *pTangent = vTangent;
        }
        if ( bHasBiNormals ) {
            pBiNormal = (Vector4*)( arrBiNormals + iOffset );
            *pBiNormal = vBinormal;
        }
    }

        // End using temp storage
    DeleteA( arrDerivateNormals );

    RenderingFn->UnSelectMemory();

    // End update
    if ( m_pVB->CanUpdate() )
        m_pVB->Update( 0, INVALID_OFFSET, pContext );
    else
        m_pVB->UnLock( pContext );
}