Пример #1
0
MQuaternion splineSolverNode::quaternionFromVectors(MVector vec1, MVector vec2)
{
    MVector crosVec = vec1^vec2;
    float w = sqrt((vec1.length() * vec1.length()) * (vec2.length() * vec2.length())) + vec1*vec2;
    //float w = 1.0f + vBaseJoint*vFinalJoint;
    MQuaternion q(crosVec.x, crosVec.y, crosVec.z, w );
    q.normalizeIt();
    return q;
}
Пример #2
0
// COMPUTE ======================================
MStatus gear_uToPercentage::compute(const MPlug& plug, MDataBlock& data)
{
	MStatus returnStatus;
	// Error check
    if (plug != percentage)
        return MS::kUnknownParameter;

	// Curve
	MFnNurbsCurve crv( data.inputValue( curve ).asNurbsCurve() );

	// Sliders
	bool in_normU = data.inputValue( normalizedU ).asBool();
	double in_u = (double)data.inputValue( u ).asFloat();
	unsigned in_steps = data.inputValue( steps ).asShort();

	// Process
	if (in_normU)
		in_u = normalizedUToU(in_u, crv.numCVs());

	// Get length
	MVectorArray u_subpos(in_steps);
	MVectorArray t_subpos(in_steps);
	MPoint pt;
	double step;
	for (unsigned i = 0; i < in_steps ; i++){

		step = i * in_u / (in_steps - 1.0);
		crv.getPointAtParam(step, pt, MSpace::kWorld);
		u_subpos[i] = MVector(pt);

        step = i/(in_steps - 1.0);
		crv.getPointAtParam(step, pt, MSpace::kWorld);
		t_subpos[i] = MVector(pt);

	}
	
	double u_length = 0;
	double t_length = 0;
	MVector v;
	for (unsigned i = 0; i < in_steps ; i++){
		if (i>0){
			v = u_subpos[i] - u_subpos[i-1];
			u_length += v.length();
			v = t_subpos[i] - t_subpos[i-1];
			t_length += v.length();
		}
	}

	double out_perc = (u_length / t_length) * 100;
		
	// Output
    MDataHandle h = data.outputValue( percentage );
    h.setDouble( out_perc );
    data.setClean( plug );

	return MS::kSuccess;
}
Пример #3
0
MStatus VolumePushCollider::compute(const MPlug& plug, MDataBlock& dataBlock)
{
	MStatus status;

	if (plug == aOutput)
	{
		// inCollider
		MArrayDataHandle hInCollider = dataBlock.inputArrayValue(aInCollider);
		// inVolume
		MArrayDataHandle hInVolume = dataBlock.inputArrayValue(aInVolume);
		// output
		MArrayDataHandle hOutput = dataBlock.inputArrayValue(aOutput);
		MDoubleArray daValues(hInVolume.elementCount());

		for (unsigned int c=0; c<hInCollider.elementCount(); c++)
		{
			// Calculate the total of every collider value for each volume
			status = hInCollider.jumpToArrayElement(c);
			CHECK_MSTATUS_AND_RETURN_IT(status);
			MMatrix mInCollider = hInCollider.inputValue().asMatrix();
			MTransformationMatrix tmInCollider(mInCollider);
			MPoint pInCollider = tmInCollider.getTranslation(MSpace::kWorld, &status);
			CHECK_MSTATUS_AND_RETURN_IT(status);

			for (unsigned int v=0; v<hInVolume.elementCount(); v++)
			{
				// pointMatrixMult
				status = hInVolume.jumpToArrayElement(v);
				CHECK_MSTATUS_AND_RETURN_IT(status);
				MMatrix mInVolume = hInVolume.inputValue().asMatrix();
				MVector vVolCollider = pInCollider * mInVolume;
				// condition
				if (vVolCollider.length() <= 1.0)
				{
					// reverse
					daValues[v] += abs(1.0 - vVolCollider.length());
				}
			}
		}
		for (unsigned int i=0; i<hInVolume.elementCount(); i++)
		{
			// set outputs
			status = hOutput.jumpToArrayElement(i);
			CHECK_MSTATUS_AND_RETURN_IT(status);
			hOutput.outputValue().set(daValues[i]);
		}
		dataBlock.setClean(plug);
	}
	return MS::kSuccess;
}
Пример #4
0
void GetValidUp(const MDoubleArray& weights, const MPointArray& points,
                const MIntArray& sampleIds, const MPoint& origin, const MVector& normal,
                MVector& up) {
  MVector unitUp = up.normal();
  // Adjust up if it's parallel to normal or if it's zero length
  if (std::abs((unitUp * normal) - 1.0) < 0.001 || up.length() < 0.0001) {
    for (unsigned int j = 0; j < weights.length()-1; ++j) {
      up -= (points[sampleIds[j]] - origin) * weights[j];
      unitUp = up.normal();
      if (std::abs((unitUp * normal) - 1.0) > 0.001 && up.length() > 0.0001) {
        // If the up and normal vectors are no longer parallel and the up vector has a length,
        // then we are good to go.
        break;
      }
    }
    up.normalize();
  } else {
    up = unitUp;
  }
}
Пример #5
0
double GeometryMath::distanceToSegment(const MVector &segmentStart, const MVector &segmentEnd, const MVector &point,MVector *hitPoint){
	MVector ab = segmentEnd-segmentStart;
	MVector ap = point-segmentStart;

	double dotBoundsTest = ap*ab.normal();
	MVector projection = ab.normal()*dotBoundsTest;
	MVector magnitude = ap-projection;

	if (dotBoundsTest<=0) {
		// return distance start--point
		if (hitPoint)
			*hitPoint = segmentStart;
		return  projection.length()+magnitude.length();
		//return ap.length();
	}

	if (dotBoundsTest>=ab.length()){
		// return distance end--point
		if (hitPoint)
			*hitPoint = segmentEnd;
		return  projection.length()+magnitude.length();

		//MVector bp(point);
		//bp -= segmentEnd;
		//return bp.length();
	}

	if (hitPoint)
		*hitPoint = segmentStart+projection;

	return magnitude.length();
}
Пример #6
0
void CylinderMesh::transform(MPointArray& points, MVectorArray& normals)
{
    MVector forward = mEnd - mStart;
    double s = forward.length();
    forward.normalize();

    MVector left = MVector(0,0,1)^forward;
    MVector up;
    if (left.length() < 0.0001)
    {
        up = forward^MVector(0,1,0);
        left = up^forward;
    }
    else
    {
        up = forward^left;
    }

    MMatrix mat;
    mat[0][0] = forward[0]; mat[0][1] = left[0]; mat[0][2] = up[0]; mat[0][3] = 0;
    mat[1][0] = forward[1];   mat[1][1] = left[1]; mat[1][2] = up[1]; mat[1][3] = 0;
    mat[2][0] = forward[2];   mat[2][1] = left[2]; mat[2][2] = up[2]; mat[2][3] = 0;
    mat[3][0] = 0;            mat[3][1] = 0;       mat[3][2] = 0;     mat[3][3] = 1;
    mat = mat.transpose();

    for (int i = 0; i < gPoints.length(); i++)
    {
        MPoint p = gPoints[i];
        p.x = p.x * s; // scale
        p = p * mat + mStart; // transform
        points.append(p);

        MVector n = gNormals[i] * mat;
        normals.append(n);
    }
}
Пример #7
0
double MG_poseReader::projVector (MVector vec1,MVector vec2)

