BOOL TrackMouseCallBack::point_on_obj(ViewExp& vpt, IPoint2 m, Point3& pt, Point3 &norm) { if ( ! vpt.IsAlive() ) { // why are we here DbgAssert(!_T("Invalid viewport!")); return FALSE; } // computes the normal ray at the point of intersection Ray ray, world_ray; float at, best_dist = 0.0f; TimeValue t = MAXScript_time(); Object *obj = NULL; Matrix3 obtm, iobtm; Point3 testNorm; BOOL found_hit = FALSE; vl->face_num_val = vl->face_bary = &undefined; hit_node = NULL; // Calculate a ray from the mouse point vpt.MapScreenToWorldRay(float(m.x), float(m.y), world_ray); for( int i=(nodeTab.Count()-1); i>=0; i-- ) { // Get the object from the node INode* node = nodeTab[i]; ObjectState os = node->EvalWorldState(t); obj = os.obj; // Back transform the ray into object space. obtm = node->GetObjectTM(t); iobtm = Inverse(obtm); ray.p = iobtm * world_ray.p; ray.dir = VectorTransform(iobtm, world_ray.dir); // See if we hit the object if (obj->IsSubClassOf(triObjectClassID)) { TriObject* tobj = (TriObject*)obj; DWORD fi; Point3 bary; if (tobj->mesh.IntersectRay(ray, at, testNorm, fi, bary) && ((!found_hit) || (at<=best_dist)) ) { // Calculate the hit point and transform everything back into world space. // record the face index and bary coord best_dist = at; pt = ray.p + ray.dir * at; pt = pt * obtm; norm = Normalize(VectorTransform(obtm, testNorm)); vl->face_num_val = Integer::intern(fi + 1); vl->face_bary = new Point3Value(bary); hit_node = node; found_hit = TRUE; } } else if (obj->IntersectRay(t, ray, at, testNorm) && ((!found_hit) || (at<=best_dist)) ) { // Calculate the hit point and transform everything back into world space. best_dist = at; pt = ray.p + ray.dir * at; pt = pt * obtm; norm = Normalize(VectorTransform(obtm, testNorm)); hit_node = node; found_hit = TRUE; } } if( found_hit ) return TRUE; // Failed to find a hit on any node, look at the Normal Align Vector for the first node if ((obj!=NULL) && obj->NormalAlignVector(t, pt, testNorm)) // See if a default NA vector is provided { pt = pt * obtm; norm = Normalize(VectorTransform(obtm, testNorm)); return TRUE; } else return FALSE; }
void TweakMouseProc::ComputeNewUVW(ViewExp& vpt, IPoint2 m) { if ( ! vpt.IsAlive() ) { // why are we here DbgAssert(!_T("Invalid viewport!")); return; } Ray r; vpt.MapScreenToWorldRay ((float) m.x, (float) m.y, r); TimeValue t = GetCOREInterface()->GetTime(); Matrix3 tm = mod->GetMeshTopoDataNode(mHitLDIndex)->GetObjectTM(t); Matrix3 itm = Inverse(tm); r.p = r.p * itm; r.dir = VectorTransform(r.dir,itm); //intersect our ray with that face and get our new bary coords Point3 n = mHitLD->GetGeomFaceNormal(mHitFace); Point3 p1, p2, p3; p1 = mHitP[0]; p2 = mHitP[1]; p3 = mHitP[2]; Point3 p, bry; float d, rn, a; // See if the ray intersects the plane (backfaced) rn = DotProd(r.dir,n); if (rn > -0.0001) return; // Use a point on the plane to find d Point3 v1 = p1; d = DotProd(v1,n); // Find the point on the ray that intersects the plane a = (d - DotProd(r.p,n)) / rn; // Must be positive... if (a < 0.0f) return ; // The point on the ray and in the plane. p = r.p + a*r.dir; // Compute barycentric coords. bry = BaryCoords(p1,p2,p3,p); // DbgAssert(bry.x + bry.y+ bry.z = 1.0) Point3 uvw = mHitUVW[0] * bry.x + mHitUVW[1] * bry.y + mHitUVW[2] * bry.z; Point3 v = uvw - mSourceUVW; v *= -1.0f; mFinalUVW = mSourceUVW + v; mHitLD->SetTVVert(GetCOREInterface()->GetTime(),mHitTVVert,mFinalUVW,mod); mod->NotifyDependents(FOREVER, PART_TEXMAP, REFMSG_CHANGE); mod->InvalidateView(); if (mod->ip) mod->ip->RedrawViews(mod->ip->GetTime()); }
BOOL BoundsTree::HitQuadTree(IPoint2 m, int &nindex, DWORD &findex, Point3 &p, Point3 &norm, Point3 &bary, float &finalZ, Matrix3 &toWorldTm) { //int nindex = 0; Leaf *l = head; BOOL hit = FALSE; Point3 hitPoint(0.0f,0.0f,0.0f); DWORD smgroup; hitPoint.x = (float) m.x; hitPoint.y = (float) m.y; float z = 0.0f; Point3 bry; if (l == NULL) { z = 0.0f; return FALSE; } int ct = 0; while ( (l!=NULL) && (l->IsBottom() == FALSE)) { int id = l->InWhichQuad(hitPoint); l = l->GetQuad(id); ct++; } if (l) { if (l->faceIndex.Count() == 0) return FALSE; else { for (int i = 0; i < l->faceIndex.Count(); i++) { int faceIndex = l->faceIndex[i].faceIndex; int nodeIndex = l->faceIndex[i].nodeIndex; LightMesh *lmesh = meshList[nodeIndex]; Point3 *tempVerts = lmesh->vertsViewSpace.Addr(0); Face *tempFaces = lmesh->faces.Addr(faceIndex); Box2D b = lmesh->boundingBoxList[faceIndex]; if ( (hitPoint.x >= b.min.x) && (hitPoint.x <= b.max.x) && (hitPoint.y >= b.min.y) && (hitPoint.y <= b.max.y) ) { //now check bary coords Point3 a,b,c; a = tempVerts[tempFaces->v[0]]; b = tempVerts[tempFaces->v[1]]; c = tempVerts[tempFaces->v[2]]; Point3 az,bz,cz,hitPointZ; az = a; bz = b; cz = c; az.z = 0.0f; bz.z = 0.0f; cz.z = 0.0f; hitPointZ = hitPoint; hitPointZ.z = 0.0f; Point3 bry; bry = BaryCoords(az, bz, cz, hitPointZ); //if inside bary find the the z point if (!( (bry.x<0.0f || bry.x>1.0f || bry.y<0.0f || bry.y>1.0f || bry.z<0.0f || bry.z>1.0f) || (fabs(bry.x + bry.y + bry.z - 1.0f) > EPSILON) )) { float tz = a.z * bry.x + b.z * bry.y + c.z * bry.z; if ( (tz > z ) || (hit == FALSE) ) { z = tz; findex = faceIndex; nindex = nodeIndex; bary = bry; finalZ = z; smgroup = tempFaces->getSmGroup(); } hit = TRUE; } } } } } if (hit) { Point3 a,b,c; int ia,ib,ic; LightMesh *lmesh = meshList[nindex]; Point3 *tempVerts = lmesh->vertsWorldSpace.Addr(0); Face *tempFaces = lmesh->faces.Addr(findex); ia = tempFaces->v[0]; ib = tempFaces->v[1]; ic = tempFaces->v[2]; a = tempVerts[ia]; b = tempVerts[ib]; c = tempVerts[ic]; ViewExp *vpt = GetCOREInterface()->GetActiveViewport(); Ray worldRay; // vpt->GetAffineTM(tm); vpt->MapScreenToWorldRay((float) m.x, (float) m.y, worldRay); GetCOREInterface()->ReleaseViewport(vpt); //intersect ray with the hit face // See if the ray intersects the plane (backfaced) norm = Normalize((b-a)^(c-b)); float rn = DotProd(worldRay.dir,norm); // Use a point on the plane to find d float d = DotProd(a,norm); // Find the point on the ray that intersects the plane float ta = (d - DotProd(worldRay.p,norm)) / rn; // The point on the ray and in the plane. p = worldRay.p + ta*worldRay.dir; // Compute barycentric coords. bary = BaryCoords(a, b, c, p); finalZ = ta; // p = a * bary.x + b * bary.y + c * bary.z; p = p * meshList[nindex]->toLocalSpace; norm = VectorTransform(meshList[nindex]->toLocalSpace,norm); toWorldTm = meshList[nindex]->toWorldSpace; } return hit; }