BOOL plDistributor::ISetSurfaceNode(INode* surfNode) const { if( !IGetMesh(surfNode, fSurfObjToDelete, fSurfMesh) ) { return false; } fSurfNode = surfNode; fSurfToWorld = surfNode->GetObjectTM(TimeValue(0)); fWorldToSurf = Inverse(fSurfToWorld); fSurfToWorldVec = Transpose(fWorldToSurf); fWorldToSurfVec = Transpose(fSurfToWorld); fSurfAngProbVec = FNormalize(fWorldToSurfVec * fAngProbVec); // This doesn't have anything to do with the surface node, but it // does have to do with the SurfAngProbVec, and this is as good a // place as any to do it. ISetAngProbCosines(); fSurfAlignVec = FNormalize(fWorldToSurfVec * fAlignVec); if( INeedMeshTree() ) IMakeMeshTree(); return true; }
BOOL plDistributor::IConformCheck(Matrix3& l2w, int iRepNode, plMeshCacheTab& cache, int& iCache) const { Matrix3 OTM = IOTM(iRepNode); Mesh* mesh = cache[iRepNode].fMesh; Point3 dir = l2w.VectorTransform(Point3(0.f, 0.f, 1.f)); dir = FNormalize(dir); const float kOneOverSqrt2 = 0.707107f; Point3 scalePt(kOneOverSqrt2, kOneOverSqrt2, 0.f); scalePt = l2w.VectorTransform(scalePt); float maxScaledDist = fMaxConform * scalePt.Length(); Box3 bnd = mesh->getBoundingBox() * OTM; bnd = Box3(Point3(bnd.Min().x, bnd.Min().y, -bnd.Max().z), bnd.Max()); bnd = bnd * l2w; Tab<int32_t> faces; IFindFaceSet(bnd, faces); int i; for( i = 0; i < mesh->getNumVerts(); i++ ) { Point3 pt = mesh->getVert(i) * OTM; pt.z = 0; pt = pt * l2w; Point3 projPt; if( !IProjectVertex(pt, dir, maxScaledDist, faces, projPt) ) return false; } return true; }
Point3 plDistributor::IGetSurfaceNormal(int iFace, const Point3& bary) const { fSurfMesh->checkNormals(true); if( !fFaceNormals ) { Face& face = fSurfMesh->faces[iFace]; Point3 norm = FNormalize(fSurfMesh->getNormal(face.getVert(0))) * bary[0]; norm += FNormalize(fSurfMesh->getNormal(face.getVert(1))) * bary[1]; norm += FNormalize(fSurfMesh->getNormal(face.getVert(2))) * bary[2]; return norm; } Point3 faceNorm = fSurfMesh->getFaceNormal(iFace); return FNormalize(faceNorm); }
BOOL plDistributor::IConformAll(Matrix3& l2w, int iRepNode, plMeshCacheTab& cache, int& iCache) const { Matrix3 OTM = IOTM(iRepNode); Mesh* mesh = cache[iRepNode].fMesh; Point3 dir = l2w.VectorTransform(Point3(0.f, 0.f, 1.f)); dir = FNormalize(dir); const float kOneOverSqrt2 = 0.707107f; Point3 scalePt(kOneOverSqrt2, kOneOverSqrt2, 0.f); scalePt = l2w.VectorTransform(scalePt); float maxScaledDist = fMaxConform * scalePt.Length(); Box3 bnd = mesh->getBoundingBox() * OTM; bnd = Box3(Point3(bnd.Min().x, bnd.Min().y, -bnd.Max().z), bnd.Max()); bnd = bnd * l2w; Tab<int32_t> faces; IFindFaceSet(bnd, faces); // l2w, iRepNode, cache, &iCache, maxScaledDist, dir iCache = cache.Count(); cache.SetCount(iCache + 1); cache[iCache] = cache[iRepNode]; cache[iCache].fMesh = new Mesh(*mesh); mesh = cache[iCache].fMesh; Matrix3 v2w = OTM * l2w; Matrix3 w2v = Inverse(v2w); BOOL retVal = true; int i; for( i = 0; i < mesh->getNumVerts(); i++ ) { Point3 pt = mesh->getVert(i) * OTM; pt.z = 0; pt = pt * l2w; Point3 projPt; if( !IProjectVertex(pt, dir, maxScaledDist, faces, projPt) ) { retVal = false; break; } Point3 del = w2v.VectorTransform(projPt - pt); mesh->getVert(i) += del; } if( !retVal ) { // delete cache[iCache].fMesh; delete mesh; cache.SetCount(iCache); iCache = iRepNode; } return retVal; }
float BerconGradient::getGradientValueNormal(ShadeContext& sc) { switch (p_normalType) { case 0: { // View return -DotProd(sc.Normal(), sc.V()); } case 1: { // Local X return (sc.VectorTo(sc.Normal(), REF_OBJECT)).x; } case 2: { // Local Y return (sc.VectorTo(sc.Normal(), REF_OBJECT)).y; } case 3: { // Local Z return (sc.VectorTo(sc.Normal(), REF_OBJECT)).z; } case 4: { // World X return (sc.VectorTo(sc.Normal(), REF_WORLD)).x; } case 5: { // World Y return (sc.VectorTo(sc.Normal(), REF_WORLD)).y; } case 6: { // World Z return (sc.VectorTo(sc.Normal(), REF_WORLD)).z; } case 7: { // Camera X return sc.Normal().x; //(sc.VectorTo(sc.Normal(), REF_CAMERA)).x; } case 8: { // Camera Y return sc.Normal().y; //(sc.VectorTo(sc.Normal(), REF_CAMERA)).y; } case 9: { // Camera Z return sc.Normal().z; //(sc.VectorTo(sc.Normal(), REF_CAMERA)).z; } case 10: { // To Object if (sc.InMtlEditor() || !p_node) return -DotProd(sc.Normal(), sc.V()); return DotProd(sc.Normal(), FNormalize(sc.PointFrom((p_node->GetNodeTM(sc.CurTime())).GetTrans(),REF_WORLD) - sc.P())); } case 11: { // Object Z if (sc.InMtlEditor() || !p_node) return -DotProd(sc.Normal(), sc.V()); return DotProd(sc.Normal(), FNormalize(sc.VectorFrom(p_node->GetNodeTM(sc.CurTime()).GetRow(2),REF_WORLD))); } } return 0.f; }
static Point3 RefractVector(ShadeContext &sc, Point3 N, Point3 V, float ior) { float VN,nur,k1; VN = DotProd(-V,N); if (sc.backFace) nur = ior; else nur = (ior!=0.0f) ? 1.0f/ior: 1.0f; k1 = 1.0f-nur*nur*(1.0f-VN*VN); if (k1<=0.0f) { // Total internal reflection: return FNormalize(2.0f*VN*N + V); } else return (nur*VN-(float)sqrt(k1))*N + nur*V; }
float BerconGradient::getGradientValueDist(ShadeContext& sc) { switch (p_normalType) { case 0: { // View return -sc.P().z; //Length(sc.OrigView()); //(sc.PointTo(sc.P(), REF_CAMERA)).z; } case 1: { // Local X return (sc.PointTo(sc.P(), REF_OBJECT)).x; } case 2: { // Local Y return (sc.PointTo(sc.P(), REF_OBJECT)).y; } case 3: { // Local Z return (sc.PointTo(sc.P(), REF_OBJECT)).z; } case 4: { // World X return (sc.PointTo(sc.P(), REF_WORLD)).x; } case 5: { // World Y return (sc.PointTo(sc.P(), REF_WORLD)).y; } case 6: { // World Z return (sc.PointTo(sc.P(), REF_WORLD)).z; } case 7: { // Camera X return sc.P().x; //(sc.PointTo(sc.P(), REF_CAMERA)).x; } case 8: { // Camera Y return sc.P().y; //(sc.PointTo(sc.P(), REF_CAMERA)).y; } case 9: { // Camera Z return -sc.P().z; //-(sc.PointTo(sc.P(), REF_CAMERA)).z; } case 10: { // To Object if (sc.InMtlEditor() || !p_node) return -sc.P().z; //(sc.PointTo(sc.P(), REF_CAMERA)).z; return Length((p_node->GetNodeTM(sc.CurTime())).GetTrans() - sc.PointTo(sc.P(), REF_WORLD)); } case 11: { // Object Z if (sc.InMtlEditor() || !p_node) return -sc.P().z; //(sc.PointTo(sc.P(), REF_CAMERA)).z; Matrix3 tm = p_node->GetNodeTM(sc.CurTime()); Point3 a = tm.GetTrans() - sc.PointTo(sc.P(), REF_WORLD); Point3 b = FNormalize(tm.GetRow(2)); return (-DotProd(b, a) / Length(b)); } } return 0.f; }
int DirLight::UpdateViewDepParams(const Matrix3& worldToCam) { BaseObjLight::UpdateViewDepParams(worldToCam); lightDir = FNormalize(lightToCam.GetRow(2)); return 1; }
// 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; }