{

		double proj; 
		float dot = vec1*vec2;
		float vec2L = vec2.length();
		if (vec2L!=0)
		{
		 proj = dot/vec2L;
		}else{
		 proj=0;
		}

		if ((proj<0) || (proj==-0))
			proj=0;
		return proj;
}
Пример #8
0
	// used when ray does not intersect object
	// to account for perspective, all edges are flattened onto 
	// a plane defined by the raySource and rayDirection
	double gpuCacheIsectUtil::getEdgeSnapPointOnTriangle(const MPoint& raySource, const MVector& rayDirection, const MPoint& vert1, const MPoint& vert2, const MPoint& vert3, MPoint& snapPoint){
		MPointArray verts;
		verts.insert(vert1,0);
		verts.insert(vert2,1);
		verts.insert(vert3,2);

		int edgeIndices[3][2]={{0,1},{1,2},{2,0}};

		double minDistTri = std::numeric_limits<double>::max();

		for(int edge=0; edge<3;edge++){
			MPoint vertex1Org = verts[edgeIndices[edge][0]];
			MPoint vertex2Org = verts[edgeIndices[edge][1]];

			double coef_plane = rayDirection * raySource;
			double d = coef_plane - rayDirection * vertex1Org;
			MPoint vertex1 = vertex1Org + rayDirection * d;
			d = coef_plane - rayDirection * vertex2Org;
			MPoint vertex2 = vertex2Org + rayDirection * d;

			MVector edgeDir = vertex2 - vertex1;
			
			if (edgeDir.length()<0.0000001){
				double dist = vertex1.distanceTo(raySource);
				if (dist < minDistTri) {
					minDistTri = dist;
					snapPoint = vertex1Org;
				}
			} else {
				MPoint edgePt;
				// Compute the closest point from the edge to cursor Ray.
				double percent = gpuCacheIsectUtil::getClosestPointOnLine(raySource, vertex1, vertex2, edgePt);
				double dist = edgePt.distanceTo(raySource);                                                            
				if (dist < minDistTri) {
					minDistTri = dist;
					snapPoint =  (vertex1Org + percent * (vertex2Org - vertex1Org));
				}
			}
		}

		return minDistTri;
	}
Пример #9
0
void MVGManipulator::getTranslatedWSEdgePoints(M3dView& view,
                                               const MVGManipulatorCache::EdgeData* originEdgeData,
                                               MPoint& originCSPosition, MPoint& targetWSPosition,
                                               MPointArray& targetEdgeWSPositions) const
{
    assert(originEdgeData != NULL);
    MVector edgeCSVector =
        MVGGeometryUtil::worldToCameraSpace(view, originEdgeData->vertex1->worldPosition) -
        MVGGeometryUtil::worldToCameraSpace(view, originEdgeData->vertex2->worldPosition);
    MVector vertex1ToMouseCSVector =
        originCSPosition -
        MVGGeometryUtil::worldToCameraSpace(view, originEdgeData->vertex1->worldPosition);
    float ratioVertex1 = vertex1ToMouseCSVector.length() / edgeCSVector.length();
    float ratioVertex2 = 1.f - ratioVertex1;

    MVector edgeWSVector =
        originEdgeData->vertex1->worldPosition - originEdgeData->vertex2->worldPosition;
    targetEdgeWSPositions.append(targetWSPosition + ratioVertex1 * edgeWSVector);
    targetEdgeWSPositions.append(targetWSPosition - ratioVertex2 * edgeWSVector);
}
Пример #10
0
MStatus MG_softIk::compute(const MPlug& plug,MDataBlock& dataBlock)
	{
		
		//Get data 
		if ((plug == outputTranslate) ||(plug == downScale) ||(plug == upScale) )
		{
		
		MMatrix startMatrixV = dataBlock.inputValue(startMatrix).asMatrix();
		MMatrix endMatrixV = dataBlock.inputValue(endMatrix).asMatrix();
		double upInitLengthV = dataBlock.inputValue(upInitLength).asDouble();
		double downInitLengthV = dataBlock.inputValue(downInitLength).asDouble();
		double softDistanceV = dataBlock.inputValue(softDistance).asDouble();
		double stretchV= dataBlock.inputValue(stretch).asDouble();
		double slideV = dataBlock.inputValue(slide).asDouble();
		double globalScaleV  = dataBlock.inputValue(globalScale).asDouble();
		upInitLengthV = upInitLengthV*(slideV*2)*globalScaleV ;
		downInitLengthV = downInitLengthV*((1 - slideV)*2)*globalScaleV;
 		double chainLength = upInitLengthV + downInitLengthV ;
		
		
		MVector startVector (startMatrixV[3][0] , startMatrixV[3][1] , startMatrixV[3][2] );
		MVector endVector  (endMatrixV[3][0] , endMatrixV[3][1] , endMatrixV[3][2] );
		MVector currentLengthVector  = endVector -  startVector ;
		
		double  currentLength = currentLengthVector.length() ;
		double startSD = chainLength - softDistanceV;
		
		double stretchParam = 1;
		double upScaleOut = 1 ;
		double downScaleOut = 1 ;
		
		if (startSD <= currentLength)
		{
		
		  if (softDistanceV != 0 )
		  {
		  double expParam =  ( currentLength - startSD) / softDistanceV;
		  expParam*= -1 ;
		  double softLength = ( (softDistanceV *(1 - exp ( expParam)) )+  startSD );
		  currentLengthVector.normalize();
		  currentLengthVector*=softLength ;
		  
		   if (stretchV != 0 )
		  {
		    
		     stretchParam = (currentLength/softLength  );
		     double delta = (stretchParam - 1); 
		     delta*=stretchV;
		     stretchParam = 1*(1 + delta);
		     currentLengthVector  *=(1 + delta );
		      
		  }
		  }
		  
		  
		}
		

		//slide computing
		
		upScaleOut = (slideV*2) *stretchParam ;
		downScaleOut = ((1 - slideV)*2)*stretchParam;
		
		
		MVector outVec =  startVector + currentLengthVector;
		dataBlock.outputValue(outputTranslate).setMVector(outVec);
		dataBlock.outputValue(outputTranslate).setClean();
		
		dataBlock.outputValue(downScale).set(downScaleOut);
		dataBlock.outputValue(downScale).setClean();
		
		
		dataBlock.outputValue(upScale).set(upScaleOut);
		dataBlock.outputValue(upScale).setClean();
		
		

		}
		return MS::kSuccess;
	}
