3dmax export plug-in-tiamo

Source: Internet
Author: User
3dmax export plug-in-tiamo

From: http://www.gpgame.net/docs/program/3dmaxexporter.htm

The first post of the new year will introduce the export plug-in of 3dmax, which is used to export the 3d model to a dll in the format required by the engine. It is loaded and called by 3dmax. specifically, how to write a plug-in is not much said. I have a detailed introduction in the 3dmax sdk, and many source codes can be found on google, here we only talk about how to organize the data of 3dmax and how to obtain the data for converting 3dmax. an important concept in 3dmax is INode. The scenario model of 3dmax is composed of INode, which constitute a system tree, all real models are attached to an INode. The 3dmax sdk provides several Matrix methods for obtaining INode pointers and INode, this can be found in the max sdk, and it is not the main things that Xiao T talked about this time. after obtaining the corresponding Matrix, use the EvalWorldState function of INode to obtain the geom object attached to the INode, The vertex information, face information, and material information can be obtained, which are relatively easy. These methods will be mentioned in any example of an export plug-in, with Little T. after talking for a long time, what does Xiao T really want to say? Hey hey. one is the weight data acquisition of the skin mesh, the other is the control data acquisition of the keyframe, and several different control keyframe interpolation methods of 3dmax. let's talk about the weight table data of the skin mesh. the skin tool used in the export plug-in of the X file is part of charactor studio (cs). The small T does not find a suitable cs installation. Therefore, the small T plug-in is not prepared to support cs, the only supported tool recommended by small T is the skin tool provided by 3dmax5. the following describes how to obtain data from the skin tool. skin is called modifier in 3dmax. 3dmax maintains a modifier stack for each object. (For details about this, see the 3dmax sdk or google ), now, the first thing to do is to get the interface pointer ISkin of the modifier skin. ---> use the GetModifier function one by one Check whether the class id of each modifier is SKIN_CLASSID. Then, call GetInterface to obtain the ISkin pointer. Call GetContextInterface to obtain the ISkinContextData pointer. The weight table is maintained in this pointer. first, call the GetNumAssignedBones of the ISkinContextData pointer, pass the vertex id (obtain this id from the face data), and obtain the number of bones that affect the vertex, then, reduce the number from 0 to bone, call GetAssignedBone one by one, pass the vertex id and bone index to get the bone id, and then use the GetBone of ISkin to get the INode pointer of bone, call GetBoneWeight of ISkinContextData to upload vertex id and bone index. Obtain weight data. A little messy. paste the code. // get weights, CFace is a class that hold face info, i0, i1, i2 is face's vertexes id void CExporter: GetWeights (CFace * pFace, INode * pNode, mesh * pMesh, int i0, int i1, int i2) {// find skin modifier Object * pObject = pNode-> GetObjectRef (); if (pObject-> SuperClassID () = GEN_DERIVOB_CLASS_ID) {IDerivedObject * pDerivedObject = (IDerivedObject *) pObject; int nMod = pDerivedObject-> NumModifiers (); for (int I = 0; I <nMod; I ++) {Modifier * pModifier = pDerivedObject-> GetModifier (I); if (pModifier-> ClassID () = SKIN_CLASSID) {ISkin * pSkin = (ISkin *) pModifier-> GetInterface (I _SKIN); // get ISkin interface if (pSkin) {ISkinContextData * pSkinContext = pSkin-> GetContextInterface (pNode); // get context interface int nBones, j; // bones nBones = pSkinContext-> GetNumAssignedBones (i0 ); // Param is vertex id, use pmaxMesh-> faces [I]. v [0] for (j = 0; j <nBones; j ++) {int nBoneIndex = pSkinContext-> GetAssignedBone (i0, j ); // FindNode is function that takes a INode pointer reture a index id. pFace-> m_vertex [0]. m_ltWeights.push_back (std: make_pair (FindNode (pSkin-> GetBone (nBoneIndex), pSkinContext-> GetBoneWeight (i0, j )));} nBones = pSkinContext-> GetNumAssignedBones (i1 );//........ same For i1 and i2 }}} the weight data of the skin mesh is obtained. next we will get the control data of 3dmax. this part is the most obscure part of the entire 3dmax. Its format is only available in the 3dmax debug sdk, and this debug sdk requires money, small T does not have the ability to pay much of the US dollars .. hey hey. the following information comes from the source code of the 3d engine of each open source collected by Xiao T from the Internet. A small part of the information is the result of his own research by Xiao T. first, list the data sources. first, the mdl export plug-in 'dex. invalid. there are many controls in 3dmax, and the small T is only intended to support the main three types: linear, bezeiser and tcb control. below One by one. linear is the simplest. It uses linear interpolation algorithms. for rotating data, use the quat slerp algorithm. void CExporter: GetLinearPosition (CNode * pOurNode, INode * pMaxNode, Control * pControl, IKeyControl * pKeyControl) {ILinPoint3Key maxKey; CAnimationPositionLinearKey ourKey; for (int I = 0; I <pKeyControl-> GetNumKeys (); I ++) {// abs position, local system pKeyControl-> GetKey (I, & maxKey); ourKey. m_fPosition [0] = maxKey. val. x; ourKey. m_fPosit Ion [1] = maxKey. val. z; ourKey. m_fPosition [2] = maxKey. val. y; ourKey. m_nTime = maxKey. time * 1000/TIME_TICKSPERSEC; AddAnimationKey (pOurNode, LinearPositionKey, & ourKey) ;}// when do interpolation, key1 is prev key, key2 is next key, t is time, then the position at t is // pos = key1.pos + (key2.pos-key1.pos) * (t-key1.time)/(key2.time-key1.time)} // linear rotation void CExporter: GetLinearRotat Ion (CNode * pOurNode, INode * pMaxNode, Control * pControl, IKeyControl * pKeyControl) {Matrix3 maxMatrix; ILinRotKey maxKey; CAnimationRotationLinearKey ourKey; for (int I = 0; I <pKeyControl-> GetNumKeys (); I ++) {pKeyControl-> GetKey (I, & maxKey); // this key's quat is an abs value, not a rel value... error in max sdk // convert to matrix maxKey. val. makeMatrix (maxMatrix); ConvertMaxMat2OurMat (maxMatrix, ou RKey. m_matNode); ourKey. m_nTime = maxKey. time * 1000/second; AddAnimationKey (pOurNode, LinearRotationKey, & ourKey);} // when do interpolation // rotation is Quat: Slerp (key1.qRot, key2.qRot, (t-key1.time) /(key2.time-key1.time)} next, tcb control is a little more complex than linear. tcb control uses hermite (hermit) interpolation, hermite interpolation refers to the construction of a polynomial based on the given values of finite points and the first derivative of these points. The values and first derivative of the given points are the same as the known values. as mentioned in the numerical analysis, give a link. obviously, the rotation angle of an object is A time function, given a time, has a unique position and a unique rotation, but now we cannot record the position and rotation information of any time, we only know the position and rotation information of some specific time points (these points are called keyframe), and the derivative information of these points, now we need to use the known information to calculate the value of any time point. this is called interpolation. (Well, this explanation is incomplete, but I personally think it is easy to understand ). using values and derivatives, we can use the hermite interpolation method to calculate the value at any time point. However, in fact, it is not easy to obtain the derivative information of a single point, therefore, tcb came into being. Instead of recording the derivative of a single point, tcb records three additional data records, the derivative information of a single vertex can be calculated based on the known information (For details, refer to the article in the above link). The special point is the first and last vertex, the first vertex only needs to calculate the TD value, float tm = 0.5f * (1.0f-firstKey-> Tension); firstKe Y-> TD = tm * (secondKey-> Value-firstKey-> Value) * 3.0f-secondKey-> TS ); the last vertex calculates the TS Value float tm = 0.5f * (1.0f-lastKey-> Tension); lastKey-> TS = tm * (lastKey-> Value-previuslastkey-> Value) * 3.0f-previuslastkey-> TD); then, the required data in the method provided in the above link is almost the same. The only exception is the s. on the surface, s is (t-key1.time)/(key2.time-key1.time). Actually, no. There is also an easeIn and easeOut data in 3dmax, the obtained result must undergo a series of calculations before it can be used as the interpolation parameter s. the method is listed as follows: cursor: first calc Float e0 = Keys [I]. m_fEaseOut; float e1 = Keys [I + 1]. m_fEaseIn; float s = e0 + e1; if (s> 1.0) {e0/= s; e1/= s;} Keys [I]. m_fEase0 = e0; Keys [I]. m_fEase1 = e1; Keys [I]. m_fEaseK = 1.0f/(2.0f-e0-e1); if (e0! = 0.0f) {Keys [I]. m_fEaseKOverEase0 = Keys [I]. m_fEaseK/e0;} if (e1! = 0.0f) {Keys [I]. m_fEaseKOverEase1 = Keys [I]. m_fEaseK/e1;} // for the last key m_fEaseK = 0.5f when do exist if (key-> m_fEaseK = 0.5f) {// keep the same s = t ;} else if (t <key-> m_fEase0) {s = key-> m_fEaseKOverEase0 * t;} else if (t <1.0f-key-> m_fEase1) {s = key-> m_fEaseK * (2.0f * t-key-> m_fEase0);} else {t = 1.0f-t; s = 1.0f-key-> m_fEaseKOverEase1 * t;} if it is position control, use the hermite Interpolation Algorithm in the link directly. If it is rotating, it is a little different, TD and TS must be recalculated. change the name to inTangent or outTangent. first calc keys [0]. inTan = Quat (0 0 0 1); keys [0]. outTan = QCompA (keys [0]. qRot, keys [0]. qRot, keys [1]. qRot); keys [keys. size ()-1]. inTan = QCompA (keys [keys. size ()-2]. qRot, keys [keys. size ()-1]. qRot, keys [keys. size ()-1]. qRot); keys [keys. size ()-1]. outTan = Quat (0 0 0 1); for (size_t I = 1; I <keys. size ()-1; I ++) {keys [I]. inTan = keys [I]. outTan = QCompA (keys [I-1]. qRot, keys [I]. qRot, keys [I + 1]. qRot);} calc result: div = comment; Quat q = Squad (keys [prev]. qRot, keys [prev]. inTan, keys [next]. outTan, keys [next]. qRot, div); note: Quat QCompA (const Quat & qprev, const Quat & q, const Quat & qnext); return a, the term used in Boehm-type interpolation. a = q * exp (-(1/4) * (ln (qinv (q) * qnext) + ln (qinv (q) * qprev) data acquisition code. // tcb position void CExporter: GetHermitePosition (CNode * pOurNode, INode * pMaxNode, Control * pControl, IKeyControl * pKeyControl) {ITCBPoint3Key maxKey; incluourkey; for (int I = 0; I <pKeyControl-> GetNumKeys (); I ++) {pKeyControl-> GetKey (I, & maxKey); ourKey. m_fPosition [0] = maxKey. val. x; ourKey. m_fPosition [1] = maxKey. val. z; ourKey. m_fPosition [2] = maxKey. val. y; ourKey. m_fTens = maxKey. tens; ourKey. m_fCont = maxKey. cont; ourKey. m_fBias = maxKey. bias; ourKey. m_fEaseIn = maxKey. easeIn; ourKey. m_fEaseOut = maxKey. easeOut; ourKey. m_nTime = maxKey. time * 1000/second; AddAnimationKey (pOurNode, TCBPositionKey, & ourKey) ;}// tcb rotation void CExporter: GetHermiteRotation (CNode * pOurNode, INode * pMaxNode, Control * pControl, IKeyControl * pKeyControl) {Quat prev, current; prev. identity (); Matrix3 maxMatrix; ITCBRotKey maxKey; CAnimationRotationTCBKey ourKey; for (int I = 0; I <pKeyControl-> GetNumKeys (); I ++) {pKeyControl-> GetKey (I, & maxKey); // this is a rel value as max sdk said // angle axis to quat current = prev * Quat (maxKey. val); prev = current; // convert to matrix current. makeMatrix (maxMatrix); ConvertMaxMat2OurMat (maxMatrix, ourKey. m_matNode); ourKey. m_fTens = maxKey. tens; ourKey. m_fCont = maxKey. cont; ourKey. m_fBias = maxKey. bias; ourKey. m_fEaseIn = maxKey. easeIn; ourKey. m_fEaseOut = maxKey. easeOut; ourKey. m_nTime = maxKey. time * 1000/TIME_TICKSPERSEC; AddAnimationKey, but his data is the least. The only interpolation algorithm available is 3dmax3, which is incorrect in 3dmax4 and 5, only this part of the algorithm is try once. the difference between the interpolation and the hermite interpolation is similar. It is a mathematical tool used to calculate arbitrary points based on a few known points. different time points are computed using control points rather than derivative. This article will be able to find a lot of results by searching for them on google. the only thing to note in interpolation calculation is the interpolation parameter s, which is the same as tcb above, not necessarily (time-key1.time)/(key2.time-key1.time ). he also needs to be computed. the same time as the location, and so on, is also a function of the interpolation parameter s, that is to say, given a s corresponds to a time, but what we know now is time, we need to find s through time. In fact, the calculation of the value of time is the result of using s for the bezr interpolation. Now, we need to reverse evaluate it, in this article, you can refer to the Solving the nearest-point-on-curve Method in graphics gems 1. the method used by the small T is not that complex. binary search. float CalcDiv (float x1, float x2, float x) {float temp, div = 0.5f, hi = 1.0f, low = 0.0f; do {temp = bezr (0.0f, x1, x2, 1.0f, div); if (fabs (temp-x) <1. e-6) break; if (temp <x) {low = div;} else {hi = div;} div = (hi + low)/2;} while (1 ); return div;} after obtaining the interpolation parameter, It will be OK for the corresponding postion to be used for the bezr interpolation. As for the calculation of the two control points, first calc control points c1 c2 p1 p2 dt = p2.time-p1.time; c1 = dt * p1.outLength * p1.outtan + p1.val; c2 = dt * p2.inLength * p2.intan + p2.val; then calc div divx = CalcDiv (p1.outLength. x, 1-p2.inLength. x, time_percent) divy = CalcDiv (p1.outLength. y, 1-p2.inLength. y, time_percent) divz = CalcDiv (p1.outLength. z, 1-p2.inLength. z, time_percent) final do bezerinterpolation x = bezerher (p1.x, c1.x, c2.x, p2.x, divx) y = bezerher (p1.y, c1.y, c2.y, p2.y, divy) z = besuppliers (p1.z, c1.z, c2.z, p2.z, divz) where besuppliers (p1, c1, c2, p2, div) is p1c1 = linear (p1, c1, div) c2p2 = linear (c2, p2, div) c1c2 = linear (c1, c2, div) p1c1c1c2 = linear (p1c1, c1c2, div) c1c2c2p2 = linear (c1c2, c2p2, div) result = linear (p1c1c1c2, c1c2c2p2, div) and linear (a, B, t) = a + t * (B-a) correspond to the rotation, and the method is different. first calc key's tan keys [0]. tan = QCompA (keys [1]. qRot, keys [0]. qRot, keys [1]. qRot); keys [keys. size ()-1]. tan = QCompA (keys [keys. size ()-2]. qRot, keys [keys. size ()-1]. qRot, keys [keys. size ()-2]. qRot); for (size_t I = 1; I <keys. size ()-1; I ++) {keys [I]. tan = QCompA (keys [I-1]. qRot, keys [I]. qRot, keys [I + 1]. qRot);} then calc result div = (time-keys [prev]. time)/(keys [next]. time-keys [prev]. time); Quat q = Quat: Squad (keys [prev]. qRot, keys [prev]. tan, keys [next]. tan, keys [next]. qRot, div); Code for obtaining data // bezr position void CExporter: GetBezierPosition (CNode * pOurNode, INode * pMaxNode, Control * pControl, IKeyControl * pKeyControl) {IBezPoint3Key maxKey; CAnimationPositionBezierKey ourKey; for (int I = 0; I <pKeyControl-> GetNumKeys (); I ++) {pKeyControl-> GetKey (I, & maxKey); ourKey. m_fPosition [0] = maxKey. val. x; ourKey. m_fPosition [1] = maxKey. val. z; ourKey. m_fPosition [2] = maxKey. val. y; ourKey. m_fInTan [0] = maxKey. intan. x; ourKey. m_fInTan [1] = maxKey. intan. z; ourKey. m_fInTan [2] = maxKey. intan. y; ourKey. m_fOutTan [0] = maxKey. outtan. x; ourKey. m_fOutTan [1] = maxKey. outtan. z; ourKey. m_fOutTan [2] = maxKey. outtan. y; ourKey. m_fOutLength [0] = maxKey. outLength. x; ourKey. m_fOutLength [1] = maxKey. outLength. z; ourKey. m_fOutLength [2] = maxKey. outLength. y; ourKey. m_nTime = maxKey. time * 1000/second; AddAnimationKey (pOurNode, BezierPositionKey, & ourKey) ;}// bezerrotation void CExporter: GetBezierRotation (CNode * pOurNode, INode * pMaxNode, Control * pControl, IKeyControl * pKeyControl) {Matrix3 maxMatrix; IBezQuatKey maxKey; CAnimationRotationBezierKey ourKey; for (int I = 0; I <pKeyControl-> GetNumKeys (); I ++) {pKeyControl-> GetKey (I, & maxKey); // this is also an abs value // convert to matrix maxKey. val. makeMatrix (maxMatrix); ConvertMaxMat2OurMat (maxMatrix, ourKey. m_matNode); ourKey. m_nTime = maxKey. time * 1000/TIME_TICKSPERSEC; AddAnimationKey (pOurNode, BezierRotationKey, & ourKey) ;}} here, the control part that T will talk about is all over. summary 1. linear control for position, get position (vector3) value from 3 dmax, then use linear interpolation to calc the position. 2. linear control for rotation, get rotation (quaternion) value from 3 dmax, then use slerp to calc the rotation 3.tcb control for position, get position (vector3) and t, c, B (float) and easeIn, easeOut (float) form 3 dmax, then calc key's inTan and outTan and parse data one times, when do interpolation, first do Parse then use hermite method. 4.tcb control for rotation, get rotation (quaternion) and t, c, B, easeIn, easeOut from 3 dmax, then calc key's inTan, outTan holding data one times, when do interpolation, first do have then use squad. 5. bezr control for position, get position (vector3) and inTan (vector3) outTan (vector3) inLength (vector3) outLength (vector3) value from 3 dmax, and calc control points one times, when do interpolation, first calc param, then use bezeir method. 6. betiller control for rotation, get rotation (quaternion) value from 3 dmax, then calc tangent one times, when do interpolation, use squad.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.