//This method does all the work for the brush. Every time the mouse moves this will be called for each brush on the surface of the model. Bool ExampleSculptGrabBrush::MovePointsFunc(BrushDabData* dab) { PolygonObject* polyObj = dab->GetPolygonObject(); if (!polyObj) return false; Int32 a; //Get the world matrix for the model so that we can turn local coordinates into world coordinates. Matrix mat = polyObj->GetMg(); //Get the location of the hitpoint on the model in world coordinates Vector hitPointWorld = mat * dab->GetHitPoint(); //Zero out the offset since its no longer required mat.off = Vector(0, 0, 0); const BaseContainer* pData = dab->GetData(); //Get our custom direction value that we added to our .res file. Int32 dirMode = pData->GetInt32(MDATA_TOOLSCULPTGRABBRUSH_DIRMODE); //Find the distance the mouse has moved in world coordinates by getting the world position of the mouse and subtracting the current grab brush world coordinate Vector moveAmnt = (dab->GetMousePos3D() - hitPointWorld); //Transform this distance into a vector that is in the local coordinates of the model. moveAmnt = ~mat * moveAmnt; Vector normal = dab->GetNormal(); switch (dirMode) { case MDATA_TOOLSCULPTGRABBRUSH_DIRMODE_NORMAL: { //If we are moving the point in the direction of its normal then use the length of the distance vector to scale the normal. moveAmnt = normal * moveAmnt.GetLength(); //Adjust the direction of the vector depending on if its moving above the surface or below it. Float dot = Dot(normal, moveAmnt); if (dot < 0) moveAmnt *= -1; break; } case MDATA_TOOLSCULPTGRABBRUSH_DIRMODE_MOUSEDIR: default: //Nothing to do here since moveAmnt is already correct. break; } //Get the original points on the surface of the object. These points are the state of the object when the //user first clicks on the model to do a mouse stroke. This allows you to compare where the points are during //a stroke, since you have moved them, when the original positions. const Vector32* pOriginalPoints = dab->GetOriginalPoints(); Int32 pointCount = dab->GetPointCount(); const Vector* pPoints = dab->GetPoints(); const BrushPointData* pPointData = dab->GetPointData(); //If any of the symmetry settings have been enabled, and this is a symmetry stroke instance, then this will return true. Bool mirror = dab->IsMirroredDab(); //Loop over every point on the dab and move them by the moveAmnt. for (a = 0; a < pointCount; ++a) { Int32 pointIndex = pPointData[a].pointIndex; //Get the falloff value for this point. This value will take into account the current stencil, stamp settings and the falloff curve to create this value. Float fallOff = dab->GetBrushFalloff(a); //Get the original location for this point Vector original = (Vector64)pOriginalPoints[pointIndex]; //Get the vector of the point we are going to change. const Vector& currentPoint = pPoints[pointIndex]; //If the user has any of the symmetry settings enabled and this is one of the symmetrical brush instance then mirror will be True. //We can check to see if another brush instance has already touched this point and moved it by calling the IsPointModified method. //If a point has been touched then that means it has already been moved by a certain vector by that brush instance. //This happens when the brushes overlap the same area of the model, which can easily happen if you have a large brush size and are using symmetry. //So we just offset it by another vector and do not worry about the original location of the point. if (mirror && dab->IsPointModified(pointIndex)) { //Adjust the offset by the new amount. dab->OffsetPoint(pointIndex, moveAmnt * fallOff); } else { //If there is no symmetry or the point hasn't been touched then we can just set the position of the point normally. //First determine the offset vector by using the original location of the point and adding on the new point after it has been adjusted by the falloff value. Vector newPosOffset = original + moveAmnt * fallOff; //A new offset is calculated by using this new point and its current position. Vector offset = newPosOffset - currentPoint; //Offset the point to place it in the correct location. dab->OffsetPoint(pointIndex, offset); } } //Ensure that all the points for the dab are marked as dirty. This is required to ensure that they all update even if they were not directly //touched by this brush instance. Marking all points as dirty ensures that the normals for all points are updated. This is only required //for grab brushes when multiple brush instances are touching the same points. dab->DirtyAllPoints(SCULPTBRUSHDATATYPE_POINT); return true; }