Пример #11
0
MStatus CIKSolverNode::doSimpleSolver()
{
	MStatus stat;

	// Get the handle and create a function set for it
	//	
	MIkHandleGroup* handle_group = handleGroup();
	if (NULL == handle_group) {
		return MS::kFailure;
	}
	MObject handle = handle_group->handle(0);
	MDagPath handlePath = MDagPath::getAPathTo(handle);
	MFnIkHandle fnHandle(handlePath, &stat);

	// End-Effector
	MDagPath endEffectorPath;
	fnHandle.getEffector(endEffectorPath);
	MFnIkEffector  fnEffector(endEffectorPath);
	MPoint effectorPos = fnEffector.rotatePivot(MSpace::kWorld);

	unsigned int numJoints = endEffectorPath.length();
	std::vector<MDagPath> jointsDagPaths; jointsDagPaths.reserve(numJoints);
	while (endEffectorPath.length() > 1)
	{
		endEffectorPath.pop();
		jointsDagPaths.push_back( endEffectorPath );
	}
	std::reverse(jointsDagPaths.begin(), jointsDagPaths.end());

	static bool builtLocalSkeleton = false;
	if (builtLocalSkeleton == false)
	{
		for (int jointIdx = 0; jointIdx < jointsDagPaths.size(); ++jointIdx)
		{
			MFnIkJoint curJoint(jointsDagPaths[jointIdx]);
			m_localJointsPos.push_back( curJoint.getTranslation(MSpace::kWorld) );
		}
		m_localJointsPos.push_back(effectorPos );
		builtLocalSkeleton = true;
	}

	MPoint startJointPos = MFnIkJoint(jointsDagPaths.front()).getTranslation(MSpace::kWorld);

	MVector startToEndEff = m_localJointsPos.back() - m_localJointsPos.front();
	double curveLength = (getPosition(1.0) - getPosition(0.0)).length();
	double chainLength = startToEndEff.length(); // in local space.
	double stretchFactor = curveLength / chainLength;
	
	double uVal = 0.0f;
	MVector jointPosL = m_localJointsPos[0];
	for (int jointIdx = 0; jointIdx < jointsDagPaths.size(); ++jointIdx)
	{
		MFnIkJoint curJoint(jointsDagPaths[jointIdx]);

		MVector curJointPosL = m_localJointsPos[jointIdx];

		double dist = stretchFactor * (curJointPosL - jointPosL).length();
		uVal = uVal + dist / curveLength;

		MVector curCurveJointPos = getPosition(uVal);
		curJoint.setTranslation(curCurveJointPos, MSpace::kWorld);
		jointPosL = curJointPosL;
	}
	MVector effectorCurvePos = getPosition(1.0);
	MVector curCurveJointPos = getPosition(uVal);
	MVector effectorVec = (effectorCurvePos - curCurveJointPos).normal();
	double endJointAngle[3]; 
	MVector effectorVecXY = MVector(effectorVec(0), effectorVec(1), 0.0);
	endJointAngle[2] = effectorVecXY.angle(MVector(1, 0, 0));
	if ((MVector(1, 0, 0) ^ effectorVecXY) * MVector(0, 0, 1) < 0.0) { endJointAngle[2] = -endJointAngle[2]; }
	MVector effectorVecXZ = MVector(effectorVec(0), 0.0, effectorVec(2));
	endJointAngle[1] = effectorVecXZ.angle(MVector(1, 0, 0));
	if ((MVector(1, 0, 0) ^ effectorVecXZ) * MVector(0, 1, 0) < 0.0) { endJointAngle[1] = -endJointAngle[1]; }
	endJointAngle[0] = 0.0;
	MFnIkJoint curJoint(jointsDagPaths.back()); curJoint.setRotation(endJointAngle, curJoint.rotationOrder());
	return MS::kSuccess;
}
MStatus sgCurveEditBrush_context::editCurve( MDagPath dagPathCurve,
		int beforeX, int beforeY, int currentX, int currentY, float radius, 
		const MDoubleArray& dArrLength, MPointArray &points )
{
	MStatus status;

	if( radius < 0 ) return MS::kSuccess;

	MDagPath dagPathCam;
	M3dView view = M3dView::active3dView( &status );
	CHECK_MSTATUS_AND_RETURN_IT( status );

	view.getCamera( dagPathCam );

	MPoint  camPos = dagPathCam.inclusiveMatrix()[3];
	MVector vCamUp  = dagPathCam.inclusiveMatrix()[1];
	vCamUp.normalize();

	radius *= .05;

	MPoint nearClipBefore;
	MPoint farClipBefore;
	view.viewToWorld( beforeX, beforeY, nearClipBefore, farClipBefore );

	MVector rayBefore  = nearClipBefore - camPos;
	rayBefore.normalize();
	rayBefore *= 20;
	MPoint  posBefore = rayBefore + camPos;

	MPoint nearClipCurrent;
	MPoint farClipCurrent;
	view.viewToWorld( currentX, currentY, nearClipCurrent, farClipCurrent );

	MVector rayCurrent = nearClipCurrent - camPos;
	rayCurrent.normalize();
	rayCurrent *= 20;
	MPoint  posCurrent = rayCurrent + camPos;

	MVector vMove = posCurrent - posBefore;

	MMatrix mtxCurve = dagPathCurve.inclusiveMatrix();
	MFnNurbsCurve fnCurve( dagPathCurve );

	fnCurve.getCVs( points );

	for( int i=0; i< points.length(); i++ )
	{
		points[i] *= mtxCurve;
	}

	for( int i=1; i< points.length(); i++ )
	{
		MPoint cuPoint = points[i];
		MVector vPoint = cuPoint - camPos;

		MVector projV = ( vPoint * rayBefore )/( pow( rayBefore.length(), 2 ) )* rayBefore;
		MVector vertical = vPoint - projV;
		
		float radiusForPoint = vertical.length() / projV.length();

		if( radius < radiusForPoint )
			continue;
		MPoint parentPoint = points[i-1];

		MVector vCurveDirection = cuPoint - parentPoint;
		double vDirLength = vCurveDirection.length();

		MVector vEditDirection = vCurveDirection + vMove/rayBefore.length()*projV.length();

		double dotEdit = vCurveDirection.normal() * vEditDirection.normal();
		if( dotEdit < 0 ) continue;
		vEditDirection = vEditDirection * dotEdit + vCurveDirection*( 1-dotEdit );

		MVector vEditLength = vEditDirection / vEditDirection.length() * vCurveDirection.length();

		MVector vEdit = (vEditLength - vCurveDirection) * pow((double)(1-radiusForPoint/radius), 1 );
		points[i] += vEdit;

		for( int j=i+1; j< points.length(); j++ )
		{
			MPoint beforePoint = points[j];
			MPoint pPoint = points[j-1];
			MPoint beforePPoint = pPoint - vEdit;

			MVector vBefore = points[j] - beforePPoint;
			MVector vAfter  = points[j] - pPoint;
			MVector vCurrent = vAfter.normal() * dArrLength[j];
			
			points[j] = vCurrent + pPoint;

			vEdit = points[j] - beforePoint;
		}
	}

	MMatrix invMtxCurve = mtxCurve.inverse();
	for( int i=0; i< points.length(); i++ )
	{
		points[i] *= invMtxCurve;
	}

	fnCurve.setCVs( points );
	fnCurve.updateCurve();

	return MS::kSuccess;
}
Пример #13
0
void 
simpleFluidEmitter::omniFluidEmitter(
	MFnFluid& 		fluid,
	const MMatrix&	fluidWorldMatrix,
	int 			plugIndex,
	MDataBlock& 	block,
	double 			dt,
	double			conversion,
	double			dropoff
)
//==============================================================================
//
//	Method:	
//
//		simpleFluidEmitter::omniFluidEmitter
//
//	Description:
//
//		Emits fluid from a point, or from a set of object control points.
//
//	Parameters:
//
//		fluid:				fluid into which we are emitting
//		fluidWorldMatrix:	object->world matrix for the fluid
//		plugIndex:			identifies which fluid connected to the emitter
//							we are emitting into
//		block:				datablock for the emitter, to retrieve attribute
//							values
//		dt:					time delta for this frame
//		conversion:			mapping from UI emission rates to internal units
//		dropoff:			specifies how much emission rate drops off as
//							we move away from each emission point.
//
//	Notes:
//
//		If no owner object is present for the emitter, we simply emit from
//		the emitter position.  If an owner object is present, then we emit
//		from each control point of that object in an identical fashion.
//		
//		To associate an owner object with an emitter, use the
//		addDynamic MEL command, e.g. "addDynamic simpleFluidEmitter1 pPlane1".
//
//==============================================================================
{
	//	find the positions that we need to emit from
	//
	MVectorArray emitterPositions;
	
	//	first, try to get them from an owner object, which will have its
	//	"ownerPositionData" attribute feeding into the emitter.  These
	//	values are in worldspace
	//
	bool gotOwnerPositions = false;
	MObject ownerShape = getOwnerShape();
	if( ownerShape != MObject::kNullObj )
	{
		MStatus status;
		MDataHandle hOwnerPos = block.inputValue( mOwnerPosData, &status );
		if( status == MS::kSuccess )
		{
			MObject dOwnerPos = hOwnerPos.data();
			MFnVectorArrayData fnOwnerPos( dOwnerPos );
			MVectorArray posArray = fnOwnerPos.array( &status );
			if( status == MS::kSuccess )
			{
				// assign vectors from block to ownerPosArray.
				//
				for( unsigned int i = 0; i < posArray.length(); i ++ )
				{
					emitterPositions.append( posArray[i] );
				}
				
				gotOwnerPositions = true;
			}
		}
	}
	
	//	there was no owner object, so we just use the emitter position for
	//	emission.
	//
	if( !gotOwnerPositions )
	{
		MPoint emitterPos = getWorldPosition();
		emitterPositions.append( emitterPos );
	}

	//	get emission rates for density, fuel, heat, and emission color
	//	
	double densityEmit = fluidDensityEmission( block );
	double fuelEmit = fluidFuelEmission( block );
	double heatEmit = fluidHeatEmission( block );
	bool doEmitColor = fluidEmitColor( block );
	MColor emitColor = fluidColor( block );

	//	rate modulation based on frame time, user value conversion factor, and
	//	standard emitter "rate" value (not actually exposed in most fluid
	//	emitters, but there anyway).
	//
	double theRate = getRate(block) * dt * conversion;

	//	get voxel dimensions and sizes (object space)
	//
	double size[3];
	unsigned int res[3];
	fluid.getDimensions( size[0], size[1], size[2] );
	fluid.getResolution( res[0], res[1], res[2] );
	
	//	voxel sizes
	double dx = size[0] / res[0];
	double dy = size[1] / res[1];
	double dz = size[2] / res[2];
	
	//	voxel centers
	double Ox = -size[0]/2;
	double Oy = -size[1]/2;
	double Oz = -size[2]/2;	

	//	emission will only happen for voxels whose centers lie within
	//	"minDist" and "maxDist" of an emitter position
	//
	double minDist = getMinDistance( block );
	double maxDist = getMaxDistance( block );

	//	bump up the min/max distance values so that they
	//	are both > 0, and there is at least about a half
	//	voxel between the min and max values, to prevent aliasing
	//	artifacts caused by emitters missing most voxel centers
	//
	MTransformationMatrix fluidXform( fluidWorldMatrix );
	double fluidScale[3];
	fluidXform.getScale( fluidScale, MSpace::kWorld );
	
	//	compute smallest voxel diagonal length
	double wsX =  fabs(fluidScale[0]*dx);
	double wsY = fabs(fluidScale[1]*dy);
	double wsZ = fabs(fluidScale[2]*dz);
	double wsMin = MIN( MIN( wsX, wsY), wsZ );
	double wsMax = MAX( MAX( wsX, wsY), wsZ );
	double wsDiag  = wsMin * sqrt(3.0);

	//	make sure emission range is bigger than 0.5 voxels
	if ( maxDist <= minDist || maxDist <= (wsDiag/2.0) ) {
		if ( minDist < 0 ) minDist = 0;

		maxDist = minDist + wsDiag/2.0;
		dropoff = 0;
	}

	//	Now, it's time to actually emit into the fluid:
	//	
	//	foreach emitter point
	//		foreach voxel
	//			- select some points in the voxel
	//			- compute a dropoff function from the emitter point
	//			- emit an appropriate amount of fluid into the voxel
	//
	//	Since we've already expanded the min/max distances to cover
	//	the smallest voxel dimension, we should only need 1 sample per
	//	voxel, unless the voxels are highly non-square.  We increase the
	//	number of samples in these cases.
	//
	//	If the "jitter" flag is enabled, we jitter each sample position,
	//	using the rangen() function, which keeps track of independent 
	//	random states for each fluid, to make sure that results are
	//	repeatable for multiple simulation runs.
	//	

	// basic sample count
	int numSamples = 1;

	// increase samples if necessary for non-square voxels
	if(wsMin >.00001) 
	{
		numSamples = (int)(wsMax/wsMin + .5);
		if(numSamples > 8) 
			numSamples = 8;
		if(numSamples < 1)
			numSamples = 1;
	}
	
	bool jitter =  fluidJitter(block);
	if( !jitter )
	{
		//	I don't have a good uniform sample generator for an 
		//	arbitrary number of samples.  It would be a good idea to use
		//	one here.  For now, just use 1 sample for the non-jittered case.
		//
		numSamples = 1;
	}

	for( unsigned int p = 0; p < emitterPositions.length(); p++ )
	{
		MPoint emitterWorldPos = emitterPositions[p];

		//	loop through all voxels, looking for ones that lie at least
		//	partially within the dropoff field around this emitter point
		//
		for( unsigned int i = 0; i < res[0]; i++ )
		{
			double x = Ox + i*dx;
			
			for( unsigned int j = 0; j < res[1]; j++ )
			{
				double y = Oy + j*dy;
				
				for( unsigned int k = 0; k < res[2]; k++ )
				{
					double z = Oz + k*dz;
	
					int si;
					for( si = 0; si < numSamples; si++ )
					{
						//	compute sample point (fluid object space)
						//
						double rx, ry, rz;
						if( jitter )
						{
							rx = x + randgen()*dx;
							ry = y + randgen()*dy;
							rz = z + randgen()*dz;
						}
						else
						{
							rx = x + 0.5*dx;
							ry = y + 0.5*dy;
							rz = z + 0.5*dz;
						}

						//	compute distance from sample to emitter point
						//	
						MPoint point( rx, ry, rz );
						point *= fluidWorldMatrix;
						MVector diff = point - emitterWorldPos;
						double distSquared = diff * diff;
						double dist = diff.length();
					
						//	discard if outside min/max range
						//
						if( (dist < minDist) || (dist > maxDist) )
						{
							continue;
						}
						
						//	drop off the emission rate according to the falloff
						//	parameter, and divide to accound for multiple samples
						//	in the voxel
						//
						double distDrop = dropoff * distSquared;
						double newVal = theRate * exp( -distDrop ) / (double)numSamples;

						//	emit density/heat/fuel/color into the current voxel
						//
						if( newVal != 0 )
						{
							fluid.emitIntoArrays( (float) newVal, i, j, k, (float)densityEmit, (float)heatEmit, (float)fuelEmit, doEmitColor, emitColor );
						}

						float *fArray = fluid.falloff();
						if( fArray != NULL )
						{
							MPoint midPoint( x+0.5*dx, y+0.5*dy, z+0.5*dz );
							midPoint.x *= 0.2;
							midPoint.y *= 0.2;
							midPoint.z *= 0.2;

							float fdist = (float) sqrt( midPoint.x*midPoint.x + midPoint.y*midPoint.y + midPoint.z*midPoint.z );
							fdist /= sqrtf(3.0f);
							fArray[fluid.index(i,j,k)] = 1.0f-fdist;
						}
					}
				}
			}
		}
	}
}
Пример #14
0
	// used when ray does not intersect object
	// to account for perspective, all edges are flattened onto 
	// a plane defined by the raySource and rayDirection
	double gpuCacheIsectUtil::getEdgeSnapPointOnBox(const MPoint& raySource, const MVector& rayDirection, const MBoundingBox& bbox, MPoint& snapPoint){
		//if ray intersects bbox
		MPoint boxIntersectionPt;
		if(firstRayIntersection(bbox.min(), bbox.max(), raySource, rayDirection, NULL, &boxIntersectionPt))
		{
			//	ray intersects bounding box, so snapPoint is
			//	closest hit on the outside of the box
			//  and distance to box is 0 (for snapping purposes)
			snapPoint = boxIntersectionPt;
			return 0.0;
		}

		MPointArray verts;
		MPoint vmin = bbox.min();
		MPoint vmax = bbox.max();

		verts.insert(vmin,0);
		verts.insert(MPoint(vmax[0],vmin[1],vmin[2]),1);
		verts.insert(MPoint(vmax[0],vmax[1],vmin[2]),2);
		verts.insert(MPoint(vmin[0],vmax[1],vmin[2]),3);
		verts.insert(MPoint(vmin[0],vmin[1],vmax[2]),4);
		verts.insert(MPoint(vmax[0],vmin[1],vmax[2]),5);
		verts.insert(vmax,6);
		verts.insert(MPoint(vmin[0],vmax[1],vmax[2]),7);

		int edgeIndices[12][2]={{0,1},{1,2},{2,3},{3,0},{4,5},{5,6},{6,7},{7,4},{0,4},{1,5},{3,7},{2,6}};

		double minDistRect = std::numeric_limits<double>::max();
		
		for(int edge=0; edge<12;edge++){
			MPoint vertex1Org = verts[edgeIndices[edge][0]];
			MPoint vertex2Org = verts[edgeIndices[edge][1]];
			
			double coef_plane = rayDirection * raySource;
			double d = coef_plane - rayDirection * vertex1Org;
			MPoint vertex1 = vertex1Org + rayDirection * d;
			d = coef_plane - rayDirection * vertex2Org;
			MPoint vertex2 = vertex2Org + rayDirection * d;

			MVector edgeDir = vertex2 - vertex1;

			if (edgeDir.length()<0.0000001){
				double dist = vertex1.distanceTo(raySource);
				if (dist < minDistRect) {
					minDistRect = dist;
					snapPoint = vertex1Org;
				}
			} else {
				MPoint edgePt;
				// Compute the closest point from the edge to cursor Ray.
				double percent = gpuCacheIsectUtil::getClosestPointOnLine(raySource, vertex1, vertex2, edgePt);
				double dist = edgePt.distanceTo(raySource);
				if (dist < minDistRect) {
					minDistRect = dist;
					snapPoint =  (vertex1Org + percent * (vertex2Org - vertex1Org));
				}
			}
		}
		
		return minDistRect;
	}
