Point3 PBombField::Force(TimeValue t,const Point3 &pos, const Point3 &vel,int index) { float d,chaos,dv; Point3 dlta,xb,yb,zb,center,expv; int decaytype,symm; Point3 zero=Zero; fValid = FOREVER; if (!tmValid.InInterval(t)) { tmValid = FOREVER; tm = node->GetObjectTM(t,&tmValid); invtm = Inverse(tm); } xb=tm.GetRow(0); yb=tm.GetRow(1); zb=tm.GetRow(2); center=tm.GetTrans(); fValid &= tmValid; TimeValue t0,t2,lastsfor; obj->pblock->GetValue(PB_STARTTIME,t,t0,fValid); obj->pblock->GetValue(PB_LASTSFOR,t,lastsfor,fValid); t2=t0+lastsfor; dlta=Zero; if ((t>=t0)&&(t<=t2)) { float L=Length(dlta=pos-center); obj->pblock->GetValue(PB_DECAY,t,d,fValid); obj->pblock->GetValue(PB_DECAYTYPE,t,decaytype,fValid); if ((decaytype==0)||(L<=d)) { obj->pblock->GetValue(PB_DELTA_V,t,dv,fValid); obj->pblock->GetValue(PB_CHAOS,t,chaos,fValid); obj->pblock->GetValue(PB_SYMMETRY,t,symm,fValid); Point3 r; if (symm==SPHERE) expv=(r=dlta/L); else if (symm==PLANAR) { L=DotProd(dlta,zb); expv=(L<0.0f?L=-L,-zb:zb); } else { Point3 E; E=DotProd(dlta,xb)*xb+DotProd(dlta,yb)*yb; L=Length(E); expv=E/L; } dlta=(dv*expv)/(float)dtsq; if (decaytype==1) dlta*=(d-L)/d; else if (decaytype==2) dlta*=(1/(float)exp(L/d)); if ((!FloatEQ0(chaos))&&(lastsfor==0.0f)) { float theta; theta=HalfPI*chaos*RND01(); // Martell 4/14/01: Fix for order of ops bug. float ztmp=RND11(); float ytmp=RND11(); float xtmp=RND11(); Point3 d=Point3(xtmp,ytmp,ztmp); Point3 c=Normalize(dlta^d); RotateOnePoint(&dlta.x,&zero.x,&c.x,theta); } } else dlta=Zero; } return dlta; }
// ============================================================================ // Convert a MAX TM to an OpenGL TM void TM3ToGLTM4(const Matrix3 &tm, float glTM[16]) { Matrix3 maxTM = tm; FixCoordSys(maxTM); Point3 row = maxTM.GetRow(0); glTM[0] = row.x; glTM[1] = row.y; glTM[2] = row.z; glTM[3] = 0.f; row = maxTM.GetRow(1); glTM[4] = row.x; glTM[5] = row.y; glTM[6] = row.z; glTM[7] = 0.f; row = maxTM.GetRow(2); glTM[8] = row.x; glTM[9] = row.y; glTM[10] = row.z; glTM[11] = 0.f; row = maxTM.GetRow(3); glTM[12] = row.x; glTM[13] = row.y; glTM[14] = row.z; glTM[15] = 1.f; }
/** * @brief * Transforms a 3ds Max matrix to a OpenGL matrix */ Matrix3 PLTools::Convert3dsMaxMatrixToOpenGLMatrix(const Matrix3 &mMatrix) { return Matrix3( Convert3dsMaxVectorToOpenGLVector(mMatrix.GetRow(0)), Convert3dsMaxVectorToOpenGLVector(mMatrix.GetRow(2)), -Convert3dsMaxVectorToOpenGLVector(mMatrix.GetRow(1)), Convert3dsMaxVectorToOpenGLVector(mMatrix.GetRow(3))); }
void makBoneTrans2(INode* pNode , sBoneTrans_t& boneTrans , Matrix3& mat) { Point3 Trans = mat.GetTrans(); Matrix3 RotMat = mat; Matrix3 ScaleMat = mat; RotMat.NoScale(); ScaleMat = mat * Inverse(RotMat); //算出Scale Matrix; RotMat.NoTrans(); Quat RotQuat(RotMat); //ScaleMat.NoRot(); //ScaleMat.NoTrans(); boneTrans.m_Rotate = conv_type<sQuat_t , Quat>(RotQuat); boneTrans.m_Trans = conv_type<sVector_t ,Point3 >(Trans); boneTrans.m_Scale.x = ScaleMat.GetRow(0).x; boneTrans.m_Scale.y = ScaleMat.GetRow(1).y; boneTrans.m_Scale.z = ScaleMat.GetRow(2).z; if( abs(boneTrans.m_Scale.x - boneTrans.m_Scale.y) > 0.000001 || abs(boneTrans.m_Scale.y - boneTrans.m_Scale.z) > 0.000001 || abs(boneTrans.m_Scale.z - boneTrans.m_Scale.x) > 0.000001 ) { std::wstring _NodeName = INodeName(pNode); XEVOL_LOG(eXL_DEBUG_HIGH , L" {警告} : 骨头[ %s ] 的上有NonUniformScale\r\n", _NodeName.c_str() ); } }
BOOL MeshExpUtility::BuildObject(CEditableObject*& exp_obj, LPCSTR m_ExportName) { bool bResult = true; if (m_ExportName[0]==0) return false; ELog.Msg(mtInformation,"Building object..." ); char fname[256]; _splitpath( m_ExportName, 0, 0, fname, 0 ); exp_obj = xr_new<CEditableObject>(fname); exp_obj->SetVersionToCurrent(TRUE,TRUE); ExportItemIt it = m_Items.begin(); for(;it!=m_Items.end();it++){ CEditableMesh *submesh = xr_new<CEditableMesh>(exp_obj); ELog.Msg(mtInformation,"Converting node '%s'...", it->pNode->GetName()); if( submesh->Convert(it->pNode) ){ // transform Matrix3 mMatrix; mMatrix = it->pNode->GetNodeTM(0)*Inverse(it->pNode->GetParentNode()->GetNodeTM(0)); Point3 r1 = mMatrix.GetRow(0); Point3 r2 = mMatrix.GetRow(1); Point3 r3 = mMatrix.GetRow(2); Point3 r4 = mMatrix.GetRow(3); Fmatrix m; m.identity(); m.i.set(r1.x, r1.z, r1.y); m.j.set(r2.x, r2.z, r2.y); m.k.set(r3.x, r3.z, r3.y); m.c.set(r4.x, r4.z, r4.y); submesh->Transform( m ); // flip faces Fvector v; v.crossproduct(m.j, m.k); if(v.dotproduct(m.i)<0.f) submesh->FlipFaces(); if(m_ObjectFlipFaces) submesh->FlipFaces(); submesh->RecomputeBBox(); // append mesh submesh->SetName (it->pNode->GetName()); exp_obj->m_Meshes.push_back (submesh); }else{ ELog.Msg(mtError,"! can't convert", it->pNode->GetName()); xr_delete(submesh); bResult = false; break; } } if (bResult){ exp_obj->UpdateBox (); exp_obj->VerifyMeshNames(); ELog.Msg (mtInformation,"Object '%s' contains: %d points, %d faces", exp_obj->GetName(), exp_obj->GetVertexCount(), exp_obj->GetFaceCount()); }else{ xr_delete(exp_obj); } //------------------------------------------------------------------- return bResult; }
void Exporter::convertMatrix(Matrix33 &dst, const Matrix3 &src) { Point3 r0 = src.GetRow(0); Point3 r1 = src.GetRow(1); Point3 r2 = src.GetRow(2); dst.Set(r0.x, r0.y, r0.z, r1.x, r1.y, r1.z, r2.x, r2.y, r2.z); }
void Matrix3ToMatrix4(D3DXMATRIX& Mat, const Matrix3& Mat3) { Point3 Row = Mat3.GetRow(0); Mat.m[0][0] = Row.x; Mat.m[0][1] = Row.y; Mat.m[0][2] = Row.z; Mat.m[0][3] = 0; Row = Mat3.GetRow(1); Mat.m[1][0] = Row.x; Mat.m[1][1] = Row.y; Mat.m[1][2] = Row.z; Mat.m[1][3] = 0; Row = Mat3.GetRow(2); Mat.m[2][0] = Row.x; Mat.m[2][1] = Row.y; Mat.m[2][2] = Row.z; Mat.m[2][3] = 0; Row = Mat3.GetRow(3); Mat.m[3][0] = Row.x; Mat.m[3][1] = Row.y; Mat.m[3][2] = Row.z; Mat.m[3][3] = 1; }
void FormationBhvr::AppendFollowerMatrix(TimeValue t,Matrix3 &mat) { Point3 *points; points = new Point3; *points = mat.GetRow(0); pblock->Append(follower_matrix1,1,&points,1); *points = mat.GetRow(1); pblock->Append(follower_matrix2,1,&points,1); *points = mat.GetRow(2); pblock->Append(follower_matrix3,1,&points,1); *points = mat.GetRow(3); pblock->Append(follower_matrix4,1,&points,1); delete points; }
Mat4 Convert( const Matrix3& m ) { Mat4 tm; tm.e00 = m.GetRow(0).x; tm.e01 = m.GetRow(0).y; tm.e02 = m.GetRow(0).z; tm.e03 = 0.0f; tm.e10 = m.GetRow(1).x; tm.e11 = m.GetRow(1).y; tm.e12 = m.GetRow(1).z; tm.e13 = 0.0f; tm.e20 = m.GetRow(2).x; tm.e21 = m.GetRow(2).y; tm.e22 = m.GetRow(2).z; tm.e23 = 0.0f; tm.e30 = m.GetRow(3).x; tm.e31 = m.GetRow(3).y; tm.e32 = m.GetRow(3).z; tm.e33 = 1.0f; return tm; } // Convert
bool NoniterativeEigen3x3<Real>::PositiveRank (Matrix3<Real>& M, Real& maxEntry, Vector3<Real>& maxRow) const { // Locate the maximum-magnitude entry of the matrix. maxEntry = (Real)-1; int row, maxRowIndex = -1; for (row = 0; row < 3; ++row) { for (int col = row; col < 3; ++col) { Real absValue = Math<Real>::FAbs(M[row][col]); if (absValue > maxEntry) { maxEntry = absValue; maxRowIndex = row; } } } // Return the row containing the maximum, to be used for eigenvector // construction. maxRow = M.GetRow(maxRowIndex); return maxEntry >= Math<Real>::ZERO_TOLERANCE; }
void SpotLightFalloffManipulator::UpdateShapes(TimeValue t, TSTR& toolTip) { GenLight* pLight = (GenLight*) mhTarget; Matrix3 tm; tm = mpINode->GetObjectTM(t); Point3 pt; b = GetTargetPoint(t, pt); if (!b) return; float den = FLength(tm.GetRow(2)); float dist = (den!=0) ? FLength(tm.GetTrans()-pt) / den : 0.0f; TSTR nodeName; nodeName = mpINode->GetName(); tm = Inverse(tm); toolTip.printf("Falloff: %5.2f", (double) pLight->GetFallsize(t)); SetGizmoScale(dist / kRingScaleFactor); ConeAngleManipulator::UpdateShapes(Point3(0,0,0), Point3(0,0,-1), dist, pLight->GetFallsize(t)); }
void SpotLightMultiplierManipulator::UpdateShapes(TimeValue t, TSTR& toolTip) { GenLight* pLight = (GenLight*) mhTarget; Matrix3 tm; tm = mpINode->GetObjectTM(t); Point3 pt; b = GetTargetPoint(t, pt); if (!b) return; TSTR nodeName; nodeName = mpINode->GetName(); float den = FLength(tm.GetRow(2)); float targetDist = (den!=0) ? FLength(tm.GetTrans()-pt) / den : 0.0f; toolTip.printf("%s: %5.2f", "Multiplier", (double) pLight->GetIntensity(t)); SetGizmoScale(targetDist / 40.0); float dist = (targetDist / 2.0) * pLight->GetIntensity(t); ConeDistanceManipulator::UpdateShapes(Point3(0,0,0), Point3(0,0,-1), dist, pLight->GetFallsize(t), true); }
void TapeHelpObject::GetWorldBoundBox(TimeValue t, INode* inode, ViewExp* vpt, Box3& box ) { if ( ! vpt || ! vpt->IsAlive() ) { box.Init(); return; } int i, nv; Matrix3 tm; float dtarg; Point3 pt; Point3 q[2]; GetMat(t,inode,*vpt,tm); nv = mesh.getNumVerts(); box.Init(); for (i=0; i<nv; i++) box += tm*mesh.getVert(i); if (GetTargetPoint(t,inode,pt)) { tm = inode->GetObjectTM(t); dtarg = Length(tm.GetTrans()-pt)/Length(tm.GetRow(2)); box += tm*Point3(float(0),float(0),-dtarg); } if(GetSpecLen()) { GetLinePoints(t, q, GetLength(t) ); box += tm * q[0]; box += tm * q[1]; } }
void Exporter::ExportNodeTM(INode* node, int indentLevel,rmatrix *mat) { Matrix3 pivot = node->GetNodeTM(GetStaticFrame()); // Export TM inheritance flags DWORD iFlags = node->GetTMController()->GetInheritanceFlags(); Point3 row; row = pivot.GetRow(0); mat->_11=-row.x;mat->_12=row.y;mat->_13=row.z;mat->_14=0; row = pivot.GetRow(1); mat->_21=-row.x;mat->_22=row.y;mat->_23=row.z;mat->_24=0; row = pivot.GetRow(2); mat->_31=-row.x;mat->_32=row.y;mat->_33=row.z;mat->_34=0; row = pivot.GetRow(3); mat->_41=-row.x;mat->_42=row.y;mat->_43=row.z;mat->_44=1; *mat=MatrixInverse(*mat); }
void SpotLightFalloffManipulator::UpdateShapes(TimeValue t, TSTR& toolTip) { GenLight* pLight = (GenLight*) mhTarget; Matrix3 tm; tm = mpINode->GetObjectTM(t); Point3 pt; float dist; BOOL b = GetTargetPoint(t, pt); if (!b) { dist = pLight->GetTDist(t); } else { float den = FLength(tm.GetRow(2)); dist = (den!=0) ? FLength(tm.GetTrans()-pt) / den : 0.0f; } TSTR nodeName; nodeName = mpINode->GetName(); toolTip.printf("%s [Falloff: %5.2f]", nodeName.data(), (double) pLight->GetFallsize(t)); SetGizmoScale(dist / kRingScaleFactor); ConeAngleManipulator::SetValues(Point3(0,0,0), Point3(0,0,-1), dist, DegToRad(pLight->GetFallsize(t)), pLight->GetSpotShape() == RECT_LIGHT, pLight->GetAspect(t)); }
// From BaseObject int TapeHelpObject::DrawLine(TimeValue t, INode* inode, GraphicsWindow *gw, int drawing ) { Matrix3 tm = inode->GetObjectTM(t); gw->setTransform(tm); gw->clearHitCode(); Point3 pt,v[3]; if (GetTargetPoint(t,inode,pt)) { float den = Length(tm.GetRow(2)); float dist = (den!=0)?Length(tm.GetTrans()-pt)/den : 0.0f; if(!inode->IsFrozen() && !inode->Dependent() && drawing) gw->setColor( LINE_COLOR, GetUIColor(COLOR_TAPE_OBJ)); if (drawing) { if(specLenState) { GetLinePoints(t, v, GetLength(t) ); if(drawing == -1) v[1] = 0.9f * v[1]; } else { v[0] = Point3(0,0,0); if(drawing == -1) // hit-testing! Shorten the line so target can be picked v[1] = Point3(0.0f, 0.0f, -0.9f * dist); else v[1] = Point3(0.0f, 0.0f, -dist); } gw->polyline( 2, v, NULL, NULL, FALSE, NULL ); } } return gw->checkHitCode(); }
static void TransformPlane(Matrix3& tm, Point4 plin, Point4 plout) { Point3 n = VectorTransform(tm, Point3(plin[0],plin[1],plin[2])); plout[0] = n.x; plout[1] = n.y; plout[2] = n.z; plout[3] = plin[3] - DotProd(tm.GetRow(3),n); }
void SpotLightAttenuationManipulator::UpdateShapes(TimeValue t, TSTR& toolTip) { GenLight* pLight = (GenLight*) mhTarget; Matrix3 tm; tm = mpINode->GetObjectTM(t); Point3 pt; b = GetTargetPoint(t, pt); if (!b) return; float dist = pLight->GetAtten(t, mAttenuationType); TSTR nodeName; nodeName = mpINode->GetName(); float den = FLength(tm.GetRow(2)); float targetDist = (den!=0) ? FLength(tm.GetTrans()-pt) / den : 0.0f; toolTip.printf("%s: %5.2f", mAttenName.data(), (double) dist); SetGizmoScale(targetDist / 40.0); ConeDistanceManipulator::UpdateShapes(Point3(0,0,0), Point3(0,0,-1), dist, pLight->GetFallsize(t), false); }
Void SoftBody::_UpdatePose() { if ( !(m_hPose.bIsFrame) ) return; // Update COM m_hPose.vCenterOfMass = _ComputeCenterOfMass(); // Update Rotation & Scaling const Node * pNode; UInt iNodeIndex; Vector3 vTmpRow, vWeigthedDelta; Matrix3 matRotScale; matRotScale.MakeNull(); matRotScale.m00 = SCALAR_EPSILON; matRotScale.m11 = SCALAR_EPSILON * 2.0f; matRotScale.m22 = SCALAR_EPSILON * 3.0f; EnumNodes(); pNode = EnumNextNode(); while( pNode != NULL ) { iNodeIndex = pNode->GetIndex(); const Vector3 & vDelta = m_hPose.arrDeltas[iNodeIndex]; vWeigthedDelta = ( (pNode->Position - m_hPose.vCenterOfMass) * m_hPose.arrWeights[iNodeIndex] ); matRotScale.GetRow( vTmpRow, 0 ); matRotScale.SetRow( 0, vTmpRow + (vDelta * vWeigthedDelta.X) ); matRotScale.GetRow( vTmpRow, 1 ); matRotScale.SetRow( 1, vTmpRow + (vDelta * vWeigthedDelta.Y) ); matRotScale.GetRow( vTmpRow, 2 ); matRotScale.SetRow( 2, vTmpRow + (vDelta * vWeigthedDelta.Z) ); pNode = EnumNextNode(); } Matrix3 matRot, matScale; matRotScale.PolarDecomposition( matRot, matScale ); m_hPose.matRotation = matRot; m_hPose.matScaling = ( m_hPose.matBaseScaling * matScale ); if ( m_fMaxVolumeRatio > 1.0f ) { Scalar fInvDet = Clamp<Scalar>( MathFn->Invert( m_hPose.matScaling.Determinant() ), 1.0f, m_fMaxVolumeRatio ); m_hPose.matScaling *= fInvDet; } }
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; }
void RemovePivotScale(INode* node) { const TimeValue t = ccMaxWorld::MaxTime(); Matrix3 nodeTM = node->GetNodeTM(t); Point3 pos = nodeTM.GetRow(3); Matrix3 objectTM = node->GetObjectTM(t); nodeTM = objectTM; nodeTM.SetRow(3, pos); Matrix3 pv = objectTM * Inverse(nodeTM); node->SetNodeTM(t, nodeTM); node->SetObjOffsetPos(pv.GetTrans()); node->SetObjOffsetRot(IdentQuat()); node->SetObjOffsetScale(ScaleValue(Point3(1,1,1))); }
int TapeHelpObject::Display(TimeValue t, INode* inode, ViewExp *vpt, int flags) { if ( ! vpt || ! vpt->IsAlive() ) { // why are we here DbgAssert(!_T("Invalid viewport!")); return FALSE; } Matrix3 m; GraphicsWindow *gw = vpt->getGW(); Material *mtl = gw->getMaterial(); GetMat(t,inode,*vpt,m); gw->setTransform(m); DWORD rlim = gw->getRndLimits(); gw->setRndLimits(GW_WIREFRAME|GW_EDGES_ONLY|GW_BACKCULL| (rlim&GW_Z_BUFFER) ); if (inode->Selected()) gw->setColor( LINE_COLOR, GetSelColor()); else if(!inode->IsFrozen() && !inode->Dependent()) gw->setColor( LINE_COLOR, GetUIColor(COLOR_TAPE_OBJ)); mesh.render( gw, mtl, NULL, COMP_ALL); DrawLine(t,inode,gw,1); gw->setRndLimits(rlim); if(editting && !specLenState) { Point3 pt(0,0,0); Matrix3 tm = inode->GetObjectTM(t); GetTargetPoint(t,inode,pt); float den = Length(tm.GetRow(2)); float dist = (den!=0)?Length(tm.GetTrans()-pt)/den : 0.0f; lengthSpin->SetValue( lastDist = dist, FALSE ); } if(editting) { m.NoTrans(); dirPt = m * Point3(0,0,1); float len = Length(dirPt); if(len != 0) dirPt *= 1.0f/len; UpdateUI(iObjParams->GetTime()); } return(0); }
void XsiExp::ExportNodeTM( INode * node, int indentLevel) { // dump the full matrix Matrix3 matrix = node->GetNodeTM(GetStaticFrame()); TSTR indent = GetIndent(indentLevel); fprintf(pStream,"%s\t%s {\n\n", indent.data(), "FrameTransformMatrix"); Object * obj = node->EvalWorldState(0).obj; BOOL isBone = obj && obj->ClassID() == Class_ID(BONE_CLASS_ID, 0) ? TRUE : FALSE; if (node->GetParentNode() && node->GetParentNode()->IsRootNode()) { // bone chains get grafted into the hierarchy tree // if (!isBone) { // root mesh oTopMatrix = matrix; AffineParts ap; decomp_affine( matrix, &ap); topMatrix.Set( Point3( ap.k.x,0.0f,0.0f), Point3( 0.0f,ap.k.z,0.0f), Point3(0.0f,0.0f,ap.k.y), Point3(0,0,0)); // root transform is controlled by the engine matrix.IdentityMatrix(); } } else { matrix = matrix * Inverse(node->GetParentTM(GetStaticFrame())); if (!isBone) { matrix.SetRow( 3, topMatrix * matrix.GetRow(3)); } } // write the matrix values DumpMatrix3( &matrix, indentLevel+2); // transform close brace fprintf(pStream,"%s\t}\n", indent.data()); }
void AFRMod::GetWorldBoundBox( TimeValue t,INode* inode, ViewExp *vpt, Box3& box, ModContext *mc) { Matrix3 tm = CompMatrix(t,inode,mc); Point3 pt1, pt2; box.Init(); p1->GetValue(t,&pt1,FOREVER,CTRL_ABSOLUTE); box += pt1 * tm; p2->GetValue(t,&pt2,FOREVER,CTRL_ABSOLUTE); box += pt2 * tm; Matrix3 vtm; vpt->GetAffineTM(vtm); Point3 vz = vtm.GetRow(2) * Inverse(tm); Point3 dp = (pt2-pt1); Point3 v = Normalize(vz^dp) * Length(dp) * 0.2f; box += (pt2 - (0.2f*dp) + v) * tm; box += (pt2 - (0.2f*dp) - v) * tm; v = Normalize(v^dp) * Length(dp) * 0.2f; box += (pt2 - (0.2f*dp) + v) * tm; box += (pt2 - (0.2f*dp) - v) * tm; }
void SpotLightMultiplierManipulator::SetDistance(float distance) { GenLight* pLight = (GenLight*) mhTarget; TimeValue t = GetCOREInterface()->GetTime(); Matrix3 tm; tm = mpINode->GetObjectTM(GetCOREInterface()->GetTime()); Point3 pt; b = GetTargetPoint(t, pt); if (!b) return; TSTR nodeName; nodeName = mpINode->GetName(); float den = FLength(tm.GetRow(2)); float targetDist = (den!=0) ? FLength(tm.GetTrans()-pt) / den : 0.0f; float mult = 2.0 * distance / targetDist; pLight->SetIntensity(t, mult); }
bool bgGlobalMax::CheckNegativeTM(Matrix3& m) { return (DotProd(CrossProd(m.GetRow(0), m.GetRow(1)), m.GetRow(2)) < 0.0) ? 1 : 0; }
int ExportQuake3Model(const TCHAR *filename, ExpInterface *ei, Interface *gi, int start_time, std::list<ExportNode> lTags, std::list<ExportNode> lMeshes) { FILE *file; int i, j, totalTags, totalMeshes, current_time = 0; long pos_current, totalTris = 0, totalVerts = 0; std::list<FrameRange>::iterator range_i; std::vector<Point3> lFrameBBoxMin; std::vector<Point3> lFrameBBoxMax; long pos_tagstart; long pos_tagend; long pos_filesize; long pos_framestart; int lazynamesfixed = 0; const Point3 x_axis(1, 0, 0); const Point3 z_axis(0, 0, 1); SceneEnumProc checkScene(ei->theScene, start_time, gi); totalTags = (int)lTags.size(); if (g_tag_for_pivot) totalTags++; totalMeshes = (int)lMeshes.size(); // open file file = _tfopen(filename, _T("wb")); if (!file) { ExportError("Cannot open file '%s'.", filename); return FALSE; } ExportDebug("%s:", filename); // sync pattern and version putChars("IDP3", 4, file); put32(15, file); putChars("Darkplaces MD3 Exporter", 64, file); put32(0, file); // flags // MD3 header ExportState("Writing MD3 header"); put32(g_total_frames, file); // how many frames put32(totalTags, file); // tagsnum put32(totalMeshes, file); // meshnum put32(1, file); // maxskinnum put32(108, file); // headersize pos_tagstart = ftell(file); put32(0, file); // tagstart pos_tagend = ftell(file); put32(256, file); // tagend pos_filesize = ftell(file); put32(512, file); // filesize ExportDebug(" %i frames, %i tags, %i meshes", g_total_frames, totalTags, totalMeshes); // frame info // bbox arrays get filled while exported mesh and written back then ExportState("Writing frame info"); pos_framestart = ftell(file); lFrameBBoxMin.resize(g_total_frames); lFrameBBoxMax.resize(g_total_frames); for (i = 0; i < g_total_frames; i++) { // init frame data lFrameBBoxMin[i].Set(0, 0, 0); lFrameBBoxMax[i].Set(0, 0, 0); // put data putFloat(-1.0f, file); // bbox min vector putFloat(-1.0f, file); putFloat(-1.0f, file); putFloat( 1.0f, file); // bbox max vector putFloat(1.0f, file); putFloat(1.0f, file); putFloat(0.0f, file); // local origin (usually 0 0 0) putFloat(0.0f, file); putFloat(0.0f, file); putFloat(1.0f, file); // radius of bounding sphere putChars("", 16, file); } // tags pos_current = ftell(file); fseek(file, pos_tagstart, SEEK_SET); put32(pos_current, file); fseek(file, pos_current, SEEK_SET); // for each frame range cycle all frames and write out each tag long pos_tags = pos_current; if (totalTags) { long current_frame = 0; ExportState("Writing %i tags", totalTags); for (range_i = g_frame_ranges.begin(); range_i != g_frame_ranges.end(); range_i++) { for (i = (*range_i).first; i <= (int)(*range_i).last; i++, current_frame++) { SceneEnumProc current_scene(ei->theScene, i * g_ticks_per_frame, gi); current_time = current_scene.time; // write out tags if (lTags.size()) { for (std::list<ExportNode>::iterator tag_i = lTags.begin(); tag_i != lTags.end(); tag_i++) { INode *node = current_scene[tag_i->i]->node; Matrix3 tm = node->GetObjTMAfterWSM(current_time); ExportState("Writing '%s' frame %i of %i", tag_i->name, i, g_total_frames); // tagname putChars(tag_i->name, 64, file); // origin, rotation matrix Point3 row = tm.GetRow(3); putFloat(row.x, file); putFloat(row.y, file); putFloat(row.z, file); row = tm.GetRow(0); putFloat(row.x, file); putFloat(row.y, file); putFloat(row.z, file); row = tm.GetRow(1); putFloat(row.x, file); putFloat(row.y, file); putFloat(row.z, file); row = tm.GetRow(2); putFloat(row.x, file); putFloat(row.y, file); putFloat(row.z, file); } } // write the center of mass tag_pivot which is avg of all objects's pivots if (g_tag_for_pivot) { ExportState("Writing 'tag_pivot' frame %i of %i", i, g_total_frames); // write the null data as tag_pivot need to be written after actual geometry // (it needs information on frame bound boxes to get proper blendings) putChars("tag_pivot", 64, file); putFloat(0, file); putFloat(0, file); putFloat(0, file); putFloat(1, file); putFloat(0, file); putFloat(0, file); putFloat(0, file); putFloat(1, file); putFloat(0, file); putFloat(0, file); putFloat(0, file); putFloat(1, file); } } } } // write the tag object offsets pos_current = ftell(file); fseek(file, pos_tagend, SEEK_SET); put32(pos_current, file); fseek(file, pos_current, SEEK_SET); // allocate the structs used to calculate tag_pivot std::vector<Point3> tag_pivot_origin; std::vector<double> tag_pivot_volume; if (g_tag_for_pivot) { tag_pivot_origin.resize(g_total_frames); tag_pivot_volume.resize(g_total_frames); } // mesh objects // for each mesh object write uv and frames SceneEnumProc scratch(ei->theScene, start_time, gi); ExportState("Writing %i meshes", (int)lMeshes.size()); for (std::list<ExportNode>::iterator mesh_i = lMeshes.begin(); mesh_i != lMeshes.end(); mesh_i++) { bool needsDel; ExportState("Start mesh #%i", mesh_i); INode *node = checkScene[mesh_i->i]->node; Matrix3 tm = node->GetObjTMAfterWSM(start_time); TriObject *tri = GetTriObjectFromNode(node, start_time, needsDel); if (!tri) continue; // get mesh, compute normals Mesh &mesh = tri->GetMesh(); MeshNormalSpec *meshNormalSpec = mesh.GetSpecifiedNormals(); if (meshNormalSpec) { if (!meshNormalSpec->GetNumFaces()) meshNormalSpec = NULL; else { meshNormalSpec->SetParent(&mesh); meshNormalSpec->CheckNormals(); } } mesh.checkNormals(TRUE); // fix lazy object names ExportState("Attempt to fix mesh name '%s'", mesh_i->name); char meshname[64]; size_t meshnamelen = min(63, strlen(mesh_i->name)); memset(meshname, 0, 64); strncpy(meshname, mesh_i->name, meshnamelen); meshname[meshnamelen] = 0; if (!strncmp("Box", meshname, 3) || !strncmp("Sphere", meshname, 6) || !strncmp("Cylinder", meshname, 8) || !strncmp("Torus", meshname, 5) || !strncmp("Cone", meshname, 4) || !strncmp("GeoSphere", meshname, 9) || !strncmp("Tube", meshname, 4) || !strncmp("Pyramid", meshname, 7) || !strncmp("Plane", meshname, 5) || !strncmp("Teapot", meshname, 6) || !strncmp("Object", meshname, 6)) { name_conflict: lazynamesfixed++; if (lazynamesfixed == 1) strcpy(meshname, "base"); else sprintf(meshname, "base%i", lazynamesfixed); // check if it's not used by another mesh for (std::list<ExportNode>::iterator m_i = lMeshes.begin(); m_i != lMeshes.end(); m_i++) if (!strncmp(m_i->name, meshname, strlen(meshname))) goto name_conflict; // approve name ExportWarning("Lazy object name '%s' (mesh renamed to '%s').", node->GetName(), meshname); } // special mesh check bool shadow_or_collision = false; if (g_mesh_special) if (!strncmp("collision", meshname, 9) || !strncmp("shadow", meshname, 6)) shadow_or_collision = true; // get material const char *shadername = NULL; Texmap *tex = 0; Mtl *mtl = 0; if (!shadow_or_collision) { mtl = node->GetMtl(); if (mtl) { // check for multi-material if (mtl->IsMultiMtl()) { // check if it's truly multi material // we do support multi-material with only one texture (some importers set it) bool multi_material = false; MtlID matId = mesh.faces[0].getMatID(); for (i = 1; i < mesh.getNumFaces(); i++) if (mesh.faces[i].getMatID() != matId) multi_material = true; if (multi_material) if (g_mesh_multimaterials == MULTIMATERIALS_NONE) ExportWarning("Object '%s' is multimaterial and using multiple materials on its faces, that case is not yet supported (truncating to first submaterial).", node->GetName()); // switch to submaterial mtl = mtl->GetSubMtl(matId); } // get shader from material if supplied char *materialname = GetChar(mtl->GetName()); if (g_mesh_materialasshader && (strstr(materialname, "/") != NULL || strstr(materialname, "\\") != NULL)) shadername = GetChar(mtl->GetName()); else { // get texture tex = mtl->GetSubTexmap(ID_DI); if (tex) { if (tex->ClassID() == Class_ID(BMTEX_CLASS_ID, 0x00)) { shadername = GetChar(((BitmapTex *)tex)->GetMapName()); if (shadername == NULL || !shadername[0]) ExportWarning("Object '%s' material '%s' has no bitmap.", tex->GetName(), node->GetName()); } else { tex = NULL; ExportWarning("Object '%s' has material with wrong texture type (only Bitmap are supported).", node->GetName()); } } else ExportWarning("Object '%s' has material but no texture.", node->GetName()); } } else ExportWarning("Object '%s' has no material.", node->GetName()); } long pos_meshstart = ftell(file); // surface object ExportState("Writing mesh '%s' header", meshname); putChars("IDP3", 4, file); putChars(meshname, 64, file); put32(0, file); // flags put32(g_total_frames, file); // framecount put32(1, file); // skincount long pos_vertexnum = ftell(file); put32(0, file); // vertexcount put32(mesh.getNumFaces(), file); // trianglecount long pos_trianglestart = ftell(file); put32(0, file); // start triangles put32(108, file); // header size long pos_texvecstart = ftell(file); put32(0, file); // texvecstart long pos_vertexstart = ftell(file); put32(16, file); // vertexstart long pos_meshsize = ftell(file); put32(32, file); // meshsize // write out a single 'skin' ExportState("Writing mesh %s texture", meshname); if (shadow_or_collision) putChars(meshname, 64, file); else if (shadername) putMaterial(shadername, mtl, tex, file); else putChars("noshader", 64, file); put32(0, file); // flags // build geometry ExportState("Building vertexes/triangles"); std::vector<ExportVertex>vVertexes; std::vector<ExportTriangle>vTriangles; vVertexes.resize(mesh.getNumVerts()); int vExtraVerts = mesh.getNumVerts(); for (i = 0; i < mesh.getNumVerts(); i++) { vVertexes[i].vert = i; vVertexes[i].normalfilled = false; // todo: check for coincident verts } int vNumExtraVerts = 0; // check normals if (!mesh.normalsBuilt && !shadow_or_collision) ExportWarning("Object '%s' does not have normals contructed.", node->GetName()); // get info for triangles const float normal_epsilon = 0.01f; vTriangles.resize(mesh.getNumFaces()); for (i = 0; i < mesh.getNumFaces(); i++) { DWORD smGroup = mesh.faces[i].getSmGroup(); ExportState("Mesh %s: checking normals for face %i of %i", meshname, i, mesh.getNumFaces()); for (j = 0; j < 3; j++) { int vert = mesh.faces[i].getVert(j); vTriangles[i].e[j] = vert; // find a right normal for this vertex and save its 'address' int vni; Point3 vn; if (!mesh.normalsBuilt || shadow_or_collision) { vn.Set(0, 0, 0); vni = 0; } else { int numNormals; RVertex *rv = mesh.getRVertPtr(vert); if (meshNormalSpec) { ExportState("face %i vert %i have normal specified", i, j); // mesh have explicit normals (i.e. Edit Normals modifier) vn = meshNormalSpec->GetNormal(i, j); vni = meshNormalSpec->GetNormalIndex(i, j); } else if (rv && rv->rFlags & SPECIFIED_NORMAL) { ExportState("face %i vert %i have SPECIFIED_NORMAL flag", i, j); // SPECIFIED_NORMAL flag vn = rv->rn.getNormal(); vni = 0; } else if (rv && (numNormals = rv->rFlags & NORCT_MASK) && smGroup) { // If there is only one vertex is found in the rn member. if (numNormals == 1) { ExportState("face %i vert %i have solid smooth group", i, j); vn = rv->rn.getNormal(); vni = 0; } else { ExportState("face %i vert %i have mixed smoothing groups", i, j); // If two or more vertices are there you need to step through them // and find the vertex with the same smoothing group as the current face. // You will find multiple normals in the ern member. for (int k = 0; k < numNormals; k++) { if (rv->ern[k].getSmGroup() & smGroup) { vn = rv->ern[k].getNormal(); vni = 1 + k; } } } } else { ExportState("face %i vert %i flat shaded", i, j); // Get the normal from the Face if no smoothing groups are there vn = mesh.getFaceNormal(i); vni = 0 - (i + 1); } } // subdivide to get all normals right if (!vVertexes[vert].normalfilled) { vVertexes[vert].normal = vn; vVertexes[vert].normalindex = vni; vVertexes[vert].normalfilled = true; } else if ((vVertexes[vert].normal - vn).Length() >= normal_epsilon) { // current vertex not matching normal - it was already filled by different smoothing group // find a vert in extra verts in case it was already created bool vert_found = false; for (int ev = vExtraVerts; ev < (int)vVertexes.size(); ev++) { if (vVertexes[ev].vert == vert && (vVertexes[ev].normal - vn).Length() < normal_epsilon) { vert_found = true; vTriangles[i].e[j] = ev; break; } } // we havent found a vertex, create new if (!vert_found) { ExportVertex NewVert; NewVert.vert = vVertexes[vert].vert; NewVert.normal = vn; NewVert.normalindex = vni; NewVert.normalfilled = true; vTriangles[i].e[j] = (int)vVertexes.size(); vVertexes.push_back(NewVert); vNumExtraVerts++; } } } } int vNumExtraVertsForSmoothGroups = vNumExtraVerts; // generate UV map // VorteX: use direct maps reading since getNumTVerts()/getTVert is deprecated // max sets two default mesh maps: 0 - vertex color, 1 : UVW, 2 & up are custom ones ExportState("Building UV map"); std::vector<ExportUV>vUVMap; vUVMap.resize(vVertexes.size()); int meshMap = 1; if (!mesh.mapSupport(meshMap) || !mesh.getNumMapVerts(meshMap) || shadow_or_collision) { for (i = 0; i < mesh.getNumVerts(); i++) { vUVMap[i].u = 0.5; vUVMap[i].v = 0.5; } if (!shadow_or_collision) ExportWarning("No UV mapping was found on object '%s'.", node->GetName()); } else { UVVert *meshUV = mesh.mapVerts(meshMap); for (i = 0; i < (int)vTriangles.size(); i++) { ExportState("Mesh %s: converting tvert for face %i of %i", meshname, i, (int)vTriangles.size()); // for 3 face vertexes for (j = 0; j < 3; j++) { int vert = vTriangles[i].e[j]; int tv = mesh.tvFace[i].t[j]; UVVert &UV = meshUV[tv]; if (!vUVMap[vert].filled) { // fill uvMap vertex vUVMap[vert].u = UV.x; vUVMap[vert].v = UV.y; vUVMap[vert].filled = true; vUVMap[vert].tvert = tv; } else if (tv != vUVMap[vert].tvert) { // uvMap slot for this vertex has been filled // we should arrange triangle to other vertex, which not filled and having same shading and uv // check if any of the extra vertices can fit bool vert_found = false; for (int ev = vExtraVerts; ev < (int)vVertexes.size(); ev++) { if (vVertexes[ev].vert == vert && vUVMap[vert].u == UV.x &&vUVMap[vert].v == UV.y && (vVertexes[ev].normal - vVertexes[vert].normal).Length() < normal_epsilon) { vert_found = true; vTriangles[i].e[j] = vVertexes[ev].vert; break; } } if (!vert_found) { // create new vert ExportVertex NewVert; NewVert.vert = vVertexes[vert].vert; NewVert.normal = vVertexes[vert].normal; NewVert.normalindex = vVertexes[vert].normalindex; NewVert.normalfilled = vVertexes[vert].normalfilled; vTriangles[i].e[j] = (int)vVertexes.size(); vVertexes.push_back(NewVert); vNumExtraVerts++; // create new TVert ExportUV newUV; newUV.filled = true; newUV.u = UV.x; newUV.v = UV.y; newUV.tvert = tv; vUVMap.push_back(newUV); } } } } } int vNumExtraVertsForUV = (vNumExtraVerts - vNumExtraVertsForSmoothGroups); // print some debug stats ExportDebug(" mesh %s: %i vertexes +%i %s +%i UV, %i triangles", meshname, ((int)vVertexes.size() - vNumExtraVerts), vNumExtraVertsForSmoothGroups, meshNormalSpec ? "EditNormals" : "SmoothGroups", vNumExtraVertsForUV, (int)vTriangles.size()); // fill in triangle start pos_current = ftell(file); fseek(file, pos_trianglestart, SEEK_SET); put32(pos_current - pos_meshstart, file); fseek(file, pos_current, SEEK_SET); // detect if object have negative scale (mirrored) // in this canse we should rearrange triangles counterclockwise // so stuff will not be inverted ExportState("Mesh %s: writing %i triangles", meshname, (int)vTriangles.size()); if (DotProd(CrossProd(tm.GetRow(0), tm.GetRow(1)), tm.GetRow(2)) < 0.0) { ExportWarning("Object '%s' is mirrored (having negative scale on it's transformation)", node->GetName()); for (i = 0; i < (int)vTriangles.size(); i++) { put32(vTriangles[i].b, file); // vertex index put32(vTriangles[i].c, file); // for 3 vertices put32(vTriangles[i].a, file); // of triangle } } else { for (i = 0; i < (int)vTriangles.size(); i++) { put32(vTriangles[i].a, file); // vertex index put32(vTriangles[i].c, file); // for 3 vertices put32(vTriangles[i].b, file); // of triangle } } // fill in texvecstart // write out UV mapping coords. ExportState("Mesh %s: writing %i UV vertexes", meshname, (int)vUVMap.size()); pos_current = ftell(file); fseek(file, pos_texvecstart, SEEK_SET); put32(pos_current - pos_meshstart, file); fseek(file, pos_current, SEEK_SET); for (i = 0; i < (int)vUVMap.size(); i++) { putFloat(vUVMap[i].u, file); // texture coord u,v putFloat(1.0f - vUVMap[i].v, file); // for vertex } vUVMap.clear(); // fill in vertexstart pos_current = ftell(file); fseek(file, pos_vertexstart, SEEK_SET); put32(pos_current - pos_meshstart, file); fseek(file, pos_current, SEEK_SET); // fill in vertexnum pos_current = ftell(file); fseek(file, pos_vertexnum, SEEK_SET); put32((int)vVertexes.size(), file); fseek(file, pos_current, SEEK_SET); // write out for each frame the position of each vertex long current_frame = 0; ExportState("Mesh %s: writing %i frames", meshname, g_total_frames); for (range_i = g_frame_ranges.begin(); range_i != g_frame_ranges.end(); range_i++) { for (i = (*range_i).first; i <= (int)(*range_i).last; i++, current_frame++) { bool _needsDel; // get triobject for current frame SceneEnumProc current_scene(ei->theScene, i * g_ticks_per_frame, gi); current_time = current_scene.time; INode *_node = current_scene[mesh_i->i]->node; TriObject *_tri = GetTriObjectFromNode(_node, current_time, _needsDel); if (!_tri) continue; // get mesh, compute normals Mesh &_mesh = _tri->GetMesh(); MeshNormalSpec *_meshNormalSpec = _mesh.GetSpecifiedNormals(); if (_meshNormalSpec) { if (!_meshNormalSpec->GetNumFaces()) _meshNormalSpec = NULL; else { _meshNormalSpec->SetParent(&_mesh); _meshNormalSpec->CheckNormals(); } } _mesh.checkNormals(TRUE); // get transformations for current frame Matrix3 _tm = _node->GetObjTMAfterWSM(current_time); ExportState("Mesh %s: writing frame %i of %i", meshname, current_frame, g_total_frames); Point3 BoxMin(0, 0, 0); Point3 BoxMax(0, 0, 0); for (j = 0; j < (int)vVertexes.size(); j++) // number of vertices { ExportState("Mesh %s: transform vertex %i of %i", meshname, j, (int)vVertexes.size()); int vert = vVertexes[j].vert; Point3 &v = _tm.PointTransform(_mesh.getVert(vert)); // populate bbox data if (!shadow_or_collision) { BoxMin.x = min(BoxMin.x, v.x); BoxMin.y = min(BoxMin.y, v.y); BoxMin.z = min(BoxMin.z, v.z); BoxMax.x = max(BoxMax.x, v.x); BoxMax.y = max(BoxMax.y, v.y); BoxMax.z = max(BoxMax.z, v.z); } // write vertex double f; f = v.x * 64.0f; if (f < -32768.0) f = -32768.0; if (f > 32767.0) f = 32767.0; put16((short)f, file); f = v.y * 64.0f; if (f < -32768.0) f = -32768.0; if (f > 32767.0) f = 32767.0; put16((short)f, file); f = v.z * 64.0f; if (f < -32768.0) f = -32768.0; if (f > 32767.0) f = 32767.0; put16((short)f, file); // get normal ExportState("Mesh %s: transform vertex normal %i of %i", meshname, j, (int)vVertexes.size()); Point3 n; if (_meshNormalSpec) // mesh have explicit normals (i.e. Edit Normals modifier) n = _meshNormalSpec->Normal(vVertexes[j].normalindex); else if (!vVertexes[j].normalfilled || !_mesh.normalsBuilt) n = _mesh.getNormal(vert); else { RVertex *rv = _mesh.getRVertPtr(vert); if (vVertexes[j].normalindex < 0) n = _mesh.getFaceNormal((0 - vVertexes[j].normalindex) - 1); else if (vVertexes[j].normalindex == 0) n = rv->rn.getNormal(); else n = rv->ern[vVertexes[j].normalindex - 1].getNormal(); } // transform normal Point3 &nt = _tm.VectorTransform(n).Normalize(); // encode a normal vector into a 16-bit latitude-longitude value double lng = acos(nt.z) * 255 / (2 * pi); double lat = atan2(nt.y, nt.x) * 255 / (2 * pi); put16((((int)lat & 0xFF) << 8) | ((int)lng & 0xFF), file); } // blend the pivot positions for tag_pivot using mesh's volumes for blending power if (g_tag_for_pivot && !shadow_or_collision) { ExportState("Mesh %s: writing tag_pivot", meshname); Point3 Size = BoxMax - BoxMin; double BoxVolume = pow(Size.x * Size.y * Size.z, 0.333f); // blend matrices float blend = (float)(BoxVolume / (BoxVolume + tag_pivot_volume[current_frame])); float iblend = 1 - blend; tag_pivot_volume[current_frame] = tag_pivot_volume[current_frame] + BoxVolume; Point3 row = _tm.GetRow(3) - _node->GetObjOffsetPos(); tag_pivot_origin[current_frame].x = tag_pivot_origin[current_frame].x * iblend + row.x * blend; tag_pivot_origin[current_frame].y = tag_pivot_origin[current_frame].y * iblend + row.y * blend; tag_pivot_origin[current_frame].z = tag_pivot_origin[current_frame].z * iblend + row.z * blend; } // populate bbox data for frames lFrameBBoxMin[current_frame].x = min(lFrameBBoxMin[current_frame].x, BoxMin.x); lFrameBBoxMin[current_frame].y = min(lFrameBBoxMin[current_frame].y, BoxMin.y); lFrameBBoxMin[current_frame].z = min(lFrameBBoxMin[current_frame].z, BoxMin.z); lFrameBBoxMax[current_frame].x = max(lFrameBBoxMax[current_frame].x, BoxMax.x); lFrameBBoxMax[current_frame].y = max(lFrameBBoxMax[current_frame].y, BoxMax.y); lFrameBBoxMax[current_frame].z = max(lFrameBBoxMax[current_frame].z, BoxMax.z); // delete the working object, if necessary. if (_needsDel) delete _tri; } } // delete if necessary if (needsDel) delete tri; // fill in meshsize pos_current = ftell(file); fseek(file, pos_meshsize, SEEK_SET); put32(pos_current - pos_meshstart, file); fseek(file, pos_current, SEEK_SET); // reset back to first frame SceneEnumProc scratch(ei->theScene, start_time, gi); totalTris += (long)vTriangles.size(); totalVerts += (long)vVertexes.size(); vTriangles.clear(); vVertexes.clear(); } // write tag_pivot ExportState("Writing tag_pivot positions"); if (g_tag_for_pivot) { pos_current = ftell(file); long current_frame = 0; for (range_i = g_frame_ranges.begin(); range_i != g_frame_ranges.end(); range_i++) { for (i = (*range_i).first; i <= (int)(*range_i).last; i++, current_frame++) { fseek(file, pos_tags + totalTags*112*current_frame + (int)lTags.size()*112 + 64, SEEK_SET); // origin putFloat(tag_pivot_origin[current_frame].x, file); putFloat(tag_pivot_origin[current_frame].y, file); putFloat(tag_pivot_origin[current_frame].z, file); } } fseek(file, pos_current, SEEK_SET); } tag_pivot_volume.clear(); tag_pivot_origin.clear(); // write frame data ExportState("Writing culling info"); long current_frame = 0; pos_current = ftell(file); for (range_i = g_frame_ranges.begin(); range_i != g_frame_ranges.end(); range_i++) { for (i = (*range_i).first; i <= (int)(*range_i).last; i++, current_frame++) { fseek(file, pos_framestart + current_frame*56, SEEK_SET); putFloat(lFrameBBoxMin[current_frame].x, file); // bbox min vector putFloat(lFrameBBoxMin[current_frame].y, file); putFloat(lFrameBBoxMin[current_frame].z, file); putFloat(lFrameBBoxMax[current_frame].x, file); // bbox max vector putFloat(lFrameBBoxMax[current_frame].y, file); putFloat(lFrameBBoxMax[current_frame].z, file); putFloat(0, file); // local origin (usually 0 0 0) putFloat(0, file); putFloat(0, file); putFloat(max(lFrameBBoxMin[current_frame].Length(), lFrameBBoxMax[current_frame].Length()) , file); // radius of bounding sphere } } fseek(file, pos_current, SEEK_SET); lFrameBBoxMin.clear(); lFrameBBoxMax.clear(); // fill in filesize pos_current = ftell(file); fseek(file, pos_filesize, SEEK_SET); put32(pos_current, file); fseek(file, pos_current, SEEK_SET); fclose(file); ExportDebug(" total: %i vertexes, %i triangles", totalVerts, totalTris); return TRUE; }
// Determine is the node has negative scaling. // This is used for mirrored objects for example. They have a negative scale factor // so when calculating the normal we should take the vertices counter clockwise. // If we don't compensate for this the objects will be 'inverted'. BOOL Exporter::TMNegParity(Matrix3 &m) { return (DotProd(CrossProd(m.GetRow(0),m.GetRow(1)),m.GetRow(2))<0.0)?1:0; }
bool PFOperatorSimpleSpeed::Proceed(IObject* pCont, PreciseTimeValue timeStart, PreciseTimeValue& timeEnd, Object* pSystem, INode* pNode, INode* actionNode, IPFIntegrator* integrator) { // acquire all necessary channels, create additional if needed IParticleChannelNewR* chNew = GetParticleChannelNewRInterface(pCont); if(chNew == NULL) return false; IParticleChannelPTVR* chTime = GetParticleChannelTimeRInterface(pCont); if(chTime == NULL) return false; IParticleChannelAmountR* chAmount = GetParticleChannelAmountRInterface(pCont); if(chAmount == NULL) return false; // the position channel may not be present. For some option configurations it is okay IParticleChannelPoint3R* chPos = GetParticleChannelPositionRInterface(pCont); int iDir = _pblock()->GetInt(kSimpleSpeed_direction, timeStart); if ((chPos == NULL) && ((iDir == kSS_Icon_Center_Out) || (iDir == kSS_Icon_Arrow_Out))) return false; IChannelContainer* chCont; chCont = GetChannelContainerInterface(pCont); if (chCont == NULL) return false; // the channel of interest bool initSpeed = false; IParticleChannelPoint3W* chSpeed = (IParticleChannelPoint3W*)chCont->EnsureInterface(PARTICLECHANNELSPEEDW_INTERFACE, ParticleChannelPoint3_Class_ID, true, PARTICLECHANNELSPEEDR_INTERFACE, PARTICLECHANNELSPEEDW_INTERFACE, true, actionNode, (Object*)NULL, &initSpeed); IParticleChannelPoint3R* chSpeedR = GetParticleChannelSpeedRInterface(pCont); if ((chSpeed == NULL) || (chSpeedR == NULL)) return false; // there are no new particles if (chNew->IsAllOld()) return true; float fUPFScale = 1.0f/TIME_TICKSPERSEC; // conversion units per seconds to units per tick Point3 pt3SpeedVec; RandGenerator* prg = randLinker().GetRandGenerator(pCont); int iQuant = chAmount->Count(); bool wasIgnoringEmitterTMChange = IsIgnoringEmitterTMChange(); if (!wasIgnoringEmitterTMChange) SetIgnoreEmitterTMChange(); for(int i = 0; i < iQuant; i++) { if(chNew->IsNew(i)) { // apply only to new particles TimeValue tv = chTime->GetValue(i).TimeValue(); Matrix3 nodeTM = pNode->GetObjectTM(tv); float fSpeedParam = fUPFScale * GetPFFloat(pblock(), kSimpleSpeed_speed, tv); // change speed in user selected direction switch(iDir) { case kSS_Along_Icon_Arrow: { // icon arrow appears to be in the negative z direction pt3SpeedVec = -Normalize(nodeTM.GetRow(2)); } break; case kSS_Icon_Center_Out: { Point3 pt3IconCenter = nodeTM.GetTrans(); Point3 pt3PartPos = chPos->GetValue(i); pt3SpeedVec = Normalize(pt3PartPos - pt3IconCenter); } break; case kSS_Icon_Arrow_Out: { Point3 pt3PartPos = chPos->GetValue(i); Point3 pt3ArrowVec = nodeTM.GetRow(2); Point3 pt3Tmp = CrossProd(pt3PartPos - nodeTM.GetTrans(), pt3ArrowVec); pt3SpeedVec = Normalize(CrossProd(pt3ArrowVec, pt3Tmp)); } break; case kSS_Rand_3D: { pt3SpeedVec = RandSphereSurface(prg); } break; case kSS_Rand_Horiz: { float fAng = TWOPI * prg->Rand01(); // establish x, y coordinates of random angle, z component zero float x = cos(fAng); float y = sin(fAng); float z = 0.0f; pt3SpeedVec = Point3(x, y, z); } break; case kSS_Inherit_Prev: { if (initSpeed) pt3SpeedVec = Point3::Origin; else pt3SpeedVec = Normalize(chSpeedR->GetValue(i)); } break; } // account for reverse check box int iRev = _pblock()->GetInt(kSimpleSpeed_reverse, 0); float fDirMult = iRev > 0 ? -1.f : 1.f; // calculate variation float fVar = fUPFScale * GetPFFloat(pblock(), kSimpleSpeed_variation, tv); if(fVar > 0.f) fSpeedParam = fSpeedParam + fVar * prg->Rand11(); pt3SpeedVec = fDirMult * fSpeedParam * pt3SpeedVec; // calculate divergence float fDiv = GetPFFloat(pblock(), kSimpleSpeed_divergence, tv); pt3SpeedVec = DivergeVectorRandom(pt3SpeedVec, prg, fDiv); chSpeed->SetValue(i, pt3SpeedVec); } } if (!wasIgnoringEmitterTMChange) ClearIgnoreEmitterTMChange(); return true; }
bool Exporter::TMNegParity(const Matrix3 &m) { return (DotProd(CrossProd(m.GetRow(0),m.GetRow(1)),m.GetRow(2))<0.0)?true:false; }