bool PivotScaled(ScaleValue& sv) { ScaleValue noscale(Point3(1,1,1)); Point3 p = sv.s - noscale.s; Point3 q(sv.q.x - noscale.q.x, sv.q.y - noscale.q.y, sv.q.z - noscale.q.z); float w = sv.q.w - noscale.q.w; float v = p.LengthSquared() + q.LengthSquared() + w * w; return v > gTolerenceEpsilon; }
bool IsScaled(Matrix3& tm) { Matrix3 t(1); t = tm - t; Point3 x = t.GetRow(0), y = t.GetRow(1), z = t.GetRow(2), u = t.GetRow(3); float v = x.LengthSquared() + y.LengthSquared() + z.LengthSquared() + u.LengthSquared(); if(v > gTolerenceEpsilon) return true; else return false; }
// Calculate bounding sphere using average position of the points. Better fit but slower. void CalcCenteredSphere(Mesh& mesh, Point3& center, float& radius) { int nv = mesh.getNumVerts(); Point3 sum(0.0f, 0.0f, 0.0f); for (int i=0; i<nv; ++i) sum += mesh.getVert(i); center = sum / float(nv); float radsq = 0.0f; for (int i=0; i<nv; ++i){ Point3 diff = mesh.getVert(i) - center; float mag = diff.LengthSquared(); radsq = max(radsq, mag); } radius = Sqrt(radsq); }
Point3 plDistributor::IPerpAxis(const Point3& p) const { const float kMinLengthSquared = 1.e-1f; int minAx = p.MinComponent(); Point3 ax(0,0,0); ax[minAx] = 1.f; Point3 perp = p ^ ax; if( perp.LengthSquared() < kMinLengthSquared ) { // hmm, think we might be screwed, but this shouldn't happen. } return perp = perp.FNormalize(); }
// Generate local to world from face info (pos, normal, etc) Matrix3 plDistributor::IGenerateTransform(int iRepNode, int iFace, const Point3& pt, const Point3& bary) const { const float kMinVecLengthSq = 1.e-6f; Matrix3 l2w(true); // First, set the scale Point3 scale; switch( fScaleLock ) { case kLockX | kLockY: scale.x = fRand.RandRangeF(fScaleLo.x, fScaleHi.x); scale.y = scale.x; scale.z = fRand.RandRangeF(fScaleLo.z, fScaleHi.z); break; case kLockX | kLockY | kLockZ: scale.x = fRand.RandRangeF(fScaleLo.x, fScaleHi.x); scale.y = scale.z = scale.x; break; default: scale.x = fRand.RandRangeF(fScaleLo.x, fScaleHi.x); scale.y = fRand.RandRangeF(fScaleLo.y, fScaleHi.y); scale.z = fRand.RandRangeF(fScaleLo.z, fScaleHi.z); break; } l2w.Scale(scale); // Next up, get the rotation. // First we'll randomly rotate about local Z float azimRot = fRand.RandMinusOneToOne() * fAzimuthRange; Matrix3 azimMat; azimMat.SetRotateZ(azimRot); l2w = l2w * azimMat; // Now align with the surface. // Get the interpolated surface normal. Point3 surfNorm = IGetSurfaceNormal(iFace, bary); Matrix3 repNodeTM = fRepNodes[iRepNode]->GetNodeTM(TimeValue(0)); Point3 alignVec = repNodeTM.GetRow(2); alignVec = alignVec * fWorldToSurfVec; alignVec = FNormalize(alignVec); Point3 norm = surfNorm + (alignVec - surfNorm) * fAlignWgt; // The norm can come out of this zero length, if the surace normal // is directly opposite the "natural" up direction and the weight // is 50% (for example). In that case, this is just a bad place // to drop this replicant. if( norm.LengthSquared() < kMinVecLengthSq ) { l2w.IdentityMatrix(); return l2w; } norm = norm.Normalize(); // Randomize through the cone around that. Point3 rndNorm = norm; Point3 rndDir = IPerpAxis(norm); Point3 rndOut = rndDir ^ norm; rndDir *= fRand.RandMinusOneToOne(); float len = sqrt(1.f - rndDir.LengthSquared()); rndOut *= len; if( fRand.RandMinusOneToOne() < 0 ) rndOut *= -1.f; Point3 rndPol = rndDir + rndOut; float polScale = fRand.RandZeroToOne() * fTanPolarRange; // Combine using the bunching factor polScale = polScale * (1.f - fPolarBunch) + polScale * polScale * fPolarBunch; rndPol *= polScale; rndNorm += rndPol; norm = rndNorm.Normalize(); // Have "up" alignment, now just generate random dir vector perpindicular to up Point3 dir = repNodeTM.GetRow(1); dir = dir * fWorldToSurfVec; Point3 out = dir ^ norm; if( out.LengthSquared() < kMinVecLengthSq ) { if( fAzimuthRange < M_PI * 0.5f ) { l2w.IdentityMatrix(); return l2w; } else { dir = IPerpAxis(norm); out = dir ^ norm; } } out = FNormalize(out); dir = norm ^ out; // If our "up" direction points into the surface, return an "up" direction // tangent to the surface. Also, make the "dir" direction point out from // the surface. So if the alignVec/fAlignWgt turns the replicant around // to penetrate the surface, it just lies down instead. // // There's an early out here, for the case where the surface normal is // exactly opposed to the destination normal. This usually means the // surface normal is directly opposite the alignVec. In that // case, we just want to bag it. if( DotProd(norm, surfNorm) < 0 ) { dir = surfNorm; dir = dir.Normalize(); out = dir ^ norm; if( out.LengthSquared() < kMinVecLengthSq ) { l2w.IdentityMatrix(); return l2w; } out = out.Normalize(); norm = out ^ dir; } Matrix3 align; align.Set(out, dir, norm, Point3(0,0,0)); l2w = l2w * align; // Lastly, set the position. Point3 pos = pt; const float offset = fRand.RandRangeF(fOffsetMin, fOffsetMax); pos += norm * offset; l2w.Translate(pos); l2w = l2w * fSurfNode->GetObjectTM(TimeValue(0)); return l2w; }