Пример #15
0
	void gpuCacheIsectUtil::getClosestPointToRayOnLine(const MPoint& vertex1, const MPoint& vertex2, const MPoint& raySource, const MVector& rayDirection, MPoint& closestPoint, double& percent){
		MPoint clsPoint;
		MVector edgeDir = vertex2 - vertex1;
		double len = edgeDir.length();

		if(len < 0.0000001 )
		{
			percent = 0.0;
			closestPoint = vertex1;
			return;
		}

		edgeDir.normalize();
		
		//if line is parallel to ray
		double dotPrd = fabs(edgeDir * rayDirection);
		if(dotPrd > 0.9999){
			percent = 0.0;
			closestPoint = vertex1;
			return;
		}

		// Vector connecting two closest points.
		//
		MVector crossProd = edgeDir ^ rayDirection;

		// Normal to the plane defined by that vector and the 'otherLine'.
		//
		MVector planeNormal = rayDirection ^ crossProd;
		//intersectionPlane is raySource,planeNormal
		double t;
		if(intersectPlane(raySource, planeNormal, vertex1,edgeDir,t)){
			clsPoint = vertex1 + t * edgeDir;

			// Find percent, where
			// vertex1 + percent * (edgeDir) == closestPoint
			//
			percent = edgeDir * (clsPoint - vertex1) / len;

			// The closest point may not be on the segment. Find the closest
			// point on the segment using t.
			//
			if (percent < 0)
			{
				closestPoint = vertex1;
				percent = 0.0;
			}
			else if (percent > 1.0)
			{
				closestPoint = vertex2;
				percent = 1.0;
			}
			else
			{
				closestPoint = clsPoint;
			}
		} else
		{
			closestPoint = vertex1;
			percent = 0.0;
		}
	}
