bool Curve::recursiveIntersect(const Ray &ray, Float *tHit, SurfaceInteraction *isect, const Point3f cp[4], const Transform &rayToObject, Float u0, Float u1, int depth) const { // Try to cull curve segment versus ray // Compute bounding box of curve segment, _curveBounds_ Bounds3f curveBounds = Union(Bounds3f(cp[0], cp[1]), Bounds3f(cp[2], cp[3])); Float maxWidth = std::max(Lerp(u0, common->width[0], common->width[1]), Lerp(u1, common->width[0], common->width[1])); curveBounds = Expand(curveBounds, 0.5 * maxWidth); // Compute bounding box of ray, _rayBounds_ Float rayLength = ray.d.Length(); Float zMax = rayLength * ray.tMax; Bounds3f rayBounds(Point3f(0, 0, 0), Point3f(0, 0, zMax)); if (Overlaps(curveBounds, rayBounds) == false) return false; if (depth > 0) { // Split curve segment into sub-segments and test for intersection Float uMid = 0.5f * (u0 + u1); Point3f cpSplit[7]; SubdivideBezier(cp, cpSplit); return (recursiveIntersect(ray, tHit, isect, &cpSplit[0], rayToObject, u0, uMid, depth - 1) || recursiveIntersect(ray, tHit, isect, &cpSplit[3], rayToObject, uMid, u1, depth - 1)); } else { // Intersect ray with curve segment // Test ray against segment endpoint boundaries // Test sample point against tangent perpendicular at curve start Float edge = (cp[1].y - cp[0].y) * -cp[0].y + cp[0].x * (cp[0].x - cp[1].x); if (edge < 0) return false; // Test sample point against tangent perpendicular at curve end edge = (cp[2].y - cp[3].y) * -cp[3].y + cp[3].x * (cp[3].x - cp[2].x); if (edge < 0) return false; // Compute line $w$ that gives minimum distance to sample point Vector2f segmentDirection = Point2f(cp[3]) - Point2f(cp[0]); Float denom = segmentDirection.LengthSquared(); if (denom == 0) return false; Float w = Dot(-Vector2f(cp[0]), segmentDirection) / denom; // Compute $u$ coordinate of curve intersection point and _hitWidth_ Float u = Clamp(Lerp(w, u0, u1), u0, u1); Float hitWidth = Lerp(u, common->width[0], common->width[1]); Normal3f nHit; if (common->type == CurveType::Ribbon) { // Scale _hitWidth_ based on ribbon orientation Float sin0 = std::sin((1 - u) * common->normalAngle) * common->invSinNormalAngle; Float sin1 = std::sin(u * common->normalAngle) * common->invSinNormalAngle; nHit = sin0 * common->n[0] + sin1 * common->n[1]; hitWidth *= AbsDot(nHit, ray.d) / rayLength; } // Test intersection point against curve width Vector3f dpcdw; Point3f pc = EvalBezier(cp, Clamp(w, 0, 1), &dpcdw); Float ptCurveDist2 = pc.x * pc.x + pc.y * pc.y; if (ptCurveDist2 > hitWidth * hitWidth * .25) return false; if (pc.z < 0 || pc.z > zMax) return false; // Compute $v$ coordinate of curve intersection point Float ptCurveDist = std::sqrt(ptCurveDist2); Float edgeFunc = dpcdw.x * -pc.y + pc.x * dpcdw.y; Float v = (edgeFunc > 0) ? 0.5f + ptCurveDist / hitWidth : 0.5f - ptCurveDist / hitWidth; // Compute hit _t_ and partial derivatives for curve intersection if (tHit != nullptr) { // FIXME: this tHit isn't quite right for ribbons... *tHit = pc.z / rayLength; // Compute error bounds for curve intersection Vector3f pError(2 * hitWidth, 2 * hitWidth, 2 * hitWidth); // Compute $\dpdu$ and $\dpdv$ for curve intersection Vector3f dpdu, dpdv; EvalBezier(common->cpObj, u, &dpdu); if (common->type == CurveType::Ribbon) dpdv = Normalize(Cross(nHit, dpdu)) * hitWidth; else { // Compute curve $\dpdv$ for flat and cylinder curves Vector3f dpduPlane = (Inverse(rayToObject))(dpdu); Vector3f dpdvPlane = Normalize(Vector3f(-dpduPlane.y, dpduPlane.x, 0)) * hitWidth; if (common->type == CurveType::Cylinder) { // Rotate _dpdvPlane_ to give cylindrical appearance Float theta = Lerp(v, -90., 90.); Transform rot = Rotate(-theta, dpduPlane); dpdvPlane = rot(dpdvPlane); } dpdv = rayToObject(dpdvPlane); } *isect = (*ObjectToWorld)(SurfaceInteraction( ray(pc.z), pError, Point2f(u, v), -ray.d, dpdu, dpdv, Normal3f(0, 0, 0), Normal3f(0, 0, 0), ray.time, this)); } ++nHits; return true; } }
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 UnwrapMod::fnGizmoAlignToView() { if (ip == NULL) return; ViewExp& vpt = ip->GetActiveViewExp(); if (!vpt.IsAlive()) return; //get our tm //set the tm scale theHold.Begin(); SuspendAnimate(); AnimateOff(); TimeValue t = GetCOREInterface()->GetTime(); // Viewport tm Matrix3 vtm; vpt.GetAffineTM(vtm); vtm = Inverse(vtm); // Node tm Matrix3 ntm(1);// = nodeList[0]->GetObjectTM(ip->GetTime()); Matrix3 destTM = vtm * Inverse(ntm); //get our tm Matrix3 initialTM = *fnGetGizmoTM(); Point3 center = Normalize(initialTM.GetRow(3)); initialTM.SetRow(3,center); for (int i = 0; i < 3; i++) { Point3 vec = destTM.GetRow(i); float l = Length(initialTM.GetRow(i)); vec = Normalize(vec) * l; initialTM.SetRow(i,vec); } initialTM.SetRow(3,center); Matrix3 ptm(1), id(1); initialTM = initialTM ; SetXFormPacket tmpck(initialTM,ptm); tmControl->SetValue(t,&tmpck,TRUE,CTRL_RELATIVE); ResumeAnimate(); fnGizmoFit(); if ((fnGetMapMode() == PLANARMAP) || (fnGetMapMode() == CYLINDRICALMAP) || (fnGetMapMode() == SPHERICALMAP) || (fnGetMapMode() == BOXMAP)) ApplyGizmo(); theHold.Accept(GetString(IDS_MAPPING_ALIGNTOVIEW)); fnGetGizmoTM(); if (ip) ip->RedrawViews(ip->GetTime()); }
// Returns the derivative of PObj(), relative to the pixel. // TBD Point3 SContext::DPObj(void) { Point3 d = DP(); return VectorTransform(Inverse(tmAfterWSM),d); }
void FrenetFinder::ConvertPathToFrenets (Spline3D *pSpline, Matrix3 relativeTransform, Tab<Matrix3> & tFrenets, int numSegs, bool align, float rotateAroundZ) { // Given a path, a sequence of points in 3-space, create transforms // for putting a cross-section around each of those points, loft-style. // bezShape is provided by user, tFrenets contains output, numSegs is one less than the number of transforms requested. // Strategy: The Z-axis is mapped along the path, and the X and Y axes // are chosen in a well-defined manner to get an orthonormal basis. int i; if (numSegs < 1) return; tFrenets.SetCount (numSegs+1); int numIntervals = pSpline->Closed() ? numSegs+1 : numSegs; float denominator = float(numIntervals); Point3 xDir, yDir, zDir, location, tangent, axis; float position, sine, cosine, theta; Matrix3 rotation; // Find initial x,y directions: location = relativeTransform * pSpline->InterpCurve3D (0.0f); tangent = relativeTransform.VectorTransform (pSpline->TangentCurve3D (0.0f)); zDir = tangent; Matrix3 inverseBasisOfSpline(1); if (align) { xDir = Point3(0.0f, 0.0f, 0.0f); yDir = xDir; mBasisFinder.BasisFromZDir (zDir, xDir, yDir); if (rotateAroundZ) { Matrix3 rotator(1); rotator.SetRotate (AngAxis (zDir, rotateAroundZ)); xDir = xDir * rotator; yDir = yDir * rotator; } Matrix3 basisOfSpline(1); basisOfSpline.SetRow (0, xDir); basisOfSpline.SetRow (1, yDir); basisOfSpline.SetRow (2, tangent); basisOfSpline.SetTrans (location); inverseBasisOfSpline = Inverse (basisOfSpline); } else { inverseBasisOfSpline.SetRow (3, -location); } // Make relative transform take the spline from its own object space to our object space, // and from there into the space defined by its origin and initial direction: relativeTransform = relativeTransform * inverseBasisOfSpline; // (Note left-to-right evaluation order: Given matrices A,B, point x, x(AB) = (xA)B // The first transform is necessarily the identity: tFrenets[0].IdentityMatrix (); // Set up xDir, yDir, zDir to match our first-point basis: xDir = Point3 (1,0,0); yDir = Point3 (0,1,0); zDir = Point3 (0,0,1); for (i=1; i<=numIntervals; i++) { position = float(i) / denominator; location = relativeTransform * pSpline->InterpCurve3D (position); tangent = relativeTransform.VectorTransform (pSpline->TangentCurve3D (position)); // This is the procedure we follow at each step in the path: find the // orthonormal basis with the right orientation, then compose with // the translation putting the origin at the path-point. // As we proceed along the path, we apply minimal rotations to // our original basis to keep the Z-axis tangent to the curve. // The X and Y axes follow in a natural manner. // xDir, yDir, zDir still have their values from last time... // Create a rotation matrix which maps the last zDir onto the current tangent: axis = zDir ^ tangent; // gives axis, scaled by sine of angle. sine = FLength(axis); // positive - keeps angle value in (0,PI) range. cosine = DotProd (zDir, tangent); // Gives cosine of angle. theta = atan2f (sine, cosine); rotation.SetRotate (AngAxis (Normalize(axis), theta)); Point3 testVector = rotation * zDir; xDir = Normalize (rotation * xDir); yDir = Normalize (rotation * yDir); zDir = tangent; if (i<=numSegs) { tFrenets[i].IdentityMatrix (); tFrenets[i].SetRow (0, xDir); tFrenets[i].SetRow (1, yDir); tFrenets[i].SetRow (2, tangent); tFrenets[i].SetTrans (location); } } }
Matrix3 plMaxNodeBase::GetParentToWorld(TimeValue t) { return Inverse(GetWorldToParent(t)); }
void TestBSDF(void (*createBSDF)(BSDF*, MemoryArena&), const char* description) { MemoryArena arena; Options opt; pbrtInit(opt); const int thetaRes = CHI2_THETA_RES; const int phiRes = CHI2_PHI_RES; const int sampleCount = CHI2_SAMPLECOUNT; Float* frequencies = new Float[thetaRes * phiRes]; Float* expFrequencies = new Float[thetaRes * phiRes]; RNG rng; int index = 0; std::cout.precision(3); // Create BSDF, which requires creating a Shape, casting a Ray that // hits the shape to get a SurfaceInteraction object. BSDF* bsdf = nullptr; Transform t = RotateX(-90); Transform tInv = Inverse(t); { bool reverseOrientation = false; ParamSet p; std::shared_ptr<Shape> disk( new Disk(&t, &tInv, reverseOrientation, 0., 1., 0, 360.)); Point3f origin(0.1, 1, 0); // offset slightly so we don't hit center of disk Vector3f direction(0, -1, 0); Float tHit; Ray r(origin, direction); SurfaceInteraction isect; disk->Intersect(r, &tHit, &isect); bsdf = ARENA_ALLOC(arena, BSDF)(isect); createBSDF(bsdf, arena); } for (int k = 0; k < CHI2_RUNS; ++k) { /* Randomly pick an outgoing direction on the hemisphere */ Point2f sample {rng.UniformFloat(), rng.UniformFloat()}; Vector3f woL = CosineSampleHemisphere(sample); Vector3f wo = bsdf->LocalToWorld(woL); FrequencyTable(bsdf, wo, rng, sampleCount, thetaRes, phiRes, frequencies); IntegrateFrequencyTable(bsdf, wo, sampleCount, thetaRes, phiRes, expFrequencies); std::string filename = StringPrintf("/tmp/chi2test_%s_%03i.m", description, ++index); DumpTables(frequencies, expFrequencies, thetaRes, phiRes, filename.c_str()); auto result = Chi2Test(frequencies, expFrequencies, thetaRes, phiRes, sampleCount, CHI2_MINFREQ, CHI2_SLEVEL, CHI2_RUNS); EXPECT_TRUE(result.first) << result.second << ", iteration " << k; } delete[] frequencies; delete[] expFrequencies; pbrtCleanup(); }
// M^-1 Matrix3 Inverse(const Matrix3& m) { Matrix3 r; r.mat = Inverse(m.mat); return r; }
void CreateRadianceProbes::Render(const Scene *scene) { // Compute scene bounds and initialize probe integrators if (bbox.pMin.x > bbox.pMax.x) bbox = scene->WorldBound(); surfaceIntegrator->Preprocess(scene, camera, this); volumeIntegrator->Preprocess(scene, camera, this); Sample *origSample = new Sample(NULL, surfaceIntegrator, volumeIntegrator, scene); // Compute sampling rate in each dimension Vector delta = bbox.pMax - bbox.pMin; int nProbes[3]; for (int i = 0; i < 3; ++i) nProbes[i] = max(1, Ceil2Int(delta[i] / probeSpacing)); // Allocate SH coefficient vector pointers for sample points int count = nProbes[0] * nProbes[1] * nProbes[2]; Spectrum **c_in = new Spectrum *[count]; for (int i = 0; i < count; ++i) c_in[i] = new Spectrum[SHTerms(lmax)]; // Compute random points on surfaces of scene // Create scene bounding sphere to catch rays that leave the scene Point sceneCenter; float sceneRadius; scene->WorldBound().BoundingSphere(&sceneCenter, &sceneRadius); Transform ObjectToWorld(Translate(sceneCenter - Point(0,0,0))); Transform WorldToObject(Inverse(ObjectToWorld)); Reference<Shape> sph = new Sphere(&ObjectToWorld, &WorldToObject, true, sceneRadius, -sceneRadius, sceneRadius, 360.f); Reference<Material> nullMaterial = Reference<Material>(NULL); GeometricPrimitive sphere(sph, nullMaterial, NULL); vector<Point> surfacePoints; uint32_t nPoints = 32768, maxDepth = 32; surfacePoints.reserve(nPoints + maxDepth); Point pCamera = camera->CameraToWorld(camera->shutterOpen, Point(0, 0, 0)); surfacePoints.push_back(pCamera); RNG rng; while (surfacePoints.size() < nPoints) { // Generate random path from camera and deposit surface points Point pray = pCamera; Vector dir = UniformSampleSphere(rng.RandomFloat(), rng.RandomFloat()); float rayEpsilon = 0.f; for (uint32_t i = 0; i < maxDepth; ++i) { Ray ray(pray, dir, rayEpsilon, INFINITY, time); Intersection isect; if (!scene->Intersect(ray, &isect) && !sphere.Intersect(ray, &isect)) break; surfacePoints.push_back(ray(ray.maxt)); DifferentialGeometry &hitGeometry = isect.dg; pray = isect.dg.p; rayEpsilon = isect.rayEpsilon; hitGeometry.nn = Faceforward(hitGeometry.nn, -ray.d); dir = UniformSampleSphere(rng.RandomFloat(), rng.RandomFloat()); dir = Faceforward(dir, hitGeometry.nn); } } // Launch tasks to compute radiance probes at sample points vector<Task *> tasks; ProgressReporter prog(count, "Radiance Probes"); for (int i = 0; i < count; ++i) tasks.push_back(new CreateRadProbeTask(i, nProbes, time, bbox, lmax, includeDirectInProbes, includeIndirectInProbes, nIndirSamples, prog, origSample, surfacePoints, scene, this, c_in[i])); EnqueueTasks(tasks); WaitForAllTasks(); for (uint32_t i = 0; i < tasks.size(); ++i) delete tasks[i]; prog.Done(); // Write radiance probe coefficients to file FILE *f = fopen(filename.c_str(), "w"); if (f) { if (fprintf(f, "%d %d %d\n", lmax, includeDirectInProbes?1:0, includeIndirectInProbes?1:0) < 0 || fprintf(f, "%d %d %d\n", nProbes[0], nProbes[1], nProbes[2]) < 0 || fprintf(f, "%f %f %f %f %f %f\n", bbox.pMin.x, bbox.pMin.y, bbox.pMin.z, bbox.pMax.x, bbox.pMax.y, bbox.pMax.z) < 0) Severe("Error writing radiance file \"%s\"", filename.c_str()); for (int i = 0; i < nProbes[0] * nProbes[1] * nProbes[2]; ++i) { for (int j = 0; j < SHTerms(lmax); ++j) { fprintf(f, " "); if (c_in[i][j].Write(f) == false) Severe("Error writing radiance file \"%s\"", filename.c_str()); fprintf(f, "\n"); } fprintf(f, "\n"); } fclose(f); } for (int i = 0; i < nProbes[0] * nProbes[1] * nProbes[2]; ++i) delete[] c_in[i]; delete[] c_in; delete origSample; }
Quaternion Quaternion::Sub( const Quaternion& q ) const { return Inverse()*q; }
ColMesh* RBExport::GetColMesh( INode* node ) { ObjectState os = node->EvalWorldState( m_CurTime ); Object* pObject = os.obj; if (!pObject) { Warn( "Could not evaluate object state. Collision mesh %s was skipped.", node->GetName() ); return NULL; } Matrix3 nodeTM = node->GetNodeTM( m_CurTime ); Matrix3 nodeTMAfterWSM = node->GetObjTMAfterWSM( m_CurTime ); Matrix3 mOffs = nodeTMAfterWSM*Inverse( nodeTM ); // triangulate TriObject* pTriObj = NULL; if (pObject->CanConvertToType( Class_ID( TRIOBJ_CLASS_ID, 0 ) )) { pTriObj = (TriObject*)pObject->ConvertToType( m_CurTime, Class_ID( TRIOBJ_CLASS_ID, 0 ) ); } bool bReleaseTriObj = (pTriObj != pObject); if (!pTriObj) { Warn( "Could not triangulate mesh in node. Collision mesh %s was skipped.", node->GetName() ); return NULL; } // ensure, that vertex winding direction in polygon is CCW Matrix3 objTM = node->GetObjTMAfterWSM( m_CurTime ); bool bNegScale = (DotProd( CrossProd( objTM.GetRow(0), objTM.GetRow(1) ), objTM.GetRow(2) ) >= 0.0); int vx[3]; vx[0] = bNegScale ? 2 : 0; vx[1] = bNegScale ? 1 : 1; vx[2] = bNegScale ? 0 : 2; Mesh& mesh = pTriObj->GetMesh(); // some cosmetics mesh.RemoveDegenerateFaces(); mesh.RemoveIllegalFaces(); // create collision mesh ColMesh* pMesh = new ColMesh(); int numPri = mesh.getNumFaces(); int numVert = mesh.numVerts; // copy vertices for (int i = 0; i < numVert; i++) { Point3 pt = mesh.verts[i]; pt = mOffs.PointTransform( pt ); pt = c_FlipTM.PointTransform( pt ); pMesh->AddVertex( Vec3( pt.x, pt.y, pt.z ) ); } // loop on mesh faces for (int i = 0; i < numPri; i++) { Face& face = mesh.faces[i]; pMesh->AddPoly( face.v[vx[0]], face.v[vx[1]], face.v[vx[2]] ); } Msg( LogType_Stats, "Physics collision trimesh has %d vertices and %d faces.", numVert, numPri ); return pMesh; } // RBExport::GetColMesh
// Here we process mesh geometry for given node. // Vertices for the geometry from the all meshes of the scene are allocated in // one big vertex pool. One vertex can occur several times in this pool, because // we add 3 new vertices for every face. // After all meshes in the scene are processed, this pool is collapsed to remove // duplicate vertices. void RBExport::ProcessMesh( INode* node ) { if (!node->Renderable() || node->IsNodeHidden()) { return; } ObjectState os = node->EvalWorldState( m_CurTime ); Object* pObject = os.obj; if (!pObject) { Warn( "Could not evaluate object state in node <%s>. Mesh was skipped.", node->GetName() ); return; } Matrix3 nodeTM = node->GetNodeTM( m_CurTime ); Matrix3 nodeTMAfterWSM = node->GetObjTMAfterWSM( m_CurTime ); Matrix3 mOffs = nodeTMAfterWSM*Inverse( nodeTM ); // triangulate TriObject* pTriObj = 0; if (pObject->CanConvertToType( Class_ID( TRIOBJ_CLASS_ID, 0 ) )) { pTriObj = (TriObject*)pObject->ConvertToType( m_CurTime, Class_ID( TRIOBJ_CLASS_ID, 0 ) ); } bool bReleaseTriObj = (pTriObj != pObject); if (!pTriObj) { Warn( "Could not triangulate mesh in node <%s>. Node was skipped", node->GetName() ); return; } if (!MeshModStackIsValid( node )) { Warn( "Modifier stack for node %s should be collapsed or contain only Skin modifier.", node->GetName() ); } // ensure, that vertex winding direction in polygon is CCW Matrix3 objTM = node->GetObjTMAfterWSM( m_CurTime ); bool bNegScale = (DotProd( CrossProd( objTM.GetRow(0), objTM.GetRow(1) ), objTM.GetRow(2) ) >= 0.0); int vx[3]; if (bNegScale) { vx[0] = 0; vx[1] = 1; vx[2] = 2; } else { vx[0] = 2; vx[1] = 1; vx[2] = 0; } Mesh& mesh = pTriObj->GetMesh(); bool bHasTexCoord = (mesh.numTVerts != 0); bool bHasVertexColor = (mesh.numCVerts != 0) && m_pConfig->m_bExportVertexColors; bool bHasNormal = m_pConfig->m_bExportNormals; bool bHasSkin = ProcessSkin( node ); // some cosmetics BOOL res = mesh.RemoveDegenerateFaces(); if (res) { Spam( "Degenerate faces were fixed." ); } res = mesh.RemoveIllegalFaces(); if (res) { Spam( "Degenerate indices were fixed." ); } ExpNode* pExpNode = GetExportedNode( node ); if (!pExpNode) { return; } int numPri = mesh.getNumFaces(); int numVert = mesh.numVerts; // initialize helper array for building vertices' 0-circles VertexPtrArray vertexEntry; vertexEntry.resize( numVert ); memset( &vertexEntry[0], 0, sizeof( ExpVertex* )*numVert ); Spam( "Original mesh has %d vertices and %d faces.", numVert, numPri ); bool bHasVoidFaces = false; // loop on mesh faces for (int i = 0; i < numPri; i++) { Face& face = mesh.faces[i]; // calculate face normal const Point3& v0 = mesh.verts[face.v[vx[0]]]; const Point3& v1 = mesh.verts[face.v[vx[1]]]; const Point3& v2 = mesh.verts[face.v[vx[2]]]; Point3 normal = -Normalize( (v1 - v0)^(v2 - v1) ); normal = mOffs.VectorTransform( normal ); normal = c_FlipTM.VectorTransform( normal ); // loop on face vertices ExpVertex* pFaceVertex[3]; for (int j = 0; j < 3; j++) { ExpVertex v; v.mtlID = pExpNode->GetMaterialIdx( face.getMatID() ); v.nodeID = pExpNode->m_Index; if (v.mtlID < 0) { bHasVoidFaces = true; } // extract vertex position and apply world-space modifier to it int vIdx = face.v[vx[j]]; Point3 pt = mesh.verts[vIdx]; pt = mOffs.PointTransform( pt ); pt = c_FlipTM.PointTransform( pt ); v.index = vIdx; v.pos = Vec3( pt.x, pt.y, pt.z ); //v.pos *= m_WorldScale; // extract skinning info if (bHasSkin) { GetSkinInfo( v ); } // assign normal if (bHasNormal) { v.normal = Vec3( normal.x, normal.y, normal.z ); v.smGroup = face.smGroup; } // extract vertex colors if (bHasVertexColor) { const VertColor& vcol = mesh.vertCol[mesh.vcFace[i].t[vx[j]]]; v.color = ColorToDWORD( Color( vcol.x, vcol.y, vcol.z ) ); } // extract texture coordinates if (bHasTexCoord) { const Point3& texCoord = mesh.tVerts[mesh.tvFace[i].t[vx[j]]]; v.uv.x = texCoord.x; v.uv.y = 1.0f - texCoord.y; // second texture coordinate channel if (mesh.getNumMaps() > 1 && mesh.mapSupport( 2 )) { UVVert* pUVVert = mesh.mapVerts( 2 ); TVFace* pTVFace = mesh.mapFaces( 2 ); if (pUVVert && pTVFace) { const Point3& tc2 = pUVVert[pTVFace[i].t[vx[j]]]; v.uv2.x = tc2.x; v.uv2.y = 1.0f - tc2.y; } } } // allocate new vertex pFaceVertex[j] = AddVertex( v ); // we want vertices in the 0-ring neighborhood to be linked into closed linked list if (vertexEntry[vIdx] == NULL) { vertexEntry[vIdx] = pFaceVertex[j]; pFaceVertex[j]->pNext = pFaceVertex[j]; } else { vertexEntry[vIdx]->AddToZeroRing( pFaceVertex[j] ); } } AddPolygon( pFaceVertex[0], pFaceVertex[1], pFaceVertex[2] ); if (IsCanceled()) { return; } } // correct normals at vertices corresponding to smoothing groups SmoothNormals( vertexEntry ); // put vertices into set (this removes duplicate vertices) for (int i = 0; i < numVert; i++) { ExpVertex::ZeroRingIterator it( vertexEntry[i] ); while (it) { VertexSet::iterator sIt = m_VertexSet.find( it ); if (sIt == m_VertexSet.end()) { m_VertexSet.insert( it ); } else { it->pBase = (*sIt); } ++it; } } if (bReleaseTriObj) { delete pTriObj; } if (bHasVoidFaces) { Warn( "Mesh %s has faces with no material assigned.", node->GetName() ); } } // RBExport::ProcessMesh
void CompressibleNonlinearElasticitySolver<DIM>::AssembleOnElement( Element<DIM, DIM>& rElement, c_matrix<double, STENCIL_SIZE, STENCIL_SIZE >& rAElem, c_matrix<double, STENCIL_SIZE, STENCIL_SIZE >& rAElemPrecond, c_vector<double, STENCIL_SIZE>& rBElem, bool assembleResidual, bool assembleJacobian) { static c_matrix<double,DIM,DIM> jacobian; static c_matrix<double,DIM,DIM> inverse_jacobian; double jacobian_determinant; this->mrQuadMesh.GetInverseJacobianForElement(rElement.GetIndex(), jacobian, jacobian_determinant, inverse_jacobian); if (assembleJacobian) { rAElem.clear(); rAElemPrecond.clear(); } if (assembleResidual) { rBElem.clear(); } // Get the current displacement at the nodes static c_matrix<double,DIM,NUM_NODES_PER_ELEMENT> element_current_displacements; for (unsigned II=0; II<NUM_NODES_PER_ELEMENT; II++) { for (unsigned JJ=0; JJ<DIM; JJ++) { element_current_displacements(JJ,II) = this->mCurrentSolution[DIM*rElement.GetNodeGlobalIndex(II) + JJ]; } } // Allocate memory for the basis functions values and derivative values static c_vector<double, NUM_VERTICES_PER_ELEMENT> linear_phi; static c_vector<double, NUM_NODES_PER_ELEMENT> quad_phi; static c_matrix<double, DIM, NUM_NODES_PER_ELEMENT> grad_quad_phi; static c_matrix<double, NUM_NODES_PER_ELEMENT, DIM> trans_grad_quad_phi; // Get the material law AbstractCompressibleMaterialLaw<DIM>* p_material_law = this->mrProblemDefinition.GetCompressibleMaterialLaw(rElement.GetIndex()); static c_matrix<double,DIM,DIM> grad_u; // grad_u = (du_i/dX_M) static c_matrix<double,DIM,DIM> F; // the deformation gradient, F = dx/dX, F_{iM} = dx_i/dX_M static c_matrix<double,DIM,DIM> C; // Green deformation tensor, C = F^T F static c_matrix<double,DIM,DIM> inv_C; // inverse(C) static c_matrix<double,DIM,DIM> inv_F; // inverse(F) static c_matrix<double,DIM,DIM> T; // Second Piola-Kirchoff stress tensor (= dW/dE = 2dW/dC) static c_matrix<double,DIM,DIM> F_T; // F*T static c_matrix<double,DIM,NUM_NODES_PER_ELEMENT> F_T_grad_quad_phi; // F*T*grad_quad_phi c_vector<double,DIM> body_force; static FourthOrderTensor<DIM,DIM,DIM,DIM> dTdE; // dTdE(M,N,P,Q) = dT_{MN}/dE_{PQ} static FourthOrderTensor<DIM,DIM,DIM,DIM> dSdF; // dSdF(M,i,N,j) = dS_{Mi}/dF_{jN} static FourthOrderTensor<NUM_NODES_PER_ELEMENT,DIM,DIM,DIM> temp_tensor; static FourthOrderTensor<NUM_NODES_PER_ELEMENT,DIM,NUM_NODES_PER_ELEMENT,DIM> dSdF_quad_quad; static c_matrix<double, DIM, NUM_NODES_PER_ELEMENT> temp_matrix; static c_matrix<double,NUM_NODES_PER_ELEMENT,DIM> grad_quad_phi_times_invF; if(this->mSetComputeAverageStressPerElement) { this->mAverageStressesPerElement[rElement.GetIndex()] = zero_vector<double>(DIM*(DIM+1)/2); } // Loop over Gauss points for (unsigned quadrature_index=0; quadrature_index < this->mpQuadratureRule->GetNumQuadPoints(); quadrature_index++) { // This is needed by the cardiac mechanics solver unsigned current_quad_point_global_index = rElement.GetIndex()*this->mpQuadratureRule->GetNumQuadPoints() + quadrature_index; double wJ = jacobian_determinant * this->mpQuadratureRule->GetWeight(quadrature_index); const ChastePoint<DIM>& quadrature_point = this->mpQuadratureRule->rGetQuadPoint(quadrature_index); // Set up basis function information LinearBasisFunction<DIM>::ComputeBasisFunctions(quadrature_point, linear_phi); QuadraticBasisFunction<DIM>::ComputeBasisFunctions(quadrature_point, quad_phi); QuadraticBasisFunction<DIM>::ComputeTransformedBasisFunctionDerivatives(quadrature_point, inverse_jacobian, grad_quad_phi); trans_grad_quad_phi = trans(grad_quad_phi); // Get the body force, interpolating X if necessary if (assembleResidual) { switch (this->mrProblemDefinition.GetBodyForceType()) { case FUNCTIONAL_BODY_FORCE: { c_vector<double,DIM> X = zero_vector<double>(DIM); // interpolate X (using the vertices and the /linear/ bases, as no curvilinear elements for (unsigned node_index=0; node_index<NUM_VERTICES_PER_ELEMENT; node_index++) { X += linear_phi(node_index)*this->mrQuadMesh.GetNode( rElement.GetNodeGlobalIndex(node_index) )->rGetLocation(); } body_force = this->mrProblemDefinition.EvaluateBodyForceFunction(X, this->mCurrentTime); break; } case CONSTANT_BODY_FORCE: { body_force = this->mrProblemDefinition.GetConstantBodyForce(); break; } default: NEVER_REACHED; } } // Interpolate grad_u grad_u = zero_matrix<double>(DIM,DIM); for (unsigned node_index=0; node_index<NUM_NODES_PER_ELEMENT; node_index++) { for (unsigned i=0; i<DIM; i++) { for (unsigned M=0; M<DIM; M++) { grad_u(i,M) += grad_quad_phi(M,node_index)*element_current_displacements(i,node_index); } } } // Calculate C, inv(C) and T for (unsigned i=0; i<DIM; i++) { for (unsigned M=0; M<DIM; M++) { F(i,M) = (i==M?1:0) + grad_u(i,M); } } C = prod(trans(F),F); inv_C = Inverse(C); inv_F = Inverse(F); // Compute the passive stress, and dTdE corresponding to passive stress this->SetupChangeOfBasisMatrix(rElement.GetIndex(), current_quad_point_global_index); p_material_law->SetChangeOfBasisMatrix(this->mChangeOfBasisMatrix); p_material_law->ComputeStressAndStressDerivative(C, inv_C, 0.0, T, dTdE, assembleJacobian); if(this->mIncludeActiveTension) { // Add any active stresses, if there are any. Requires subclasses to overload this method, // see for example the cardiac mechanics assemblers. this->AddActiveStressAndStressDerivative(C, rElement.GetIndex(), current_quad_point_global_index, T, dTdE, assembleJacobian); } if(this->mSetComputeAverageStressPerElement) { this->AddStressToAverageStressPerElement(T,rElement.GetIndex()); } // Residual vector if (assembleResidual) { F_T = prod(F,T); F_T_grad_quad_phi = prod(F_T, grad_quad_phi); for (unsigned index=0; index<NUM_NODES_PER_ELEMENT*DIM; index++) { unsigned spatial_dim = index%DIM; unsigned node_index = (index-spatial_dim)/DIM; rBElem(index) += - this->mrProblemDefinition.GetDensity() * body_force(spatial_dim) * quad_phi(node_index) * wJ; // The T(M,N)*F(spatial_dim,M)*grad_quad_phi(N,node_index) term rBElem(index) += F_T_grad_quad_phi(spatial_dim,node_index) * wJ; } } // Jacobian matrix if (assembleJacobian) { // Save trans(grad_quad_phi) * invF grad_quad_phi_times_invF = prod(trans_grad_quad_phi, inv_F); ///////////////////////////////////////////////////////////////////////////////////////////// // Set up the tensor dSdF // // dSdF as a function of T and dTdE (which is what the material law returns) is given by: // // dS_{Mi}/dF_{jN} = (dT_{MN}/dC_{PQ}+dT_{MN}/dC_{PQ}) F{iP} F_{jQ} + T_{MN} delta_{ij} // // todo1: this should probably move into the material law (but need to make sure // memory is handled efficiently // todo2: get material law to return this immediately, not dTdE ///////////////////////////////////////////////////////////////////////////////////////////// // Set up the tensor 0.5(dTdE(M,N,P,Q) + dTdE(M,N,Q,P)) for (unsigned M=0; M<DIM; M++) { for (unsigned N=0; N<DIM; N++) { for (unsigned P=0; P<DIM; P++) { for (unsigned Q=0; Q<DIM; Q++) { // this is NOT dSdF, just using this as storage space dSdF(M,N,P,Q) = 0.5*(dTdE(M,N,P,Q) + dTdE(M,N,Q,P)); } } } } // This is NOT dTdE, just reusing memory. A^{MdPQ} = F^d_N * dTdE_sym^{MNPQ} dTdE.template SetAsContractionOnSecondDimension<DIM>(F, dSdF); // dSdF{MdPe} := F^d_N * F^e_Q * dTdE_sym^{MNPQ} dSdF.template SetAsContractionOnFourthDimension<DIM>(F, dTdE); // Now add the T_{MN} delta_{ij} term for (unsigned M=0; M<DIM; M++) { for (unsigned N=0; N<DIM; N++) { for (unsigned i=0; i<DIM; i++) { dSdF(M,i,N,i) += T(M,N); } } } /////////////////////////////////////////////////////// // Set up the tensor // dSdF_quad_quad(node_index1, spatial_dim1, node_index2, spatial_dim2) // = dS_{M,spatial_dim1}/d_F{spatial_dim2,N} // * grad_quad_phi(M,node_index1) // * grad_quad_phi(P,node_index2) // // = dSdF(M,spatial_index1,N,spatial_index2) // * grad_quad_phi(M,node_index1) // * grad_quad_phi(P,node_index2) // /////////////////////////////////////////////////////// temp_tensor.template SetAsContractionOnFirstDimension<DIM>(trans_grad_quad_phi, dSdF); dSdF_quad_quad.template SetAsContractionOnThirdDimension<DIM>(trans_grad_quad_phi, temp_tensor); for (unsigned index1=0; index1<NUM_NODES_PER_ELEMENT*DIM; index1++) { unsigned spatial_dim1 = index1%DIM; unsigned node_index1 = (index1-spatial_dim1)/DIM; for (unsigned index2=0; index2<NUM_NODES_PER_ELEMENT*DIM; index2++) { unsigned spatial_dim2 = index2%DIM; unsigned node_index2 = (index2-spatial_dim2)/DIM; // The dSdF*grad_quad_phi*grad_quad_phi term rAElem(index1,index2) += dSdF_quad_quad(node_index1,spatial_dim1,node_index2,spatial_dim2) * wJ; } } } } rAElemPrecond.clear(); if (assembleJacobian) { rAElemPrecond = rAElem; } if(this->mSetComputeAverageStressPerElement) { for(unsigned i=0; i<DIM*(DIM+1)/2; i++) { this->mAverageStressesPerElement[rElement.GetIndex()](i) /= this->mpQuadratureRule->GetNumQuadPoints(); } } }
//typedef double* FOOL; int MAPGetDir(double *Param,double *MaxStep,MatrCl &DirMat,double ErrorMatr) { //cout<<" MAPGetDir Begin \n"; int Dimen=Param[0],DimExp=(*MAPVar).ExperPoint[0],Ret=1; if ((Dimen>0) && (DimExp>0)) { int k,k1; int Iter; VecCl TmpGr(DimExp),CurGr(DimExp); VecCl HiGrad(Dimen); MatrCl WMat1(Dimen),WMat2(Dimen); double TmpHi,CurHi=True_Hi(Param); //cout<<" Coreleft MAPDir "<<coreleft()<<"\n"; double *TmpPar=new double[Dimen+1]; double *NormDiag=new double[Dimen+1]; VecCl *GrDat=new VecCl[Dimen+1]; for (k=1;k<=Dimen;k++) GrDat[k].SetDim(DimExp); True_Gr(Param,CurGr.Ptr); // begining of calculation of d(hi)/dx[k] in HiGrad[k] //cout<<" Coreleft 90 "<<coreleft()<<"\n"; for (k=1;k<=Dimen;k++) { if (fabs(MaxStep[k])<MathZer) cout<<" MAPGetDir MaxStep k "<<MaxStep[k]<<" "<<k<<"\n"; movmem(Param,TmpPar,sizeof(double)*(Dimen+1)); TmpPar[k]+=DERIVESTP*MaxStep[k]; True_Gr(TmpPar,TmpGr.Ptr); for (k1=1;k1<=DimExp;k1++) GrDat[k][k1]=(TmpGr[k1]-CurGr[k1])/(DERIVESTP*MaxStep[k]); TmpHi=True_Hi(TmpPar); HiGrad[k]=(CurHi-TmpHi)/(DERIVESTP*MaxStep[k]); } //cout<<" Hi Grad "<<HiGrad<<"Cur_Hi "<<CurHi<<"\nMax Step "; // for (k=1;k<=Dimen;k++) cout<<MaxStep[k]<<" ";cout<<"\n"; //ChRead(); // // end of calculation of d(hi)/dx[k] in HiGrad[k]} // //{ begining of calculation d(integral(dx[i]))/dx[k]=hmat[i,k] // D'[k]=correl[k] } for (k=1;k<=Dimen;k++) { for (k1=k;k1<=Dimen;k1++) WMat1(k,k1)=Correl_Func(DimExp,GrDat[k].Ptr,GrDat[k1].Ptr); if (WMat1(k,k)<MathZer) {cout<<" Function does not depend from parameter "<<k<<". Exiting\n"; Ret=0;goto exi; } double d=sqrt(WMat1(k,k)); if (d<MathZer) cout<<" MAPGetDir sqrt(WMat1(k,k)) k "<<d<<" "<<k<<"\n"; NormDiag[k]=1/d;//sqrt(WMat1(k,k)); } //cout<<" dxi/dxk \n"<<WMat1; for ( k=1;k<=Dimen;k++) { for (k1=k;k1<=Dimen;k1++) { WMat1(k,k1)=WMat1(k,k1)*NormDiag[k]*NormDiag[k1]; WMat1(k1,k)=WMat1(k,k1); } } //cout<<" dxi/dxk normalized\n"<<WMat1; // fwritem(nomparam,addr(hmat),1,1);k0:=ermes('first converted',-1); //{ end of calculation d(integral(dx[i]))/dx[k]=hmat[i,k] // D'[k,k]=correl[k] } //cout<<" Coreleft 129 "<<coreleft()<<"\n"; // if ((Err=Jacobi(WMat1,1000,ErrorMatr,TmpPar,WMat1,Iter))!=0) // {cout<<" Cannot Calculate Jacobi. Error ="<<Err<<" \n";exit(1);} if (!ReduceLQ(WMat1,WMat1,TmpPar,ErrorMatr)) {cout<<" Cannot Calculate ReduceLQ. \n";Ret=0;goto exi;} //cout<<" Coreleft 132=129"<<coreleft()<<"\n"; //cout<<" Eigen Vectors\n"<<WMat1<<" Eigen Val \n";ChRead(); //for ( k=1;k<=Dimen;k++) cout<<TmpPar[k]<<" ";cout<<"\n"; // Transpon(WMat1); //Because ReduceLQ we have not to transpon WMat2=WMat1; //cout<<" Coreleft 137 "<<coreleft()<<"\n"; //cout<<"Inverse "; Inverse(WMat1); //cout<<" O Key \n"; //cout<<" Coreleft 139=137"<<coreleft()<<"\n"; for ( k=1;k<=Dimen;k++) { for ( k1=1;k1<=Dimen;k1++) { double d=sqrt(fabs(TmpPar[k1])); if (d<MathZer) cout<<" MAPGetDir sqrt(fabs(TmpPar[k1])) k1 "<<d<<" "<<k1<<"\n"; WMat2(k,k1)=WMat2(k,k1)/d;//sqrt(fabs(TmpPar[k1])); } } WMat1=WMat2*WMat1; //cout<< " Result Matr After Mull\n"<<WMat1; for ( k=1;k<=Dimen;k++) { for ( k1=1;k1<=Dimen;k1++) WMat1(k,k1)=WMat1(k,k1)*NormDiag[k]; } //cout<<" MaxStep: "; for ( k=1;k<=Dimen;k++) { double s=0; for (int k1=1;k1<=Dimen;k1++) s+=HiGrad[k1]*WMat1(k1,k); MaxStep[k]=s; //cout<<MaxStep[k]<<" "; } //cout<<"\n"; //ChRead(); //cout<<" Coreleft 158=90 "<<coreleft()<<"\n"; DirMat=WMat1; //cout<<" Coreleft 160 "<<coreleft()<<"\n"; //cout<< " Dir Matr \n"<<DirMat; //cout<<"MaxStep ";for (k=1;k<=Dimen;k++) cout<<MaxStep[k]<<" ";cout<<"\n"; exi: delete TmpPar; delete NormDiag; for ( k=0;k<=Dimen;k++) {delete GrDat[k].Ptr;GrDat[k].Ptr=NULL;} delete GrDat; //cout<< "End MAPGetDir\n"; //cout<<" Coreleft MAPDir "<<coreleft()<<"\n"; } return Ret; };
Matrix3 plMaxNodeBase::GetLocalToVert(TimeValue t) { Matrix3 v2l = GetVertToLocal(t); Matrix3 l2v = Inverse(v2l); return l2v; }
//---------------------------------------------------------------------------- PX2::Transform SceneBuilder::GetLocalTransform (INode *node, TimeValue time) { // 计算节点的本地变换。Max节点的变换方法提供的节点的世界变换,所以我们 // 必须做一些操纵去获得节点的本地变换。 Matrix3 maxLocal = node->GetObjTMAfterWSM(time) * Inverse(node->GetParentNode()->GetObjTMAfterWSM(time)); // 分解变换 AffineParts affParts; decomp_affine(maxLocal, &affParts); // Position bool isTranslationZero = fabsf(affParts.t.x) < MIN_DIFFERENCE && fabsf(affParts.t.y) < MIN_DIFFERENCE && fabsf(affParts.t.z) < MIN_DIFFERENCE; // Rotation float qSign = (affParts.q.w >= 0.0f ? 1.0f : -1.0f); bool isRotationIndentity = fabsf(qSign*affParts.q.w - 1.0f) < MIN_DIFFERENCE && fabsf(affParts.q.x) < MIN_DIFFERENCE && fabsf(affParts.q.y) < MIN_DIFFERENCE && fabsf(affParts.q.z) < MIN_DIFFERENCE; // Reflect bool hasReflection = (affParts.f < 0.0f); // Uniform scale bool isScaleUniform = (fabsf(affParts.k.x - affParts.k.y)<MIN_DIFFERENCE && fabsf(affParts.k.y - affParts.k.z)<MIN_DIFFERENCE); // Unity scale bool isScaleUnity = isScaleUniform && fabsf(affParts.k.x - 1.0f) < MIN_DIFFERENCE; // Scale orientation is identity? float uSign = (affParts.u.w >= 0.0f ? 1.0f : -1.0f); bool isOrientIndentity = isScaleUniform || ( fabsf(uSign*affParts.u.w - 1.0f) < MIN_DIFFERENCE && fabsf(affParts.u.x) < MIN_DIFFERENCE && fabsf(affParts.u.y) < MIN_DIFFERENCE && fabsf(affParts.u.z) < MIN_DIFFERENCE); // 计算Phoenix2等价变换 PX2::Transform local; if (!isTranslationZero) { local.SetTranslate(PX2::APoint(affParts.t.x, affParts.t.y, affParts.t.z)); } if (hasReflection) { affParts.k *= -1.0f; } if (isScaleUniform) { // 矩阵的形式为R*(s*I),s是统一缩放矩阵。 if (!isRotationIndentity) { PX2::HMatrix rot; PX2::HQuaternion(affParts.q.w, -affParts.q.x, -affParts.q.y, -affParts.q.z).ToRotationMatrix(rot); local.SetRotate(rot); } if (!isScaleUnity) { local.SetUniformScale(affParts.k.x); } } else if (isOrientIndentity) { if (!isRotationIndentity) { PX2::HMatrix rot; PX2::HQuaternion(affParts.q.w, -affParts.q.x, -affParts.q.y, -affParts.q.z).ToRotationMatrix(rot); local.SetRotate(rot); } local.SetScale(PX2::APoint(affParts.k.x, affParts.k.y, affParts.k.z)); } else { PX2::Matrix3f mat( maxLocal.GetAddr()[0][0], maxLocal.GetAddr()[1][0], maxLocal.GetAddr()[2][0], maxLocal.GetAddr()[0][1], maxLocal.GetAddr()[1][1], maxLocal.GetAddr()[2][1], maxLocal.GetAddr()[0][2], maxLocal.GetAddr()[1][2], maxLocal.GetAddr()[2][2]); local.SetMatrix(PX2::HMatrix(mat)); } return local; }
Matrix3 plMaxNodeBase::GetOBBToLocal(TimeValue t) { return Inverse(GetOTM(t)) * GetVertToLocal(t); }
void LocalInverse( DistMatrix<F,STAR,STAR>& A ) { DEBUG_CSE Inverse( A.Matrix() ); }
void GradientDataExport<dim>::eval_and_deriv(MathVector<dim> vValue[], const MathVector<dim> vGlobIP[], number time, int si, GridObject* elem, const MathVector<dim> vCornerCoords[], const MathVector<refDim> vLocIP[], const size_t nip, LocalVector* u, bool bDeriv, int s, std::vector<std::vector<MathVector<dim> > > vvvDeriv[], const MathMatrix<refDim, dim>* vJT) const { // abbreviation for component static const int _C_ = 0; // reference object id const ReferenceObjectID roid = elem->reference_object_id(); // local finite element id const LFEID& lfeID = this->function_group().local_finite_element_id(_C_); // access local vector by map u->access_by_map(this->map()); // request for trial space try{ const LocalShapeFunctionSet<refDim>& rTrialSpace = LocalFiniteElementProvider::get<refDim>(roid, lfeID); // Reference Mapping MathMatrix<dim, refDim> JTInv; std::vector<MathMatrix<refDim, dim> > vJTtmp; if(!vJT){ DimReferenceMapping<refDim, dim>& map = ReferenceMappingProvider::get<refDim, dim>(roid, vCornerCoords); vJTtmp.resize(nip); map.jacobian_transposed(&vJTtmp[0], vLocIP, nip); vJT = &vJTtmp[0]; } // storage for shape function at ip std::vector<MathVector<refDim> > vLocGrad; MathVector<refDim> locGrad; // loop ips for(size_t ip = 0; ip < nip; ++ip) { // evaluate at shapes at ip rTrialSpace.grads(vLocGrad, vLocIP[ip]); // compute grad at ip VecSet(locGrad, 0.0); for(size_t sh = 0; sh < vLocGrad.size(); ++sh) VecScaleAppend(locGrad, (*u)(_C_, sh), vLocGrad[sh]); Inverse(JTInv, vJT[ip]); MatVecMult(vValue[ip], JTInv, locGrad); // store derivative if(bDeriv) for(size_t sh = 0; sh < vLocGrad.size(); ++sh) MatVecMult(vvvDeriv[ip][_C_][sh], JTInv, vLocGrad[sh]); } } UG_CATCH_THROW("GradientDataExport: Trial space missing, Reference Object: " <<roid<<", Trial Space: "<<lfeID<<", refDim="<<refDim); }
/* ==================== GatherSkin ==================== */ void G3DSExport::GatherSkin(INode* i_node) { SKIN skin; // get the name of the node skin.name = i_node->GetName(); // get the skin interface Modifier *modifier = GetModifier(i_node,SKIN_CLASSID); ISkin* i_skin = (ISkin*)modifier->GetInterface(I_SKIN); MAX_CHECK(i_skin); // convert to the triangle type Mesh* i_mesh = NULL; Object* obj = i_node->EvalWorldState(mTime).obj; if(obj && ( obj->SuperClassID() == GEOMOBJECT_CLASS_ID )) { if(obj->CanConvertToType(Class_ID(TRIOBJ_CLASS_ID, 0))) { TriObject *tri_obj = (TriObject*)obj->ConvertToType(mTime, Class_ID(TRIOBJ_CLASS_ID, 0)); MAX_CHECK(tri_obj); i_mesh = &tri_obj->mesh; } } MAX_CHECK(i_mesh&&i_mesh->getNumFaces()&&i_mesh->getNumVerts()); // get the material skin.texture = "textures/default.tga"; Mtl* mtl = i_node->GetMtl(); if(mtl && (mtl->ClassID()==Class_ID(DMTL_CLASS_ID, 0)) && ((StdMat*)mtl)->MapEnabled(ID_DI)) { Texmap *texmap = mtl->GetSubTexmap(ID_DI); if(texmap && texmap->ClassID() == Class_ID(BMTEX_CLASS_ID, 0x00)) { skin.texture = UnifySlashes(((BitmapTex *)texmap)->GetMapName()); if( !strstr( skin.texture.c_str(), mPath.c_str() ) ) { G3DAssert("The material(%s) is error : the texture path(%s) is illegal!",mtl->GetName(), skin.texture.c_str()); } else { skin.texture = strstr(skin.texture.c_str(),mPath.c_str()) + strlen(mPath.c_str()); } } } // if it has uvs int map_count = i_mesh->getNumMaps(); bool has_uvs = i_mesh->getNumTVerts() && i_mesh->tvFace; if(!(has_uvs&&map_count)) { G3DAssert("The skin(%s) has not the uv coordinates.",skin.name.c_str()); return; } // get the transform Matrix3 mesh_matrix = i_node->GetObjectTM(mTime); Matrix3 node_matrix = i_node->GetNodeTM(mTime); Matrix3 transform = mesh_matrix * Inverse(node_matrix); // get the points skin.points.assign(i_mesh->verts, i_mesh->verts+i_mesh->getNumVerts()); // get the triangles for(int i = 0; i < i_mesh->getNumFaces(); i++) { Face& face = i_mesh->faces[i]; TRIANGLE tri; tri.smoothing = face.smGroup; for(int j = 0; j < 3; j++) { VPTNIS v; v.pos = transform * i_mesh->verts[face.v[j]]; // get the uv UVVert * map_verts = i_mesh->mapVerts(1); TVFace * map_faces = i_mesh->mapFaces(1); v.uv = reinterpret_cast<Point2&>(map_verts[map_faces[i].t[j]]); v.uv.y = 1 - v.uv.y; // initialize the normal v.normal = Point3::Origin; // get the vertex index v.index = face.v[j]; // get the smoothing group v.smoothing = face.smGroup; // set the index for the triangle tri.index0[j] = v.index; // reassemble the vertex list tri.index1[j] = AddVertex(skin, v); } // add the triangle to the table skin.triangles.push_back(tri); } // build the index map for( int i = 0; i < skin.vertexes.size(); i++ ) { skin.vertex_index_map[skin.vertexes[i].index].push_back(i); } // get the skin context data ISkinContextData* i_skin_context_data = i_skin->GetContextInterface(i_node); if(i_skin_context_data == NULL) { G3DAssert("The skin(%s) has not the weight.",skin.name.c_str()); return; } // gets the initial matrix of the skinned object Matrix3 initial_object_transform; i_skin->GetSkinInitTM(i_node, initial_object_transform, true); // process the points int num_points = i_skin_context_data->GetNumPoints(); for(int i = 0; i < num_points; i++) { MAX_CHECK(i < skin.points.size()); VPIW viw; // get the initial point viw.pos = initial_object_transform * skin.points[i]; // process the weights std::multimap< float, int > weights; // get the number of bones that control this vertex int num_bones = i_skin_context_data->GetNumAssignedBones(i); if(num_bones>0) { for (int j = 0; j < num_bones; j++) { Matrix3 transform; // get the assigned bone of the point INode* i_bone_node = i_skin->GetBone(i_skin_context_data->GetAssignedBone(i, j)); MAX_CHECK(i_bone_node != NULL); // get the weight of the bone float weight = i_skin_context_data->GetBoneWeight(i, j); // add the weight to the table weights.insert(std::make_pair(weight, AddBone(skin,i_bone_node))); } } else { // add the weight to the table weights.insert(std::make_pair(1.f, AddBone(skin,i_node))); } // recalculate the weights float weight0 = 0.f, weight1 = 0.f, weight2 = 0.f; int index0 = 0, index1 = 0, index2 = 0; std::multimap< float, int >::iterator it = weights.end(); it--; weight0 = it->first; index0 = it->second; if(it != weights.begin()) { it--; weight1 = it->first; index1 = it->second; if(it != weights.begin()) { it--; weight2 = it->first; index2 = it->second; } } float sum_weights = weight0 + weight1 + weight2; // store the skin weights viw.weight[0] = weight0/sum_weights; viw.index[0] = index0; viw.weight[1] = weight1/sum_weights; viw.index[1] = index1; viw.weight[2] = weight2/sum_weights; viw.index[2] = index2; skin.weights.push_back(viw); } // get the initial transforms skin.transforms.resize(skin.bones.size()); for(int i = 0; i < skin.bones.size(); i++) { INode* node = skin.bones[i]; Matrix3 mat; if (SKIN_INVALID_NODE_PTR == i_skin->GetBoneInitTM( node, mat )) { if (SKIN_INVALID_NODE_PTR == i_skin->GetSkinInitTM( node, mat )) { mat.IdentityMatrix(); } } skin.transforms[i] = Inverse(mat); } // there is a 75 bone limit for each skinned object. if(skin.bones.size()>75) { G3DAssert("There are more %d bones in the skin(%s).",skin.bones.size(), i_node->GetName()); return; } // reset the skin vertex position for(int i = 0; i < skin.vertexes.size(); i++) { VPTNIS& v0 = skin.vertexes[i]; VPIW& v1 = skin.weights[v0.index]; v0.pos = v1.pos; } // build the normal space BuildNormal(skin); // calculate the bounding box skin.box.Init(); for(int i = 0; i < skin.vertexes.size(); i++) { Point3 pt = node_matrix * skin.vertexes[i].pos; skin.box += pt; } // add the skin to the table mSkins.push_back(skin); }
// Returns the point to be shaded in object coordinates. Point3 SContext::PObj(void) { return Inverse(tmAfterWSM) * P(); }
// Returns the point to be shaded in object coordinates. Point3 SContext::PObj(void) { SCDebugPrint("SContext::PObj\n"); Matrix3 camToObj = Inverse(pInst->objToWorld * renderer->view.affineTM); return camToObj * P(); }
int EditPatchMod::DoAttach(INode *node, PatchMesh *attPatch, RPatchMesh *rattPatch, bool & canUndo) { ModContextList mcList; INodeTab nodes; if (!ip) return 0; ip->GetModContexts(mcList, nodes); if (mcList.Count() != 1) { nodes.DisposeTemporary(); return 0; } EditPatchData *patchData =(EditPatchData*)mcList[0]->localData; if (!patchData) { nodes.DisposeTemporary(); return 0; } // If the mesh isn't yet cached, this will cause it to get cached. RPatchMesh *rpatch; PatchMesh *patch = patchData->TempData(this)->GetPatch(ip->GetTime(), rpatch); if (!patch) { nodes.DisposeTemporary(); return 0; } patchData->RecordTopologyTags(patch); RecordTopologyTags(); patchData->BeginEdit(ip->GetTime()); // Transform the shape for attachment: // If reorienting, just translate to align pivots // Otherwise, transform to match our transform Matrix3 attMat(1); if (attachReorient) { Matrix3 thisTM = nodes[0]->GetNodeTM(ip->GetTime()); Matrix3 thisOTMBWSM = nodes[0]->GetObjTMBeforeWSM(ip->GetTime()); Matrix3 thisPivTM = thisTM * Inverse(thisOTMBWSM); Matrix3 otherTM = node->GetNodeTM(ip->GetTime()); Matrix3 otherOTMBWSM = node->GetObjTMBeforeWSM(ip->GetTime()); Matrix3 otherPivTM = otherTM * Inverse(otherOTMBWSM); Point3 otherObjOffset = node->GetObjOffsetPos(); attMat = Inverse(otherPivTM) * thisPivTM; } else { attMat = node->GetObjectTM(ip->GetTime()) * Inverse(nodes[0]->GetObjectTM(ip->GetTime())); } // RB 3-17-96 : Check for mirroring AffineParts parts; decomp_affine(attMat, &parts); if (parts.f < 0.0f) { int v[8], ct, ct2, j; int tvInteriors[4], tvHandles[8]; Point3 p[9]; for (int i = 0; i < attPatch->numPatches; i++) { // Re-order rpatch if (attPatch->patches[i].type == PATCH_QUAD) { UI_PATCH rpatch=rattPatch->getUIPatch (i); int ctU=rpatch.NbTilesU<<1; int ctV=rpatch.NbTilesV<<1; int nU; for (nU=0; nU<ctU; nU++) { for (int nV=0; nV<ctV; nV++) { rattPatch->getUIPatch (i).getTileDesc (nU+nV*ctU)=rpatch.getTileDesc (ctU-1-nU+(ctV-1-nV)*ctU); } } for (nU=0; nU<ctU+1; nU++) { for (int nV=0; nV<ctV+1; nV++) { rattPatch->getUIPatch (i).setColor (nU+nV*(ctU+1), rpatch.getColor (ctU-nU+(ctV-nV)*ctU)); } } } // Re-order vertices ct = attPatch->patches[i].type == PATCH_QUAD ? 4 : 3; for (j = 0; j < ct; j++) { v[j] = attPatch->patches[i].v[j]; } for (j = 0; j < ct; j++) { attPatch->patches[i].v[j] = v[ct - j - 1]; } // Re-order vecs ct = attPatch->patches[i].type == PATCH_QUAD ? 8 : 6; ct2 = attPatch->patches[i].type == PATCH_QUAD ? 5 : 3; for (j = 0; j < ct; j++) { v[j] = attPatch->patches[i].vec[j]; } for (j = 0; j < ct; j++, ct2--) { if (ct2 < 0) ct2 = ct - 1; attPatch->patches[i].vec[j] = v[ct2]; } // Re-order enteriors if (attPatch->patches[i].type == PATCH_QUAD) { ct = 4; for (j = 0; j < ct; j++) { v[j] = attPatch->patches[i].interior[j]; } for (j = 0; j < ct; j++) { attPatch->patches[i].interior[j] = v[ct - j - 1]; } } // Re-order aux if (attPatch->patches[i].type == PATCH_TRI) { ct = 9; for (j = 0; j < ct; j++) { p[j] = attPatch->patches[i].aux[j]; } for (j = 0; j < ct; j++) { attPatch->patches[i].aux[j] = p[ct - j - 1]; } } #if (MAX_RELEASE < 4000) /* #if (MAX_RELEASE < 4000) */ // Re-order TV faces if present for (int chan = 0; chan < patch->getNumMaps(); ++chan) { if (attPatch->tvPatches[chan]) { ct = 4; for (j = 0; j < ct; j++) { v[j] = attPatch->tvPatches[chan][i].tv[j]; } for (j = 0; j < ct; j++) { attPatch->tvPatches[chan][i].tv[j] = v[ct - j - 1]; } } } #else /* #if (MAX_RELEASE < 4000) #else */ // Re-order TV faces if present for(int chan = -NUM_HIDDENMAPS; chan < patch->getNumMaps(); ++chan) { if (chan < attPatch->getNumMaps() && attPatch->mapPatches(chan)) { ct = attPatch->patches[i].type==PATCH_QUAD ? 4 : 3; for (j=0; j<ct; j++) { v[j] = attPatch->mapPatches(chan)[i].tv[j]; tvInteriors[j] = attPatch->mapPatches(chan)[i].interiors[j]; int a; int b; a = j*2-1; b = j*2; if (a<0) a = ct*2-1; tvHandles[j*2] = attPatch->mapPatches(chan)[i].handles[a]; tvHandles[j*2+1] = attPatch->mapPatches(chan)[i].handles[b]; } for (j=0; j<ct; j++) { attPatch->mapPatches(chan)[i].tv[j] = v[ct-j-1]; attPatch->mapPatches(chan)[i].interiors[j] = tvInteriors[(ct)-(j)-1]; int index = ct-j-1; int a; int b; a = j*2-1; b = j*2; if (a<0) a = ct*2-1; attPatch->mapPatches(chan)[i].handles[b] = tvHandles[index*2]; attPatch->mapPatches(chan)[i].handles[a] = tvHandles[index*2+1]; } } } #endif /* #if (MAX_RELEASE < 4000) #else #endif */ } } int i; for (i = 0; i < attPatch->numVerts; ++i) attPatch->verts[i].p = attPatch->verts[i].p * attMat; for (i = 0; i < attPatch->numVecs; ++i) attPatch->vecs[i].p = attPatch->vecs[i].p * attMat; attPatch->computeInteriors(); theHold.Begin(); // Combine the materials of the two nodes. int mat2Offset = 0; Mtl *m1 = nodes[0]->GetMtl(); Mtl *m2 = node->GetMtl(); bool condenseMe = FALSE; if (m1 && m2 &&(m1 != m2)) { if (attachMat == ATTACHMAT_IDTOMAT) { int ct = 1; if (m1->IsMultiMtl()) ct = m1->NumSubMtls(); for (int i = 0; i < patch->numPatches; ++i) { int mtid = patch->getPatchMtlIndex(i); if (mtid >= ct) patch->setPatchMtlIndex(i, mtid % ct); } FitPatchIDsToMaterial(*attPatch, m2); if (condenseMat) condenseMe = TRUE; } // the theHold calls here were a vain attempt to make this all undoable. // This should be revisited in the future so we don't have to use the SYSSET_CLEAR_UNDO. theHold.Suspend(); if (attachMat == ATTACHMAT_MATTOID) { m1 = FitMaterialToPatchIDs(*patch, m1); m2 = FitMaterialToPatchIDs(*attPatch, m2); } Mtl *multi = CombineMaterials(m1, m2, mat2Offset); if (attachMat == ATTACHMAT_NEITHER) mat2Offset = 0; theHold.Resume(); // We can't be in face subobject mode, else we screw up the materials: DWORD oldSL = patch->selLevel; DWORD roldSL = patch->selLevel; patch->selLevel = PATCH_OBJECT; rpatch->SetSelLevel (EP_OBJECT); nodes[0]->SetMtl(multi); patch->selLevel = oldSL; rpatch->SetSelLevel (roldSL); m1 = multi; canUndo = FALSE; // Absolutely cannot undo material combinations. } if (!m1 && m2) { // We can't be in face subobject mode, else we screw up the materials: DWORD oldSL = patch->selLevel; DWORD roldSL = rpatch->GetSelLevel(); patch->selLevel = PATCH_OBJECT; rpatch->SetSelLevel (EP_OBJECT); nodes[0]->SetMtl(m2); patch->selLevel = oldSL; rpatch->SetSelLevel (roldSL); m1 = m2; } // Start a restore object... if (theHold.Holding()) theHold.Put(new PatchRestore(patchData, this, patch, rpatch, "DoAttach")); // Do the attach patch->Attach(attPatch, mat2Offset); rpatch->Attach(rattPatch, *patch); patchData->UpdateChanges(patch, rpatch); patchData->TempData(this)->Invalidate(PART_TOPO | PART_GEOM); // Get rid of the original node ip->DeleteNode(node); ResolveTopoChanges(); theHold.Accept(GetString(IDS_TH_ATTACH)); if (m1 && condenseMe) { // Following clears undo stack. patch = patchData->TempData(this)->GetPatch(ip->GetTime(), rpatch); m1 = CondenseMatAssignments(*patch, m1); } nodes.DisposeTemporary(); ClearPatchDataFlag(mcList, EPD_BEENDONE); NotifyDependents(FOREVER, PART_TOPO | PART_GEOM, REFMSG_CHANGE); ip->RedrawViews(ip->GetTime(), REDRAW_NORMAL); return 1; }
bool TransformedPrimitive::IntersectP(const Ray &r) const { Transform InterpolatedPrimToWorld; PrimitiveToWorld.Interpolate(r.time, &InterpolatedPrimToWorld); Transform InterpolatedWorldToPrim = Inverse(InterpolatedPrimToWorld); return primitive->IntersectP(InterpolatedWorldToPrim(r)); }
TArray<FArrangedWidget> FHittestGrid::GetBubblePath( FVector2D DesktopSpaceCoordinate, bool bIgnoreEnabledStatus ) { if (WidgetsCachedThisFrame->Num() > 0 && Cells.Num() > 0) { const FVector2D CursorPositionInGrid = DesktopSpaceCoordinate - GridOrigin; const FIntPoint CellCoordinate = FIntPoint( FMath::Min( FMath::Max(FMath::FloorToInt(CursorPositionInGrid.X / CellSize.X), 0), NumCells.X-1), FMath::Min( FMath::Max(FMath::FloorToInt(CursorPositionInGrid.Y / CellSize.Y), 0), NumCells.Y-1 ) ); static FVector2D LastCoordinate = FVector2D::ZeroVector; if ( LastCoordinate != CursorPositionInGrid ) { LastCoordinate = CursorPositionInGrid; } checkf( (CellCoordinate.Y*NumCells.X + CellCoordinate.X) < Cells.Num(), TEXT("Index out of range, CellCoordinate is: %d %d CursorPosition is: %f %f"), CellCoordinate.X, CellCoordinate.Y, CursorPositionInGrid.X, CursorPositionInGrid.Y ); const TArray<int32>& IndexesInCell = CellAt( CellCoordinate.X, CellCoordinate.Y ).CachedWidgetIndexes; int32 HitWidgetIndex = INDEX_NONE; // Consider front-most widgets first for hittesting. for ( int32 i = IndexesInCell.Num()-1; i>=0 && HitWidgetIndex==INDEX_NONE; --i ) { check( IndexesInCell[i] < WidgetsCachedThisFrame->Num() ); const FCachedWidget& TestCandidate = (*WidgetsCachedThisFrame)[IndexesInCell[i]]; // Compute the render space clipping rect (FGeometry exposes a layout space clipping rect). FSlateRotatedRect DesktopOrientedClipRect = TransformRect( Concatenate( Inverse(TestCandidate.CachedGeometry.GetAccumulatedLayoutTransform()), TestCandidate.CachedGeometry.GetAccumulatedRenderTransform() ), FSlateRotatedRect(TestCandidate.CachedGeometry.GetClippingRect().IntersectionWith(TestCandidate.ClippingRect)) ); if (DesktopOrientedClipRect.IsUnderLocation(DesktopSpaceCoordinate) && TestCandidate.WidgetPtr.IsValid()) { HitWidgetIndex = IndexesInCell[i]; } } if (HitWidgetIndex != INDEX_NONE) { TArray<FArrangedWidget> BubblePath; int32 CurWidgetIndex=HitWidgetIndex; bool bPathUninterrupted = false; do { check( CurWidgetIndex < WidgetsCachedThisFrame->Num() ); const FCachedWidget& CurCachedWidget = (*WidgetsCachedThisFrame)[CurWidgetIndex]; const TSharedPtr<SWidget> CachedWidgetPtr = CurCachedWidget.WidgetPtr.Pin(); bPathUninterrupted = CachedWidgetPtr.IsValid(); if (bPathUninterrupted) { BubblePath.Insert(FArrangedWidget(CachedWidgetPtr.ToSharedRef(), CurCachedWidget.CachedGeometry), 0); CurWidgetIndex = CurCachedWidget.ParentIndex; } } while (CurWidgetIndex != INDEX_NONE && bPathUninterrupted); if (!bPathUninterrupted) { // A widget in the path to the root has been removed, so anything // we thought we had hittest is no longer actually there. // Pretend we didn't hit anything. BubblePath = TArray<FArrangedWidget>(); } // Disabling a widget disables all of its logical children // This effect is achieved by truncating the path to the // root-most enabled widget. if ( !bIgnoreEnabledStatus ) { const int32 DisabledWidgetIndex = BubblePath.IndexOfByPredicate( []( const FArrangedWidget& SomeWidget ){ return !SomeWidget.Widget->IsEnabled( ); } ); if (DisabledWidgetIndex != INDEX_NONE) { BubblePath.RemoveAt( DisabledWidgetIndex, BubblePath.Num() - DisabledWidgetIndex ); } } return BubblePath; } else { return TArray<FArrangedWidget>(); } } else { return TArray<FArrangedWidget>(); } }
Matrix3 plMaxNodeBase::GetParentToLocal(TimeValue t) { Matrix3 loc2Par = GetLocalToParent(t); Matrix3 par2Loc = Inverse(loc2Par); return par2Loc; }
int32 SSlider::OnPaint( const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled ) const { // we draw the slider like a horizontal slider regardless of the orientation, and apply a render transform to make it display correctly. // However, the AllottedGeometry is computed as it will be rendered, so we have to use the "horizontal orientation" when doing drawing computations. const float AllottedWidth = Orientation == Orient_Horizontal ? AllottedGeometry.GetLocalSize().X : AllottedGeometry.GetLocalSize().Y; const float AllottedHeight = Orientation == Orient_Horizontal ? AllottedGeometry.GetLocalSize().Y : AllottedGeometry.GetLocalSize().X; float HandleRotation; FVector2D HandleTopLeftPoint; FVector2D SliderStartPoint; FVector2D SliderEndPoint; // calculate slider geometry as if it's a horizontal slider (we'll rotate it later if it's vertical) const FVector2D HandleSize = Style->NormalThumbImage.ImageSize; const FVector2D HalfHandleSize = 0.5f * HandleSize; const float Indentation = IndentHandle.Get() ? HandleSize.X : 0.0f; const float SliderLength = AllottedWidth - Indentation; const float SliderPercent = ValueAttribute.Get(); const float SliderHandleOffset = SliderPercent * SliderLength; const float SliderY = 0.5f * AllottedHeight; HandleRotation = 0.0f; HandleTopLeftPoint = FVector2D(SliderHandleOffset - ( HandleSize.X * SliderPercent ) + 0.5f * Indentation, SliderY - HalfHandleSize.Y); SliderStartPoint = FVector2D(HalfHandleSize.X, SliderY); SliderEndPoint = FVector2D(AllottedWidth - HalfHandleSize.X, SliderY); FSlateRect RotatedClippingRect = MyClippingRect; FGeometry SliderGeometry = AllottedGeometry; // rotate the slider 90deg if it's vertical. The 0 side goes on the bottom, the 1 side on the top. if (Orientation == Orient_Vertical) { // Do this by translating along -X by the width of the geometry, then rotating 90 degreess CCW (left-hand coords) FSlateRenderTransform SlateRenderTransform = TransformCast<FSlateRenderTransform>(Concatenate(Inverse(FVector2D(AllottedWidth, 0)), FQuat2D(FMath::DegreesToRadians(-90.0f)))); // create a child geometry matching this one, but with the render transform. SliderGeometry = AllottedGeometry.MakeChild( FVector2D(AllottedWidth, AllottedHeight), FSlateLayoutTransform(), SlateRenderTransform, FVector2D::ZeroVector); // The clipping rect is already given properly in window space. But we do not support layout rotations, so our local space rendering cannot // get the clipping rect into local space properly for the local space clipping we do in the shader. // Thus, we transform the clip coords into local space manually, UNDO the render transform so it will clip properly, // and then bring the clip coords back into window space where DrawElements expect them. RotatedClippingRect = TransformRect( Concatenate( Inverse(SliderGeometry.GetAccumulatedLayoutTransform()), Inverse(SlateRenderTransform), SliderGeometry.GetAccumulatedLayoutTransform()), MyClippingRect); } const bool bEnabled = ShouldBeEnabled(bParentEnabled); const ESlateDrawEffect::Type DrawEffects = bEnabled ? ESlateDrawEffect::None : ESlateDrawEffect::DisabledEffect; // draw slider bar auto BarTopLeft = FVector2D(SliderStartPoint.X, SliderStartPoint.Y - Style->BarThickness * 0.5f); auto BarSize = FVector2D(SliderEndPoint.X - SliderStartPoint.X, Style->BarThickness); FSlateDrawElement::MakeBox( OutDrawElements, LayerId, SliderGeometry.ToPaintGeometry(BarTopLeft, BarSize), LockedAttribute.Get() ? &Style->DisabledBarImage : &Style->NormalBarImage, RotatedClippingRect, DrawEffects, SliderBarColor.Get().GetColor(InWidgetStyle) * InWidgetStyle.GetColorAndOpacityTint() ); ++LayerId; // draw slider thumb FSlateDrawElement::MakeBox( OutDrawElements, LayerId, SliderGeometry.ToPaintGeometry(HandleTopLeftPoint, Style->NormalThumbImage.ImageSize), LockedAttribute.Get() ? &Style->DisabledThumbImage : &Style->NormalThumbImage, RotatedClippingRect, DrawEffects, SliderHandleColor.Get().GetColor(InWidgetStyle) * InWidgetStyle.GetColorAndOpacityTint() ); return LayerId; }
Matrix3 plMaxNodeBase::GetWorldToLocal(TimeValue t) { Matrix3 l2w = GetLocalToWorld(t); Matrix3 w2l = Inverse(l2w); return w2l; }
void UnwrapMod::ApplyGizmo() { if ((fnGetMapMode() == PLANARMAP) || (fnGetMapMode() == PELTMAP) || (fnGetMapMode() == SPHERICALMAP) || (fnGetMapMode() == CYLINDRICALMAP)) { ApplyGizmoPrivate(); } else { theHold.Begin(); //compute the center //get our normal list for (int ldID = 0; ldID < mMeshTopoData.Count(); ldID++) { MeshTopoData *ld = mMeshTopoData[ldID]; ld->HoldFaceSel(); } for (int ldID = 0; ldID < mMeshTopoData.Count(); ldID++) { MeshTopoData *ld = mMeshTopoData[ldID]; ld->HoldFaceSel(); Tab<Point3> fnorms; fnorms.SetCount(ld->GetNumberFaces()); for (int k=0; k< fnorms.Count(); k++) fnorms[k] = Point3(0.0f,0.0f,0.0f); //get our projection normal Point3 projectionNorm(0.0f,0.0f,0.0f); //build normals for (int k = 0; k < fnorms.Count(); k++) { if (ld->GetFaceSelected(k)) { // Grap the three points, xformed int pcount = 3; // if (gfaces[k].flags & FLAG_QUAD) pcount = 4; pcount = ld->GetFaceDegree(k);//gfaces[k]->count; Point3 temp_point[4]; for (int j=0; j<pcount; j++) { int index = ld->GetFaceGeomVert(k,j);//gfaces[k]->t[j]; if (j < 4) temp_point[j] = ld->GetGeomVert(index);//gverts.d[index].p; } fnorms[k] = Normalize(temp_point[1]-temp_point[0]^temp_point[2]-temp_point[1]); } } BitArray front,back,left,right,top,bottom; front.SetSize(ld->GetNumberFaces()); front.ClearAll(); back = front; left = front; right = front; top = front; bottom = front; Tab<Point3> norms; Matrix3 gtm(1); TimeValue t = 0; if (ip) t = ip->GetTime(); if (tmControl) tmControl->GetValue(t,>m,FOREVER,CTRL_RELATIVE); norms.SetCount(6); for (int i = 0; i < 3; i++) { Point3 v = gtm.GetRow(i); norms[i*2] = Normalize(v); norms[i*2+1] = norms[i*2] * -1.0f; } for (int k=0; k< ld->GetNumberFaces(); k++) { if (ld->GetFaceSelected(k)) { int closestFace = -1; float closestAngle = -10.0f; for (int j = 0; j < 6; j++) { float dot = DotProd(norms[j],fnorms[k]); if (dot > closestAngle) { closestAngle = dot; closestFace = j; } } if (closestFace == 0) front.Set(k,TRUE); else if (closestFace == 1) back.Set(k,TRUE); else if (closestFace == 2) left.Set(k,TRUE); else if (closestFace == 3) right.Set(k,TRUE); else if (closestFace == 4) top.Set(k,TRUE); else if (closestFace == 5) bottom.Set(k,TRUE); } } gtm.IdentityMatrix(); if (tmControl) tmControl->GetValue(t,>m,FOREVER,CTRL_RELATIVE); Point3 xvec,yvec,zvec; xvec = gtm.GetRow(0); yvec = gtm.GetRow(1); zvec = gtm.GetRow(2); Point3 center = gtm.GetRow(3); for (int k = 0; k < 6; k++) { Matrix3 tm(1); if (k == 0) { tm.SetRow(0,yvec); tm.SetRow(1,zvec); tm.SetRow(2,xvec); ld->SetFaceSelection(front); } else if (k == 1) { tm.SetRow(0,yvec); tm.SetRow(1,zvec); tm.SetRow(2,(xvec*-1.0f)); ld->SetFaceSelection(back); } else if (k == 2) { tm.SetRow(0,xvec); tm.SetRow(1,zvec); tm.SetRow(2,yvec); ld->SetFaceSelection(left); } else if (k == 3) { tm.SetRow(0,xvec); tm.SetRow(1,zvec); tm.SetRow(2,(yvec *-1.0f)); ld->SetFaceSelection(right); } else if (k == 4) { tm.SetRow(0,xvec); tm.SetRow(1,yvec); tm.SetRow(2,zvec); ld->SetFaceSelection(top); } else if (k == 5) { tm.SetRow(0,xvec); tm.SetRow(1,yvec); tm.SetRow(2,(zvec*-1.0f)); ld->SetFaceSelection(bottom); } tm.SetRow(3,center); if (!fnGetNormalizeMap()) { for (int i = 0; i < 3; i++) { Point3 vec = tm.GetRow(i); vec = Normalize(vec); tm.SetRow(i,vec); } } tm = mMeshTopoData.GetNodeTM(t,ldID) * Inverse(tm); ld->ApplyMap(fnGetMapMode(), fnGetNormalizeMap(), tm, this); } ld->RestoreFaceSel(); } theHold.Accept(GetString(IDS_PW_PLANARMAP)); } }
template <class T> const T& AbstractGroup<T>::Subtract(const Element &a, const Element &b) const { // make copy of a in case Inverse() overwrites it Element a1(a); return Add(a1, Inverse(b)); }