Пример #16
0
MStatus sgBulgeDeformer::deform(MDataBlock& dataBlock, MItGeometry& iter, const MMatrix& mtx, unsigned int index)
{
	MStatus status;

	float bulgeWeight = dataBlock.inputValue(aBulgeWeight).asFloat();
	double bulgeRadius = dataBlock.inputValue(aBulgeRadius).asDouble();

	MArrayDataHandle hArrInputs = dataBlock.inputArrayValue(aBulgeInputs);

	MPointArray allPositions;
	iter.allPositions(allPositions);

	if (mem_resetElements)
	{
		unsigned int elementCount = hArrInputs.elementCount();
		mem_meshInfosInner.resize(mem_maxLogicalIndex);
		mem_meshInfosOuter.resize(mem_maxLogicalIndex);

		for (unsigned int i = 0; i < elementCount; i++, hArrInputs.next())
		{
			MDataHandle hInput = hArrInputs.inputValue();
			MDataHandle hMatrix = hInput.child(aMatrix);
			MDataHandle hMesh   = hInput.child(aMesh);

			MMatrix mtxMesh = hMatrix.asMatrix();
			MObject oMesh   = hMesh.asMesh();

			MFnMeshData meshDataInner, meshDataOuter;
			MObject oMeshInner = meshDataInner.create();
			MObject oMeshOuter = meshDataOuter.create();
			MFnMesh fnMesh;
			fnMesh.copy(oMesh, oMeshInner);
			fnMesh.copy(oMesh, oMeshOuter);

			sgMeshInfo* newMeshInfoInner = new sgMeshInfo(oMeshInner, hMatrix.asMatrix());
			sgMeshInfo* newMeshInfoOuter = new sgMeshInfo(oMeshOuter, hMatrix.asMatrix());

			mem_meshInfosInner[hArrInputs.elementIndex()] = newMeshInfoInner;
			mem_meshInfosOuter[hArrInputs.elementIndex()] = newMeshInfoOuter;
		}
	}
	
	for (unsigned int i = 0; i < elementCount; i++)
	{
		mem_meshInfosInner[i]->setBulge(bulgeWeight, MSpace::kWorld );
	}
	
	MFloatArray weightList;
	weightList.setLength(allPositions.length());
	for (unsigned int i = 0; i < weightList.length(); i++)
		weightList[i] = 0.0f;
	MMatrixArray inputMeshMatrixInverses;
	inputMeshMatrixInverses.setLength(elementCount);
	for (unsigned int i = 0; i < elementCount; i++)
	{
		inputMeshMatrixInverses[i] = mem_meshInfosInner[i]->matrix();
	}

	for (unsigned int i = 0; i < allPositions.length(); i++)
	{
		float resultWeight = 0;
		for (unsigned int infoIndex = 0; infoIndex < elementCount; infoIndex++)
		{
			MPoint localPoint = allPositions[i] * mtx* inputMeshMatrixInverses[infoIndex];
			MPoint innerPoint = mem_meshInfosInner[infoIndex]->getClosestPoint(localPoint);
			MPoint outerPoint = mem_meshInfosOuter[infoIndex]->getClosestPoint(localPoint);
			MVector innerVector = innerPoint - localPoint;
			MVector outerVector = outerPoint - localPoint;

			if (innerVector * outerVector < 0)
			{
				double innerLength = innerVector.length();
				double outerLength = outerVector.length();
				double allLength = innerLength + outerLength;

				float numerator = float( innerLength * outerLength );
				float denominator = float( pow(allLength / 2.0, 2) );

				resultWeight = numerator / denominator;
			}
		}
		weightList[i] = resultWeight;
	}

	for (unsigned int i = 0; i < allPositions.length(); i++)
	{
		allPositions[i] += weightList[i] * MVector(0, 1, 0);
	}
	
	iter.setAllPositions(allPositions);

	return MS::kSuccess;
}
Пример #17
0
// COMPUTE ======================================
MStatus gear_rollSplineKine::compute(const MPlug& plug, MDataBlock& data)
{

	MStatus returnStatus;
	// Error check
    if (plug != output)
        return MS::kUnknownParameter;


	// Get inputs matrices ------------------------------
	// Inputs Parent
	MArrayDataHandle adh = data.inputArrayValue( ctlParent );
	int count = adh.elementCount();
	if (count < 1)
		return MS::kFailure;
	MMatrixArray inputsP(count);
	for (int i = 0 ; i < count ; i++){
		adh.jumpToElement(i);
		inputsP[i] = adh.inputValue().asMatrix();
	}

	// Inputs
	adh = data.inputArrayValue( inputs );
	if (count != adh.elementCount())
		return MS::kFailure;
	MMatrixArray inputs(count);
	for (int i = 0 ; i < count ; i++){
		adh.jumpToElement(i);
		inputs[i] = adh.inputValue().asMatrix();
	}

	adh = data.inputArrayValue( inputsRoll );
	if (count != adh.elementCount())
		return MS::kFailure;
	MDoubleArray roll(adh.elementCount());
	for (int i = 0 ; i < count ; i++){
		adh.jumpToElement(i);
		roll[i] = degrees2radians((double)adh.inputValue().asFloat());
	}

	// Output Parent
	MDataHandle ha = data.inputValue( outputParent );
	MMatrix outputParent = ha.asMatrix();
	
    // Get inputs sliders -------------------------------
    double in_u = (double)data.inputValue( u ).asFloat();
    bool in_resample = data.inputValue( resample ).asBool();
    int in_subdiv = data.inputValue( subdiv ).asShort();
    bool in_absolute = data.inputValue( absolute ).asBool();
	
    // Process ------------------------------------------
    // Get roll, pos, tan, rot, scl
    MVectorArray pos(count);
    MVectorArray tan(count);
	MQuaternion *rot;
	rot = new MQuaternion[count];
    MVectorArray scl(count);
	double threeDoubles[3];
	for (int i = 0 ; i < count ; i++){
		MTransformationMatrix tp(inputsP[i]);
		MTransformationMatrix t(inputs[i]);
		pos[i] = t.getTranslation(MSpace::kWorld);
		rot[i] = tp.rotation();

		t.getScale(threeDoubles, MSpace::kWorld);
		scl[i] = MVector(threeDoubles[0], threeDoubles[1], threeDoubles[2]);
		tan[i] = MVector(threeDoubles[0] * 2.5, 0, 0).rotateBy(t.rotation());
	}
	
    // Get step and indexes
    // We define between wich controlers the object is to be able to
    // calculate the bezier 4 points front this 2 objects
	double step = 1.0 / max( 1, count-1.0 );
	int index1 = (int)min( count-2.0, in_u/step );
	int index2 = index1+1;
	int index1temp = index1;
	int index2temp = index2;
	double v = (in_u - step * double(index1)) / step;
	double vtemp = v;
	
   // calculate the bezier
   MVector bezierPos;
   MVector xAxis, yAxis, zAxis;
   if(!in_resample){
      // straight bezier solve
      MVectorArray results = bezier4point(pos[index1],tan[index1],pos[index2],tan[index2],v);
      bezierPos = results[0];
      xAxis = results[1];
   }
   else if(!in_absolute){
      MVectorArray presample(in_subdiv);
      MVectorArray presampletan(in_subdiv);
      MDoubleArray samplelen(in_subdiv);
      double samplestep = 1.0 / double(in_subdiv-1);
      double sampleu = samplestep;
      presample[0]  = pos[index1];
      presampletan[0]  = tan[index1];
      MVector prevsample(presample[0]);
      MVector diff;
      samplelen[0] = 0;
      double overalllen = 0;
      MVectorArray results(2);
      for(long i=1;i<in_subdiv;i++,sampleu+=samplestep){
         results = bezier4point(pos[index1],tan[index1],pos[index2],tan[index2],sampleu);
         presample[i] = results[0];
         presampletan[i] = results[1];
		 diff = presample[i] - prevsample;
		 overalllen += diff.length();
         samplelen[i] = overalllen;
         prevsample = presample[i];
      }
      // now as we have the
      sampleu = 0;
      for(long i=0;i<in_subdiv-1;i++,sampleu+=samplestep){
         samplelen[i+1] = samplelen[i+1] / overalllen;
         if(v>=samplelen[i] && v <=  samplelen[i+1]){
            v = (v - samplelen[i]) / (samplelen[i+1] - samplelen[i]);
			bezierPos = linearInterpolate(presample[i],presample[i+1],v);
			xAxis = linearInterpolate(presampletan[i],presampletan[i+1],v);
            break;
         }
      }
   }
   else{
      MVectorArray presample(in_subdiv);
      MVectorArray presampletan(in_subdiv);
      MDoubleArray samplelen(in_subdiv);
      double samplestep = 1.0 / double(in_subdiv-1);
      double sampleu = samplestep;
      presample[0]  = pos[0];
      presampletan[0]  = tan[0];
      MVector prevsample(presample[0]);
      MVector diff;
      samplelen[0] = 0;
      double overalllen = 0;
      MVectorArray results;
      for(long i=1;i<in_subdiv;i++,sampleu+=samplestep){
         index1 = (int)min(count-2,sampleu / step);
         index2 = index1+1;
         v = (sampleu - step * double(index1)) / step;
         results = bezier4point(pos[index1],tan[index1],pos[index2],tan[index2],v);
         presample[i] = results[0];
         presampletan[i] = results[1];
		 diff = presample[i] - prevsample;
		 overalllen += diff.length();
         samplelen[i] = overalllen;
         prevsample = presample[i];
      }
      // now as we have the
      sampleu = 0;
      for(long i=0;i<in_subdiv-1;i++,sampleu+=samplestep){
         samplelen[i+1] = samplelen[i+1] / overalllen;
         if(in_u>=samplelen[i] && in_u <= samplelen[i+1]){
            in_u = (in_u - samplelen[i]) / (samplelen[i+1] - samplelen[i]);
			bezierPos = linearInterpolate(presample[i],presample[i+1],in_u);
			xAxis = linearInterpolate(presampletan[i],presampletan[i+1],in_u);
            break;
         }
      }
   }

   
	// compute the scaling (straight interpolation!)
	MVector scl1 = linearInterpolate(scl[index1temp], scl[index2temp],vtemp);

	// compute the rotation!
	MQuaternion q = slerp(rot[index1temp], rot[index2temp], vtemp);
	yAxis = MVector(0,1,0);
	yAxis = yAxis.rotateBy(q);
	
	// use directly or project the roll values!
	// print roll
	double a = linearInterpolate(roll[index1temp], roll[index2temp], vtemp);
	yAxis = yAxis.rotateBy( MQuaternion(xAxis.x * sin(a/2.0), xAxis.y * sin(a/2.0), xAxis.z * sin(a/2.0), cos(a/2.0)));
	
	zAxis = xAxis ^ yAxis;
	zAxis.normalize();
	yAxis = zAxis ^ xAxis;
	yAxis.normalize();

	// Output -------------------------------------------
	MTransformationMatrix result;

	// translation
	result.setTranslation(bezierPos, MSpace::kWorld);
	// rotation
	q = getQuaternionFromAxes(xAxis,yAxis,zAxis);
	result.setRotationQuaternion(q.x, q.y, q.z, q.w);
	// scaling
	threeDoubles[0] = 1;
	threeDoubles[0] = scl1.y;
	threeDoubles[0] = scl1.z;
	result.setScale(threeDoubles, MSpace::kWorld);

	MDataHandle h = data.outputValue( output );
	h.setMMatrix( result.asMatrix() * outputParent.inverse() );

	data.setClean( plug );


	return MS::kSuccess;
}
Пример #18
0
MStatus ik2Bsolver::doSolve()
//
// This is the doSolve method which calls solveIK.
//
{
        MStatus stat;

        // Handle Group
        //
        MIkHandleGroup * handle_group = handleGroup();
        if (NULL == handle_group) {
                return MS::kFailure;
        }

        // Handle
        //
        // For single chain types of solvers, get the 0th handle.
        // Single chain solvers are solvers which act on one handle only, 
        // i.e. the     handle group for a single chain solver
        // has only one handle
        //
        MObject handle = handle_group->handle(0);
        MDagPath handlePath = MDagPath::getAPathTo(handle);
        MFnIkHandle handleFn(handlePath, &stat);

        // Effector
        //
        MDagPath effectorPath;
        handleFn.getEffector(effectorPath);
        // MGlobal::displayInfo(effectorPath.fullPathName());
        MFnIkEffector effectorFn(effectorPath);

        // Mid Joint
        //
        effectorPath.pop();
        MFnIkJoint midJointFn(effectorPath);
        
        // End Joint
        //
        MDagPath endJointPath;
        bool hasEndJ = findFirstJointChild(effectorPath, endJointPath);
        // if(hasEndJ) MGlobal::displayInfo(endJointPath.fullPathName());
        
        MFnIkJoint endJointFn(endJointPath);
        
        // Start Joint
        //
        MDagPath startJointPath;
        handleFn.getStartJoint(startJointPath);
        MFnIkJoint startJointFn(startJointPath);

        // Preferred angles
        //
        double startJointPrefAngle[3];
        double midJointPrefAngle[3];
        startJointFn.getPreferedAngle(startJointPrefAngle);
        midJointFn.getPreferedAngle(midJointPrefAngle);

        // Set to preferred angles
        //
        startJointFn.setRotation(startJointPrefAngle, 
                                                         startJointFn.rotationOrder());
        midJointFn.setRotation(midJointPrefAngle, 
                                                   midJointFn.rotationOrder());

        MPoint handlePos = handleFn.rotatePivot(MSpace::kWorld);
        MPoint effectorPos = effectorFn.rotatePivot(MSpace::kWorld);
        MPoint midJointPos = midJointFn.rotatePivot(MSpace::kWorld);
        MPoint startJointPos = startJointFn.rotatePivot(MSpace::kWorld);
        MVector poleVector = poleVectorFromHandle(handlePath);
        poleVector *= handlePath.exclusiveMatrix();
        double twistValue = twistFromHandle(handlePath);
        
		MObject thisNode = thisMObject();
        
		MVector localEndJointT = endJointFn.getTranslation(MSpace::kTransform);
		MVector worldEndJointT = endJointFn.rotatePivot(MSpace::kWorld) - midJointPos;
		
		double scaling =  worldEndJointT.length() / ( localEndJointT.length() + 1e-6);
		
		// MGlobal::displayInfo(MString(" scaling ")+scaling);
		
        // get rest length
        //
        double restL1, restL2;
		MPlug(thisNode, arestLength1).getValue(restL1);
		MPlug(thisNode, arestLength2).getValue(restL2);
        // get soft distance
        //
        MPlug plug( thisNode, asoftDistance );
        double softD = 0.0;
        plug.getValue(softD);
        
        restL1 *= scaling;
        restL2 *= scaling;
        softD *= scaling;
		
		// get max stretching
		double maxStretching = 0.0;
		MPlug(thisNode, amaxStretching).getValue(maxStretching);
        
        MQuaternion qStart, qMid;
        double stretching = 0.0;
        solveIK(startJointPos,
                        midJointPos,
                        effectorPos,
                        handlePos,
                        poleVector,
                        twistValue,
                        qStart,
                        qMid,
                        softD,
						restL1, restL2,
						stretching);

        midJointFn.rotateBy(qMid, MSpace::kWorld);
        startJointFn.rotateBy(qStart, MSpace::kWorld);

		midJointFn.setTranslation(MVector(restL1 / scaling, 0.0, 0.0), MSpace::kTransform);
		endJointFn.setTranslation(MVector(restL2 / scaling, 0.0, 0.0), MSpace::kTransform);
			
		// if(stretching > maxStretching) stretching = maxStretching;
		if(maxStretching > 0.0) {
			MVector vstretch(stretching* 0.5 / scaling, 0.0, 0.0);
			midJointFn.translateBy(vstretch, MSpace::kTransform);
			endJointFn.translateBy(vstretch, MSpace::kTransform);
		}
        
        return MS::kSuccess;
}
Пример #19
0
void ik2Bsolver::solveIK(const MPoint &startJointPos,
                         const MPoint &midJointPos,
                         const MPoint &effectorPos,
                         const MPoint &handlePos,
                         const MVector &poleVector,
                         double twistValue,
                         MQuaternion &qStart,
                         MQuaternion &qMid,
                         const double & softDistance,
						 const double & restLength1,
						 const double & restLength2,
						 double & stretching)
//
// This is method that actually computes the IK solution.
//
{
        // vector from startJoint to midJoint
        MVector vector1 = midJointPos - startJointPos; vector1 = vector1.normal() * restLength1;
        // vector from midJoint to effector
        MVector vector2 = effectorPos - midJointPos; vector2 = vector2.normal() * restLength2;
        // vector from startJoint to handle
        MVector vectorH = handlePos - startJointPos;
        // vector from startJoint to effector
        MVector vectorE = effectorPos - startJointPos;
        // lengths of those vectors
        const double length1 = restLength1;
        const double length2 = restLength2;
        const double lengthH = vectorH.length();
        // component of the vector1 orthogonal to the vectorE
        const MVector vectorO =
                vector1 - vectorE*((vector1*vectorE)/(vectorE*vectorE));
                
		
        //////////////////////////////////////////////////////////////////
        // calculate q12 which solves for the midJoint rotation
        //////////////////////////////////////////////////////////////////
        // angle between vector1 and vector2
        const double vectorAngle12 = vector1.angle(vector2);
        
        // vector orthogonal to vector1 and 2
        const MVector vectorCross12 = vector1^vector2;
			
        const double lengthHsquared = lengthH * lengthH;
		double weight = 0.0;
		double slowLH = lengthH;// / (1.0 + (6.8 - softDistance) / (restLength1 + restLength2));
		const double da = restLength1 + restLength2 - softDistance;

		if(slowLH > da) {
		    float s = (slowLH - da) / softDistance;
		    if(s> 1.f) s= 1.f;
		    Vector3F pt = m_herm.interpolate(s);
		    // MGlobal::displayInfo(MString("herm ")+ pt.y);
			
// approading l1+l2 slower 
//
			weight = 1.0 - exp(-(slowLH - da) / softDistance * 6.98);
			
			weight = pt.y * weight + (1.f - pt.y) * s;
			slowLH = da + softDistance * weight;

			// MGlobal::displayInfo(MString("wei ")+weight);
		}

//
//           1
//        /    \
//  l1  /        \ l2
//    /            \	     ---l1---1 ---l2---
//  0 ------ l ------ 2     0 ------ l ------- 2
//
	
// angle for arm extension		
        
		double cos_theta = (slowLH * slowLH - length1*length1 - length2*length2) / (2*length1*length2);
		
		if (cos_theta > 1) 
                cos_theta = 1;
        else if (cos_theta < -1) 
                cos_theta = -1;
		
        const double theta = acos(cos_theta);

        // quaternion for arm extension
        MQuaternion q12(theta - vectorAngle12, vectorCross12);
        
        //////////////////////////////////////////////////////////////////
        // calculate qEH which solves for effector rotating onto the handle
        //////////////////////////////////////////////////////////////////
        // vector2 with quaternion q12 applied
        vector2 = vector2.rotateBy(q12);
        // vectorE with quaternion q12 applied
        vectorE = vector1 + vector2;
        // quaternion for rotating the effector onto the handle
        MQuaternion qEH(vectorE, vectorH);
		
		if(lengthH > vectorE.length()) {
			// MGlobal::displayInfo(MString("vle ")+(lengthH-vectorE.length()));
			stretching = (lengthH-vectorE.length()) * weight;
		}
        
        //////////////////////////////////////////////////////////////////
        // calculate qNP which solves for the rotate plane
        //////////////////////////////////////////////////////////////////
        // vector1 with quaternion qEH applied
        vector1 = vector1.rotateBy(qEH);
        if (vector1.isParallel(vectorH))
                // singular case, use orthogonal component instead
                vector1 = vectorO.rotateBy(qEH);
        // quaternion for rotate plane
        MQuaternion qNP;
        if (!poleVector.isParallel(vectorH) && (lengthHsquared != 0)) {
                // component of vector1 orthogonal to vectorH
                MVector vectorN = 
                        vector1 - vectorH*((vector1*vectorH)/lengthHsquared);
                // component of pole vector orthogonal to vectorH
                MVector vectorP = 
                        poleVector - vectorH*((poleVector*vectorH)/lengthHsquared);
                double dotNP = (vectorN*vectorP)/(vectorN.length()*vectorP.length());
                if (absoluteValue(dotNP + 1.0) < kEpsilon) {
                        // singular case, rotate halfway around vectorH
                        MQuaternion qNP1(kPi, vectorH);
                        qNP = qNP1;
                }
                else {
                        MQuaternion qNP2(vectorN, vectorP);
                        qNP = qNP2;
                }
        }

        //////////////////////////////////////////////////////////////////
        // calculate qTwist which adds the twist
        //////////////////////////////////////////////////////////////////
        MQuaternion qTwist(twistValue, vectorH);
		
		// quaternion for the mid joint
        qMid = q12;     
        // concatenate the quaternions for the start joint
        qStart = qEH*qNP*qTwist;
}
Пример #20
0
// COMPUTE ======================================
MStatus gear_percentageToU::compute(const MPlug& plug, MDataBlock& data)
{
	MStatus returnStatus;
	// Error check
    if (plug != percentage)
        return MS::kUnknownParameter;
	
	// Curve
	MFnNurbsCurve crv( data.inputValue( curve ).asNurbsCurve() );

	// Sliders
	bool in_normU = data.inputValue( normalizedU ).asBool();
	double in_percentage = (double)data.inputValue( percentage ).asFloat() * .01;
	const unsigned in_steps = data.inputValue( steps ).asShort();

	// Process
	// Get length
	MVectorArray u_subpos(in_steps);
	MPoint pt;
	MDoubleArray u_list(in_steps);
	for(unsigned i = 0 ; i < in_steps ; i++ ){
		u_list[i] = normalizedUToU(i /(in_steps - 1.0), crv.numCVs());

		crv.getPointAtParam(u_list[i], pt, MSpace::kWorld);
		u_subpos[i] = MVector(pt);
	}
	
	
	double t_length = 0;
	MDoubleArray dist(in_steps);
	MVector v;
	for (unsigned i = 0; i < in_steps ; i++){
		if (i>0){
			v = u_subpos[i] - u_subpos[i-1];
			t_length += v.length();
			dist[i] = t_length;
		}
	}

	MDoubleArray u_perc(in_steps);
	for (unsigned i = 0; i < in_steps ; i++){
		u_perc[i] = dist[i] / t_length;
	}

	
    // Get closest indices
    unsigned index = findClosestInArray(in_percentage, u_perc);
	unsigned indexA, indexB;
    if (in_percentage <= u_perc[index]){
        indexA = abs(int(index));
        indexB = index;
		if ( indexA > indexB){
			indexA = indexB;
			indexB = indexA+1;
		}
	}
    else {
        indexA = index;
        indexB = index + 1;
	}
	
    // blend value
    double blend = set01range(in_percentage, u_perc[indexA], u_perc[indexB]);
            
    double out_u = linearInterpolate(u_list[indexA], u_list[indexB], blend);
        
    if (in_normU)
        out_u = uToNormalizedU(out_u, crv.numCVs());
	
	// Ouput
	MDataHandle h = data.outputValue( u );
    h.setDouble( out_u );
    data.setClean( plug );

	return MS::kSuccess;
}