¢ÂMax Plugin¢Â
Ç÷¯±×ÀÎ(Plugin)ÀÇ ¶æÀ» ã¾Æº¸¸é ÇÁ·Î±×·¥¿¡ ¾ø´ø »õ ±â´ÉÀ»
Ãß°¡Çϱâ À§ÇØ ³¢¿ö ³Ö´Â¡¹ºÎ°¡ÀûÀÎ ÇÁ·Î±×·¥À¸·Î ÀÚüÀûÀ¸·Î´Â ½ÇÇà´É·ÂÀº ¾øÁö¸¸ ƯÁ¤ÇÑ ÇÁ·Î±×·¥ ¼Ó¿¡¼ ÇÔ²² ½ÇÇàµÇ¾î ±â´ÉÀ» ¹ßÈÖÇÑ´Ù°í µÇ¾î ÀÖ½À´Ï´Ù.
Autodesk 3D Max(ÀÌÇÏ
MAX: ¸Æ½º) PluginÀº »ç¿ëÀÚÀÇ ¸ñÀû¿¡ ¸Â°Ô ¸Æ½º ÇÁ·Î±×·¥ÀÇ ±â´ÉÀ» º¸°Çϱâ À§Çؼ
¸¸µç ÇÁ·Î±×·¥ÀÔ´Ï´Ù. À©µµ¿ì ¿î¿µÃ¼Á¦¿¡¼ MAX¿ë Ç÷¯±×ÀÎÀÇ
±¸ÇöÀº DLL (Dynamic Linking Library)ÀÔ´Ï´Ù. µû¶ó¼
¿ø·¡ ÇÁ·Î±×·¥ÀÇ Çü½Ä°ú À©µµ¿ì DLLÀÇ Ç¥ÁØ¿¡ ¸Â°Ô ÇÁ·Î±×·¥À» ¸¸µç´Ù¸é Ç÷¯±×ÀÎÀ» ¸¸µé ¼ö ÀÖ½À´Ï´Ù.
¸Æ½º Ç÷¯±×ÀÎÀº ¾Æ¹«°Å³ª ¸¸µé ¼ö ÀÖ´Â °ÍÀÌ ¾Æ´Ï¶ó ¸Æ½º¿¡¼ Áö¿øµÇ´Â °Í¸¸ ¸¸µé ¼ö ÀÖ½À´Ï´Ù. ¾î¶² Ç÷¯±×ÀÎÀ» ¸¸µé °ÍÀÎÁö´Â Visual Studio¿¡¼ ¸Æ½º
Ç÷¯±×ÀÎ ¸¸µå´Â Wizard·Î È®ÀÎÇÒ ¼ö ÀÖÀ¸¸ç ÀÌ Áß¿¡¼
"File Export"°¡ ¿ì¸®°¡ ¸¸µé°íÀÚ ÇÏ´Â Ç÷¯±×ÀÎ ÀÔ´Ï´Ù.
"File Export" Ç÷¯±×ÀÎÀº °ÔÀÓ¿¡¼ ÇÊ¿äÇÑ
¸Æ½º ÆÄÀÏÀÇ ÀϺθ¦ ²¨³»¿À´Â °ÍÀÔ´Ï´Ù. ¹°·Ð ´Ù ²¨³»¿À¸é ÁÁ°ÚÁö¸¸ ±×·¸°Ô Çϱâ´Â Èûµé°í ¼³·É ´Ù °¡Á®¿Â´Ù
ÇÏ´õ¶óµµ ¸Æ½º ÇÁ·Î±×·¥°ú °ÔÀÓ ÇÁ·Î±×·¥ÀÇ ÀÚ·á ÇØ¼® Â÷À̷Πȸ鿡 º¸ÀÌ´Â ¸ð½ÀÀº ¾à°£ÀÇ Â÷À̰¡ ÀÖÀ» ¼ö ÀÖ½À´Ï´Ù.
ÁÁÀº "File Export" Ç÷¯±×ÀÎÀº ¸Æ½º ȸé°ú °ÔÀÓ È¸éÀÇ Â÷À̸¦
ÁÙÀ̰í ÃÖ´ëÇÑ ÀÏÄ¡½ÃŰ´Â °ÍÀ̶ó ÇÒ ¼ö ÀÖ½À´Ï´Ù.
º¸Åë °æ·ÂÀڵ鵵 ¾µ¸¸ÇÑ "File Export" Ç÷¯±×ÀÎÀ»
¸¸µå´Âµ¥ °ÅÀÇ 4~6°³¿ùÀÇ ½Ã°£ÀÌ ¼Ò¿äµË´Ï´Ù. À̰ÍÀº ¸Æ½º¿Í D3D´Â °°Àº µ¥ÀÌÅÍ¶óµµ Ã³¸®ÇÏ´Â ¹æ½ÄÀÌ ´Ù¸£°í ±¸Ã¼ÀûÀÎ ¸Æ½ºÀÇ ³»¿ëÀ» ¸ð¸£´Â »óÅ¿¡¼ ÀÛ¾÷À» Çϱ⠶§¹®ÀÔ´Ï´Ù. ¶ÇÇÑ ¸Æ½º ÇÁ·Î±×·¥ÀÇ È¸é¿¡¼´Â Á¤»óÀûÀÎ ¸ð½ÀÀ¸·Î ³ªÅ¸³ªÁö¸¸
ExportingÀ» ÇÏ¸é ¹Ìó ó¸®ÇÏÁö ¸øÇÑ µ¥ÀÌÅÍ·Î ÀÎÇØ ¿øÄ¡ ¾Ê´Â ¸ð½ÀÀÌ Á¾Á¾ ³ªÅ¸³³´Ï´Ù. µû¶ó¼
¿Ïº®ÇÑ Ç÷¯±×ÀÎÀ» ¸¸µé±â±îÁö ³Ê¹« ¸¹Àº ½Ã°£ÀÌ ¼Ò¿äµÈ´Ù¸é ȸ»ç·Î¼µµ ºñ¿ëÀÇ ¹®Á¦°¡ ¹ß»ýÇϱ⠶§¹®¿¡ ¹ö±×¸¦ ÇÇÇÏ´Â ¹æ¹ýÀ» ±×·¡ÇÈ ´ã´çÀÚµé°ú ³íÀǸ¦
ÇÏ°í ±×·¡ÇÈ ÀÛ¾÷ÀÇ ¼ø¼¸¦ °áÁ¤ÇÕ´Ï´Ù.
ÀÌ ÀåÀº ¿Ïº®ÇÏÁö ¾ÊÁö¸¸ ±×·¡µµ ¾î´À Á¤µµ ¾µ ¸¸ÇÑ Ç÷¯±×ÀÎÀ» ¸¸µé¾îº¸´Â °ÍÀÌ ¸ñÀûÀÔ´Ï´Ù. ¸ðµç ¸Æ½º µ¥ÀÌÅÍ¿¡ ´ëÇØ¼ µ¥ÀÌÅ͸¦ ExportÇÑ´Ù°í´Â ÇÒ ¼ö ¾ø°í
±×·¯ÇÑ ¹®Á¦µéÀº µ¶ÀÚÀÇ ¸ñÀ¸·Î ³²°Ü ³õ°Ú½À´Ï´Ù. ¶ÇÇÑ 3D ¸Æ½º°¡ 2010 ¹öÀü±îÁö Ãâ½ÃµÇ¾úÁö¸¸ ¿©±â¼´Â 8.0±âÁØÀ¸·Î Ç÷¯±×ÀÎÀ» ¸¸µé°Ú½À´Ï´Ù. ±×°ÍÀº ¸Æ½ºÀÇ °¡°ÝÀÌ 500¸¸¿øÀÌ ³Ñ½À´Ï´Ù. º¸Åë ±³À°±â°üÀ̳ª ±â¾÷ü¿¡¼ ¼ÒÇÁÆ®¿þ¾î°¡ »õ·Î Ãâ½ÃµÇ¸é Çлýµé ¶Ç´Â °³¹ßÀÚµéÀ» À§ÇØ »õ·Î¿î ¼ÒÇÁÆ®¿þ¾î¸¦ °ø±ÞÇÏ´Â
°ÍÀÌ ÀϹÝÀûÀÌÁö¸¸ °³¹ßÀÚ ¿ù±Þ º¸´Ù ÈξÀ ºñ½Ñ ¼ÒÇÁÆ®¿þ¾î¸¦ ¾÷±×·¹À̵å ÇÑ´Ù´Â °ÍÀº ȸ»ç ¿î¿µ»ó ¸ÂÁö ¾Ê±â ¶§¹®¿¡ ´ëºÎºÐ ÀÌÀü ¹öÀüÀ» ±×´ë·Î »ç¿ëÇÏ´Â
°æÇâÀÌ ¸¹½À´Ï´Ù. ÇÁ·Î±×·¡¸ÓÀÇ ÀÔÀÚ¿¡¼ ¹Ù¶óº¸¾Æµµ ¸Æ½º ¹öÀüÀÌ ¿Ã¶ó°¡µµ ÇÊ¿äÇÑ SDK ³»¿ëÀº °ÅÀÇ ±×´ë·ÎÀÎ °ÍÀÌ ´ëºÎºÐÀÔ´Ï´Ù.
8.0À» ¼±ÅÃÇÑ ÁÖµÈ ÀÌÀ¯´Â °¡Àå ¸¹ÀÌ »ç¿ëµÇ´Â ¹öÀüÀ̱⵵ ÇÏÁö¸¸
ÀÌÀü¿¡´Â ¸Æ½º¿¡¼ ¾Ö´Ï¸ÞÀÌ¼Ç ÀÛ¾÷À» ÇÒ ¶§ Physique¸¦ ÁÖ·Î »ç¿ëÇߴµ¥ 8.0 ÀÌÈÄ¿¡´Â ½ºÅ°´×(Skinning)ÀÌ Áö¿øµÇ¾î ÀÌ ¹æ½ÄÀ¸·Î ÀÛ¾÷À»
¸¹ÀÌ ÇÑ´Ù°í ÇÕ´Ï´Ù. ½ºÅ°´×À¸·Î ¾Ö´Ï¸ÞÀ̼ÇÀ» ÀÛ¾÷ÇÏ¸é ±×·¡ÇȰú °ÔÀÓ¿¡¼ ÀÏÄ¡ÇÏÁö ¾Ê´Â ¹ö±× ã±âµµ ¼ö¿ùÇÏ´Ù°í
ÇÕ´Ï´Ù.
5.1 SDK
5.1.1 SDK ¼³Ä¡¿Í VC Project
¸Æ½º´Â ¿ë·®ÀÌ Å©¹Ç·Î Program Files¿¡ ¼³Ä¡Çϱ⠺¸´Ù´Â Çϵ带
ºÐÇÒÇØ¼ C ´ë½Å D³ª E¿¡
¼³Ä¡ÇÏ´Â °ÍÀÌ ÁÁ½À´Ï´Ù. Àú´Â "D:\_3dsMax8"
¿¡ ¼³Ä¡ Çß½À´Ï´Ù.
¸Æ½º SDK´Â ¸Æ½º¿Í µû·Î ¼³Ä¡µË´Ï´Ù. ´ÙÀ½°ú °°ÀÌ install CD°¡ ÀÖÀ¸¸é SDK¸¦ ¼³Ä¡ÇÕ´Ï´Ù. Àú´Â
"D:\_3dsMax8\maxsdk"¿¡ ¼³Ä¡Çß½À´Ï´Ù.

<MAX SDK ¼³Ä¡>
SDK¸¦ ¼³Ä¡ÇÏ°í ³ª¼ ¸Æ½º SDK°¡
¼³Ä¡µÈ Æú´õ ¿¹¸¦ µé¾î "D:\_3dsMax8\maxsdk\howto"¿¡ °¡¸é "3dsmaxPluginWizard" Æú´õ°¡ ÀÖ½À´Ï´Ù. ÀÌ
Æú´õÀÇ "Readme.txt"ÆÄÀÏÀ» Àо¸é ÀÌ À§Àúµå´Â "Visual Studio 7.1"¿ë À§Àúµå ÀÓÀ» ¾Ë¸®°í ÀÖ½À´Ï´Ù.
¶ÇÇÑ Installing 2¹øÀ» º¸¸é "3dsmaxPluginWizard.vsz" ÆÄÀÏÀ» ¿¾î¼ ´ÙÀ½ ºÎºÐÀ» °íÄ¡¶ó°í ÇÕ´Ï´Ù.
Param="ABSOLUTE_PATH = [Absolute Path
Location of 3dsmaxPluginWizard Root Directory]"
À̰ÍÀº Visual Studio¿¡¼ À§Àúµå¸¦ ½ÇÇàÇÒ ¶§ ¸Æ½º SDKÀÇ À§Àúµå¸¦ ½ÇÇàÇÒ ¼ö ÀÖ´Â Àý´ë °æ·Î¸¦ ¼³Á¤Ç϶ó´Â °ÍÀ¸·Î ±×¸²Ã³·³
"dsmaxPluginWizard.vsz" ÆÄÀÏÀÌ ÀÖ´Â °æ·Î¸¦ º¹»çÇØ¼ ´ÙÀ½°ú ÀÌ ¸¸µì´Ï´Ù.
Param="ABSOLUTE_PATH =
[D:\_3dsMax8\maxsdk\howto\3dsmaxPluginWizard]"
¶ÇÇÑ °æ·Î À̸§¿¡ '\'¸¦ Ãß°¡ÇÏÁö ¸»¶ó°í ÇÕ´Ï´Ù. (±×³É Ž»ö±â¿¡ ÀÖ´Â °æ·Î¸¦ ºÙÀÌ¸é ¹®Á¦ ¾ø½À´Ï´Ù.)

< dsmaxPluginWizard.vsz ÆÄÀÏÀÇ °æ·Î º¹»ç>
´ÙÀ½À¸·Î Installing 3¹ø¿¡ º¸¸é
3dsmaxPluginWizard.ico
3dsmaxPluginWizard.vsdir
3dsmaxPluginWizard.vsz
ÆÄÀÏ 3°³¸¦ Visual
Studio°¡ ¼³Ä¡µÈ Æú ´õ ¹Ø¿¡ "Visual Studio Æú´õ\Vc7\vcprojects Vc7\vcprojects" Æú´õ¿¡ º¹»çÇ϶ó°í Çϴµ¥ ´ÙÀ½°ú °°ÀÌ ÇÏ¸é µË´Ï´Ù.

<Visual Studio À§Àúµå ÇÁ·ÎÁ§Æ® ¼³Ä¡>
ÀÌ·¸°Ô Çϸé À§Àúµå ¼³Ä¡´Â ³¡ÀÌ ³³´Ï´Ù. Visual StudioÀÇ
»õ ÇÁ·ÎÁ§Æ®¸¦ ½ÇÇàÇÏ¸é ´ÙÀ½ ±×¸²Ã³·³ ¸Æ½º Ç÷¯±×ÀÎ À§Àúµå ¼±Åà ¾ÆÀÌÄÜÀÌ ÀÖ½À´Ï´Ù.

<¸Æ½º Ç÷¯±×ÀÎ À§Àúµå ½ÇÇà>
È®ÀÎ ¹öưÀ» ´©¸£¸é ¾î¶² Ç÷¯±×ÀÎÀ» ¸¸µé °ÍÀÎÁö ¼±Åà ȸéÀÌ ³ª¿É´Ï´Ù.
"File Export"¸¦ ¼±ÅÃÇÕ´Ï´Ù.

<Ç÷¯±×ÀÎ Á¾·ù ¼±ÅÃ:
"File Exporter">
´ÙÀ½ â¿¡ Plugin Detail âÀÌ ÀÖ½À´Ï´Ù. ±×³É ³Ñ¾î°©´Ï´Ù. ±× ´ÙÀ½ â¿¡´Â ¸Æ½º SDK°¡ ¼³Ä¡µÈ Æú´õ, Ç÷¯±×ÀÎÀÌ ÄÄÆÄÀÏ µÇ¸é º¹»çµÉ °æ·Î, ¸Æ½ºÀÇ ½ÇÇà °æ·Î¸¦ ÁöÁ¤ÇÏ´Â °ÍÀÌ ³ª¿É´Ï´Ù. ¸Æ½º´Â ½ÇÇà ÆÄÀÏÀÌ
ÀÖ´Â ÇÏÀ§ Æú´õ "plugins" ¿¡ ÀÖ´Â Ç÷¯±×ÀεéÀ» ½ÇÇàÇÒ ¶§ ÀüºÎ ¿Ã¸³´Ï´Ù. µû¶ó¼ À̰÷¿¡ ÀÚµ¿À¸·Î º¹»çÇϵµ·Ï ¼³Á¤ÇÏ´Â °ÍÀÌ ÁÁ½À´Ï´Ù. À̰ÍÀÌ
¼³Á¤ÀÌ ¾ÈµÇ¸é ¸Å ¹ø Ç÷¯±×ÀÎÀ» À̰÷¿¡ º¹»çÇØ ³õ¾Æ¾ß ÇÕ´Ï´Ù.

<SDK Çì´õ ÆÄÀÏ Path,
Ç÷¯±×ÀÎ Ãâ·Â À§Ä¡, ¸Æ½º ½ÇÇà ÆÄÀÏ °æ·Î ¼³Á¤>
Finish ¹öưÀ» ´©¸£¸é À§Àúµå Äڵ尡 ¸¸µé¾îÁý´Ï´Ù. 2005ÀÇ °æ¿ì¿¡´Â ÇÁ·ÎÁ§Æ®°¡ Visual Studio¿¡ ¿Ã¶ó¿ÀÁö
¾ÊÀ» °ÍÀÔ´Ï´Ù. À̰ÍÀº ÀÌ À§Àúµå°¡ 2003 ¹öÀü¿¡ ¸ÂÃß¾îÁ®
Àֱ⠶§¹®ÀÔ´Ï´Ù. Visual Studio¸¦ ´Ý°í ¾Õ¼ ¸¸µç maxProject1.vcproj
¸¦ ´Ù½Ã ½ÇÇàÇÏ¸é º¯È¯ ¸¶¹ý»ç°¡ ÁøÇàÀÌ µË´Ï´Ù. ¸¶¹ý»ç¸¦ ÁøÇàÇØµµ ´ÙÀ½°ú °°Àº ¿¡·¯°¡ ¹ß»ýÇÒ
°ÍÀÔ´Ï´Ù.
"XML ±¸¹®À» ºÐ¼®ÇÏ´Â µ¿¾È ´ÙÀ½°ú °°Àº ¿À·ù°¡ ¹ß»ýÇß½À´Ï´Ù. ÆÄÀÏ:
E:\_Document\_vc\maxProject1\maxProject1.vcproj ÁÙ: 86 ¿: 22 ¿À·ù ¸Þ½ÃÁö: ºÎ¸ð ¿ä¼Ò
'Configuration'ÀÇ ÄÜÅÙÃ÷ ¸ðµ¨¿¡ µû¸£¸é 'IntelOptions'Àº(´Â) ¿¹±âÄ¡ ¾ÊÀº ¿ä¼ÒÀÔ´Ï´Ù. ¡¦"
´çȲÇÏÁö ¸»°í ¸Þ¸ðÀåÀ¸·Î vcproj ÆÄÀÏÀ» ¿¾î¼ ´ÙÀ½ ºÎºÐÀ» °ú°¨È÷
»èÁ¦ ÇÕ´Ï´Ù. ´Ù½Ã Visual Studio¸¦ ½ÇÇàÇÏ°í º¯È¯
¸¶¹ý»ç¸¦ ÁøÇàÇÏ¸é ¹«»çÈ÷ ÇÁ·ÎÁ§Æ®°¡ ¿Ã¶ó ¿É´Ï´Ù.

<ÇÁ·ÎÁ§Æ® ¿É¼Ç ¼³Á¤>
¿©±â±îÁö ÇßÀ¸¸é ´Ù µÈ °Í °°Àºµ¥ ¾ÈŸ±õ°Ôµµ ÇÁ·ÎÁ§Æ®¸¦ ºôµå ÇÏ¸é ¿¡·¯°¡ 10°³
Á¤µµ ¸¸µé¾î Áý´Ï´Ù. À̰ÍÀº Visual Studio 2005 ¹öÀüÀÌ
ÀÌÀü ¹öÀüº¸´Ù C++ Ç¥ÁØÀ» ¾ö°ÝÈ÷ µû¸£´Ù º¸´Ï ¸¸µé¾îÁø ¹®Á¦µéÀÔ´Ï´Ù.
ã¾Æ¼ ÇØ°áÇÏ¸é µË´Ï´Ù.
ù ¹øÂ° ¿¡·¯´Â d:\_3dsmax8\maxsdk\include\manipulator.h(463)
ÆÄÀÏÀÇ ManipExport Invalidate() { mValid = NEVER; }¿¡¼
³ª¿Ô±º¿ä.
2005 ÀÌÀü¿¡´Â ÇÔ¼öÀÇ ¹Ýȯ ÇüÀ» ÀûÁö ¾ÊÀ¸¸é intÇüÀ¸·Î ÄÄÆÄÀÏ·¯°¡ ÀνÄÇß°í ¹ÝȯÀ» ÁöÁ¤ÇÏÁö ¾Ê¾Æµµ Warning¸¸
¸¸µé¾îÁö°í ÄÄÆÄÀÏÀº µÆ½À´Ï´Ù. ÄÚµåÀÇ ³»¿ë»óÀ¸·Î ºÁ¼ ¹ÝȯÀº ¾ø¾î
void°¡ ¸Â°ÚÁö¸¸ ÀÌÀü¿¡´Â intÇüÀ̾úÀ¸¹Ç·Î
Invalidate ¾Õ¿¡ int¸¦ Àû¾î ÁÝ´Ï´Ù.
ManipExport int Invalidate() { mValid = NEVER; }
¶Ç ´Ù¸¥ ¿¡·¯´Â
"e:\_document\_vc\maxproject1\maxproject1.cpp(48):error
C2065: 'themaxProject1'" ¿¡¼ ¸¸µé¾î Á³½À´Ï´Ù.
"void* Create(BOOL loading = FALSE) {
return &themaxProject1; }" À¸·Î ÀÛ¼ºµÇ¾î ÀÖ´Â ºÎºÐÀ» ÇÁ·ÎÁ§Æ®ÀÇ À̸§°ú °°Àº Ŭ·¡½ºÀÇ ÀνºÅϽº¸¦
¸¸µå´Â ÄÚµå·Î ÀüȯÇÕ´Ï´Ù.
void* Create(BOOL loading = FALSE) { return new maxProject1(); }
±× ´ÙÀ½ÀÇ maxProject1ObjClassDesc Ŭ·¡½º ÄÚµåºÎÅÍ
Äݹé(Call Back) ÇÔ¼ö maxProject1OptionsDlgProc()
Àü±îÁö ÇÊ¿ä ¾ø´Â ÄÚµåÀ̹ǷΠÀüºÎ »èÁ¦ÇØ ¹ö¸³´Ï´Ù. ´ë·«
80~ 224 ¶óÀÎÀÌ µÉ °Í °°½À´Ï´Ù. ÀÌ·¸°Ô Áö¿ì¸é Ŭ·¡½º´Â maxProject1, maxProject1ClassDesc µÎ
°³¸¸ ³²¾Æ ÀÖÀ» °ÍÀÔ´Ï´Ù. ´Ù½Ã ÄÄÆÄÀÏ Çϸé À̹ø¿¡´Â ¸®¼Ò½º ÆÄÀÏ(rc)¿¡¼
¿¡·¯°¡ ¸¸µé¾îÁú °ÍÀÔ´Ï´Ù. ¿¡·¯ ºÎºÐÀº Áö¿ó´Ï´Ù.
´Ù½Ã ºôµå Çϸé À̹ø¿¡´Â "DllEntry.obj : error
LNK2019: "class ClassDesc2 * __cdecl GetmaxProject1ObjDesc" ¿¡·¯°¡
¹ß»ýÇÕ´Ï´Ù. À̰ÍÀº ¾Õ¼ maxProject1ClassDesc Ŭ·¡½º¸¦
Áö¿ü±â ¶§¹®ÀÔ´Ï´Ù.
DllEntry.cppÀÇ 16¶óÀÎ "extern ClassDesc2* GetmaxProject1ObjDesc();"
ºÎºÐ°ú 59¶óÀÎ "case
1: return GetmaxProject1ObjDesc();"À» »èÁ¦ÇÕ´Ï´Ù.
´Ù½Ã ºôµå ÇÏ¸é ¸µÅ© ¿¡·¯ "error LNK2001:
"public: virtual class Manipulator * __thiscall maxProject1ClassDesc"°¡
¸¸µé¾îÁý´Ï´Ù.
Ŭ·¡½º maxProject1ClassDesc ¾ÈÀÇ "BOOL IsManipulator() { return TRUE; }" ºÎÅÍ
"Manipulator*
CreateManipulator(RefTargetHandle hTarget, INode* pNode);"±îÁö ÀüºÎ Áö¿ó´Ï´Ù.
ÀÌ·¸°Ô Áö¿ì°í ³ª¸é maxProject1ClassDesc Ŭ·¡½º´Â
´ÙÀ½°ú °°Àº ÇÔ¼ö¸¸ ³²¾Æ ÀÖÀ» °ÍÀÔ´Ï´Ù.
class maxProject1ClassDesc : public ClassDesc2 {
public:
int IsPublic() { return TRUE; }
void * Create(BOOL loading = FALSE) { return new maxProject1(); }
const TCHAR * ClassName() { return GetString(IDS_CLASS_NAME); }
SClass_ID SuperClassID() { return SCENE_EXPORT_CLASS_ID;
}
Class_ID ClassID() { return maxProject1_CLASS_ID;
}
const TCHAR* Category() { return GetString(IDS_CATEGORY); }
const TCHAR* InternalName() { return _T("maxProject1"); }
HINSTANCE HInstance() { return hInstance; }
};
¼Ö·ç¼ÇÀ» ´Ù½Ã ºôµåÇϸé "plugins" Æú´õ¿¡ "maxProject1.dle" ÆÄÀÏÀÌ ¸¸µé¾î Áý´Ï´Ù. ¿¬½À
»ï¾Æ Äڵ尡 µ¿ÀÛ ÇÏ´ÂÁö ´ÙÀ½°ú °°ÀÌ »ý¼ºÀÚ ¼Ò¸êÀÚ, ±×¸®°í
Ext() ÇÔ¼ö¿¡ ¸Þ½ÃÁö ¹Ú½º¸¦ ¶ç¿ö ³õ°í()ºê·¹ÀÌÅ© Æ÷ÀÎÆ®¸¦ ¼³Á¤(F9 Ű)ÇÕ´Ï´Ù.
maxProject1::maxProject1()
{
¡Ü MessageBox(NULL, "Create maxProject1", "Message", 0);
}
maxProject1::~maxProject1()
{
¡Ü MessageBox(NULL, "Destory maxProject1", "Message", 0);
}
const TCHAR *maxProject1::Ext(int n)
{
¡Ü MessageBox(NULL, "Call maxProject1 Exporter", "Message", 0);
return _T("");
}
µð¹ö±× ¸ðµå·Î ½ÇÇàÇÏ¸é ´ÙÀ½°ú °°ÀÌ Ã¢ÀÌ ¿Ã¶ó¿À°í ¿©±â¿¡ ¸Æ½º ÇÁ·Î±×·¥ÀÇ À§Ä¡¸¦ ã¾Æ¼ ³ÖÀ¸¸é ¸Æ½º°¡ ½ÇÇàÀÌ
µË´Ï´Ù.

<Visual Studio¿¡¼ Ç÷¯±×ÀÎ µ¿ÀÛÀ¸·Î À§ÇØ ¸Æ½º ½ÇÇà: mxp00_maxProject1.zip >
µð¹öµù Á¤º¸ ¾øÀ½ âÀÌ ³ª¿Íµµ "¿¹"¸¦ ¼±ÅÃÇϽʽÿÀ.
¾Æ¹« µµÇüÀ̳ª ´ëÃæ ±×¸®°í ´ÙÀ½ ±×¸²°ú °°ÀÌ Export¸¦ ¼±ÅÃÇØ¼
½ÇÇàÇÏ¸é ¼³Á¤ÇÑ ºê·¹ÀÌÅ© Æ÷ÀÎÅͰ¡ µ¿ÀÛÇÏ°í °£´ÜÇÑ ¸Þ½ÃÁö âÀÌ ¿Ã¶ó¿À´Â °ÍÀ» È®ÀÎÇÒ ¼ö ÀÖ½À´Ï´Ù.

<Ç÷¯±×ÀÎ ½ÇÇà>
5.1.2 ´Ù¸¥ ÇÁ·ÎÁ§Æ® ¼öÁ¤
´Ù¸¥ »ç¶÷ÀÌ ÀÛ¼ºÇÑ Ç÷¯±×ÀÎ ÇÁ·ÎÁ§Æ®¸¦ ¼öÁ¤ÇÏ°í ½ÍÀ» ¶§µµ ÀÖ½À´Ï´Ù. ¿¹¸¦
µé¾î "mxp00_mymax0.zip"
¸¦ LcMax¶ó´Â ÇÁ·ÎÁ§Æ®·Î ¸ðµÎ ¹Ù²Û´Ù°í ÇսôÙ. ¸ÕÀú
ÇØ ¾ßÇÒ ÀÏÀº ÆÄÀÏ "mymax.*"·Î µÇ¾î ÀÖ´Â À̸§À» "LcMax.*"·Î ¹Ù²Ù´Â °ÍÀÔ´Ï´Ù.

<ÆÄÀÏ À̸§ ¹Ù²Ù±â>
´ÙÀ½À¸·Î editplus µîÀÇ ÆíÁý±â¸¦ ÀÌ¿ëÇØ¼ ±×¸²ÀÇ ¸ðµç ÆÄÀÏÀ»
¿¾î¼ "mymax"¶ó´Â À̸§À» ÀüºÎ LcMax·Î ¹Ù²Ù¾î ÁÖ¾î¾ß ÇÕ´Ï´Ù.

<ÇÁ·ÎÁ§Æ® ³»¿ë ÀüºÎ ¹Ù²Ù±â>
ÀÌ·¸°Ô ÆÄÀÏ À̸§°ú ÇÁ·ÎÁ§Æ®ÀÇ ³»¿ëÀ» ¹Ù²Ù°í ³ª¼ ´ÙÀ½°ú °°Àº Class_IDÀÇ
°ªÀ» ã¾Æ¼ ¹Ù²Ù¾î¾ß ÇÕ´Ï´Ù.
#define ¡¦_CLASS_ID
Class_ID(0x¡¦, 0x¡¦)
Class_ID °ªÀº Guid
Number ¸¦ Á÷Á¢ Á¶ÇÕÇØ¼ ¸¸µé¾îµµ µÇ°í ¸Æ½º SDK°¡ ¼³Ä¡µÈ ÇÏÀ§ Æú´õ help ¾Æ·¡ gencid.exe("¸Æ½º SDK Æú´õ\help\gencid.exe") ÆÄÀÏÀÌ ÀÖ½À´Ï´Ù. À̰ÍÀ» ½ÇÇàÇϰí New Class ID ¹öưÀ» ´©¸£°í Copy To Clipboard ¹öưÀ» ´©¸¥ ´ÙÀ½ Class_ID À§¿¡ "Ctrl+V" ۸¦ ´©¸£¸é »õ·Î¿î °ªÀÌ ºÙ¿©Áý´Ï´Ù.
´ÙÀ½À¸·Î È®ÀåÀÚ¸¦ ¹ÝȯÇÏ´Â Ext(int n) ÇÔ¼öµµ ÀÚ½ÅÀÌ Á¤ÇÑ À̸§¿¡ ¸Â°Ô °íĨ´Ï´Ù.
const TCHAR *LcMax::Ext(int n)
{
return _T("acm");
}
ºôµå ÈÄ ½ÇÇàÇϰí Menu à "File" à "Export¡¦"
¸¦ ÁøÇà ÇÏ¸é ´ÙÀ½ ±×¸²Ã³·³ ExportÇÒ Áغñ°¡ µÇ¾î ÀÖÀ½À» º¼ ¼ö ÀÖ½À´Ï´Ù.

<´Ù¸¥ ÇÁ·ÎÁ§Æ®¸¦ ¹Ù²Ù¾î »ç¿ëÇÒ ¶§: mxp01_lcmax.zip>
5.1.3 ASE ÇÁ·ÎÁ§Æ® ¼öÁ¤
¸Æ½º SDK°¡ ¼³Ä¡µÈ Æú´õ¿¡¼
"samples" Æú´õ¿¡´Â ´Ù¾çÇÑ Ç÷¯±×ÀÎ ¿¹Á¦µéÀÌ ÀÖ½À´Ï´Ù. ÀÌÁß¿¡¼ "¸Æ½º SDK Æú´õ\samples\import_export\asciiexp"
¿¡´Â ¿©·¯ºÐ¿¡°Ô Ä£¼÷ÇÑ ASE ÆÄÀÏÀ» ¸¸µå´Â ¿¹Á¦°¡ ÀÖ½À´Ï´Ù. "asciiexp.vcproj" ÇÁ·ÎÁ§Æ®¸¦ ¿°í º¯È¯À» ½ÃµµÇÏ¸é ´ÙÀ½°ú °°Àº ¿¡·¯¿¡ ´ëÇÑ
¸Þ½ÃÁö¸¦ º¼ ¼ö ÀÖ½À´Ï´Ù.
"±¸¹®À» ºÐ¼®ÇÏ´Â µ¿¾È ´ÙÀ½°ú °°Àº ¿À·ù°¡ ¹ß»ýÇß½À´Ï´Ù."
"ÆÄÀÏ:
D:\_3dsMax8\maxsdk\samples\import_export\asciiexp\asciiexp.vcproj ÁÙ: 204 ¿: 22 ¿À·ù ¸Þ½ÃÁö: ºÎ¸ð
¿ä¼Ò 'Configuration'ÀÇ ÄÜÅÙÃ÷ ¸ðµ¨¿¡ µû¸£¸é
'IntelOptions'Àº(´Â) ¿¹±âÄ¡ ¾ÊÀº
¿ä¼ÒÀÔ´Ï´Ù."
ÀÌ ¸Þ½ÃÁöÁö´Â Àü¿¡µµ º»ÀûÀÌ ÀÖ´Â ¸Þ½ÃÁö ÀÔ´Ï´Ù. asciiexp.vcproj
ÆÄÀÏÀ» ¸Þ¸ðÀåÀ̳ª Edit plusµîÀ¸·Î ¿¾î¼ ÇØ´ç ¿À» »èÁ¦ÇÕ´Ï´Ù.
"¸Æ½º SDK Æú´õ\help\ gencid.exe"¸¦ ½ÇÇàÇØ¼ »õ·Î¿î ID¸¦ asciiexp.cppÆÄÀÏÀÇ »ó´Ü¿¡ ´ë·« 25¶óÀο¡ ÀÖ´Â Class_ID ¸¦ »õ·Î¿î ¾ÆÀ̵ð·Î
¹Ù²Ù¾î ÁÝ´Ï´Ù.
asciiexp.cppÆÄÀÏÀÇ 135
¶óÀÎ ±ÙóÀÇ Ext(int n) ÇÔ¼öÀÇ ¹ÝȯÀ» ASE¿Í
±¸ºÐÇϱâ À§Çؼ ´ÙÀ½°ú °°ÀÌ asd·Î ¹Ù²Ù¾î ÁÝ´Ï´Ù.
const TCHAR * AsciiExp::Ext(int n)
{
switch(n) {
case 0:
return _T("asd");
}
return _T("");
}
¸¶Áö¸·À¸·Î ÇÁ·ÎÁ§Æ®ÀÇ Ç÷¯±×ÀÎÀÌ Ãâ·ÂÇÒ Æú´õ¸¦ º¯°æÇÕ´Ï´Ù. ¸Þ´º à ÇÁ·ÎÁ§Æ® à "asciiexp"
¼Ó¼ºÀ» ¿¾î¼
"..\..\..\..\maxsdk\plugin\asciiexp.dle"
ºÎºÐÀ» "..\..\..\..\plugins\asciiexp.dle" À¸·Î
º¯°æÇÕ´Ï´Ù.
"maxsdk\plugin" ±×´ë·Î µÎ¸é ÄÄÆÄÀÏ
ÇÑ ÈÄ¿¡ ´Ù½Ã Ç÷¯±×ÀÎÀ» ¿Å°Ü¾ß ÇÕ´Ï´Ù.

<¼öÁ¤µÈ ase: Ãâ·Â
°æ·Î º¯°æ>
¸®¼Ò½º ºä¸¦ ¿¾î IDD_ASCIIEXPORT_DLG¿¡ Å×½ºÆ®·Î ´ÙÀ½°ú
°°ÀÌ ¹öưÀ» Ãß°¡ÇØ º¾½Ã´Ù.

<¸®¼Ò½º ºä: ´ÙÀ̾ó·Îµå
¼öÁ¤>
ÄÄÆÄÀÏ ÇÑ ´ÙÀ½ ½ÇÇàÇÏ°í ³ª¼ ¸Æ½º¿¡¼ ÆÄÀÏÀÌ Export°¡ µÇ´ÂÁö
°£´ÜÇÑ ¹Ú½º ÇÑ °³¸¦ ±×¸³´Ï´Ù. ±×¸®°í ³ª¼ ¸Þ´º à ÆÄÀÏ à Export ¸¦
¼±ÅÃÇϸé ASD¸¦ ¼±ÅÃÇÒ ¼ö ÀÖ°í ´ÙÀ½°ú °°ÀÌ ÀúÀåÇØ º¾´Ï´Ù.

<Export ÆÄÀÏ ÀúÀå>
ÀÌ·¸°Ô Çϸé ÀÌÀü¿¡ ¸®¼Ò½º ºä¿¡¼ ¼öÁ¤ÇÑ ´ÙÀ̾ó·Î±× ȸéÀÌ ³ªÅ¸³ª°í OK ¹öưÀ»
´©¸£¸é È®ÀåÀÚ°¡ asd°¡ ºÙÀº ÆÄÀÏÀÌ »ý¼ºÀÌ µË´Ï´Ù.
"¸Æ½º Æú´õ\stdplugs"
¿¡´Â ±âº»ÀûÀ¸·Î Á¦°øµÇ´Â ¸Æ½º Ç÷¯±×ÀÎÀÌ ÀÖ½À´Ï´Ù. ¿©±â¿¡ 3ds¿Í aseµµ °°ÀÌ ÀÖ½À´Ï´Ù. À̵éÀ»
´Ù¸¥ °÷À¸·Î ¿Å°Ü ³õÀ¸¸é Export ¼±Åÿ¡¼ Áö¿öÁý´Ï´Ù.
¸¸¾à asciexp ÇÁ·ÎÁ§Æ®¸¦ ´Ù¸¥ °÷À¸·Î ¿Å°Ü¼ »ç¿ëÇÏ·Á¸é ¼Ó¼ºÀ»
¿¾î¼ C/C++ ÀÏ¹Ý à Ãß°¡ Æ÷ÇÔ µð·ºÅ丮°¡ »ó´ëÀûÀ¸·Î ¼³Á¤µÇ¾îÀÖ´Â °ÍÀ» Àý´ëÀûÀ¸·Î ¹Ù²Ù¾î ÁÝ´Ï´Ù.
"..\..\..\include" à "¸Æ½º SDK Æú´õ\include"
¸µÄ¿ à ÀÏ¹Ý à "Ãâ·Â ÆÄÀÏ À§Ä¡"¸¦ º¯°æÇÕ´Ï´Ù.
"..\..\..\..\plugins\asciiexp.dle"
à
"D:\_3dsMax8\plugins\asciiexp.dle"
¸µÄ¿ à ÀÔ·Â à "Ãß°¡ Á¾¼Ó¼º"¿¡ ¶óÀ̺귯¸®¸¦ Ãß°¡ÇÕ´Ï´Ù.
"odbc32.lib odbccp32.lib comctl32.lib"
à "odbc32.lib
odbccp32.lib comctl32.lib core.lib geom.lib maxutil.lib mesh.lib"
¸®¼Ò½º à ÀÏ¹Ý à "Ãß°¡ Æ÷ÇÔ µð·ºÅ丮"¸¦ º¯°æÇÕ´Ï´Ù.
"..\..\..\include" à "¸Æ½º SDK Æú´õ\include"
¼Ö·ç¼Ç Ž»ö±â¿¡¼ Libraries¸¦ ÀüºÎ »èÁ¦ÇÕ´Ï´Ù. ÀÌ ¶óÀ̺귯¸®µéÀº ¸µÄ¿ÀÇ ¶óÀ̺귯¸® Ãß°¡ Á¾¼Ó¼º¿¡ ÀÌ¹Ì Æ÷ÇÔ½ÃÄ×½À´Ï´Ù.
"¸Æ½º Æú´õ\plugins"
¿¡¼ ÀÌÀü¿¡ ¿¬½ÀÀ¸·Î ÀÛ¼ºÇÑ Ç÷¯±×ÀÎ µéÀ» ÀüºÎ Á¤¸®ÇÏ°í ¼öÁ¤µÈ asciiexp¸¦ ÄÄÆÄÀÏ
ÇØ¼ À̰÷¿¡ »õ·Î »ý¼ºÀÌ µÇ´ÂÁö È®ÀÎÇÕ´Ï´Ù.

<ÇÁ·ÎÁ§Æ®¿¡ Æ÷ÇÔµÈ ¼Ö·ç¼Ç ¶óÀ̺귯¸® »èÁ¦>
mxp01_modified_ase.zipÀº asciiexpÀÇ ÇÁ·ÎÁ§Æ® À̸§°ú ÆÄÀÏ À̸§ µîÀ» ¼öÁ¤ÇÑ ¿¹Á¦ÀÔ´Ï´Ù.
°£´ÜÇÑ Ç÷¯±×ÀÎÀ̶ó¸é ase ÇÁ·ÎÁ§Æ®¸¦ Á¤¸®Çؼ »ç¿ëÇÏ´Â °ÍÀÌ °¡Àå
¹«³ÇÕ´Ï´Ù. ase´Â °Ã¼ ¾Ö´Ï¸ÞÀ̼Ç(Rigid Body
Animation)À¸·Î ±¸¼ºµÇ¾î ÀÖ½À´Ï´Ù. ¸¸¾à ½ºÅ°´×À» ÃßÃâÇÏ·Á¸é ase¿Í ´Ù¸£°Ô ±¸¼ºÇØ¾ß ÇÕ´Ï´Ù. ¸ÕÀú ase¿¡¼ »ç¿ëµÈ µ¥ÀÌÅÍ ÃßÃâ°ú ¾Ö´Ï¸ÞÀ̼ÇÀ» ±¸ÇöÇØ º¸°í ÀÌÈÄ¿¡ SkinngÀ»
±¸ÇöÇØ º¾½Ã´Ù.
5.1.4 Wrapper Ç÷¯±×ÀÎ
¸Æ½º´Â ÇÁ·Î±×·¥À» ½ÃÀÛÇÒ ¶§ Ç÷¯±×ÀÎÀ» ÀüºÎ ·Îµå Çϰí ÀÖ½À´Ï´Ù. µû¶ó¼
Ç÷¯±×ÀÎÀ» Áö¿ì°Å³ª ±³Ã¼ÇÏ·Á¸é ¸Æ½º¸¦ ÁßÁö ½ÃÄÑ¾ß ÇÕ´Ï´Ù. À̰ÍÀº ÀÚÁÖ µð¹öµù ÇØ¾ß ÇÏ´Â Ç÷¯±×ÀÎ Á¦ÀÛ¿¡¼´Â
»ó´çÈ÷ ºÒÆíÇÕ´Ï´Ù. ÀÌ ¹®Á¦·Î °í»ýÇÏ´Ù°¡ Tom Hudson ¶ó´Â
ºÐÀÌ Ç÷¯±×ÀÎÀ» Wrapping ÇÏ´Â ¹æ¹ýÀ» ÀÎÅͳݿ¡ ¾ÆÀ̵ð¾î¿Í Äڵ带 ¿Ã·Á³õ¾Ò½À´Ï´Ù. ´ÙÀ½ÀÇ ³»¿ëÀº Tom HudsonÀÌ ¸¸µç °ÍÀ» Á¤¸®ÇÑ °ÍÀÔ´Ï´Ù.
mxp01_lcmax.zip
¿¡¼ »ý¼ºÀÚ LcMax Ŭ·¡½ºÀÇ »ý¼ºÀÚ ÇÔ¼ö, ¼Ò¸êÀÚ
ÇÔ¼ö, Ext() ÇÔ¼ö, DoExport()ÇÔ¼ö¿¡ ´ÙÀ½°ú
°°Àº ¸Þ½ÃÁö âÀ» ³Ö°í µð¹ö±×·Î ½ÇÇàÇØ º¾½Ã´Ù.
LcMax::LcMax()
{
¡Ü MessageBox(NULL, "Constructor LcMax", "Message", 0);
}
LcMax::~LcMax()
{
¡Ü MessageBox(NULL, "Destroyer LcMax", "Message", 0);
}
const TCHAR *LcMax::Ext(int n)
{
¡Ü MessageBox(NULL, "Constructor LcMax", "Message", 0);
return _T("acm");
}
int LcMax::DoExport(¡¦)
{
¡Ü MessageBox(NULL, "Do Export LcMax", "Message", 0);
}
¸Æ½º¿¡¼ ¹Ú½º¸¦ Çϳª ±×¸®°í ÆÄÀÏ à Export¸¦
¼±ÅÃÇÕ´Ï´Ù. ±×·¯¸é LcMax Ŭ·¡½ºÀÇ »ý¼ºÀÚÀÇ ºê·¹ÀÌÅ©
Æ÷ÀÎÅÍ¿¡ ÇÁ·Î¼¼½º°¡ °É¸³´Ï´Ù. ¶Ç ÁøÇà Çϸé Ext() ÇÔ¼ö¿¡¼, ±×¸®°í ´Ù½Ã ÁøÇàÇÏ¸é ¼Ò¸êÀÚ¿¡¼ ÇÁ·Î¼¼½º°¡ ÁøÇàµÊÀ» ¾Ë ¼ö ÀÖ½À´Ï´Ù. ÀÌ
µ¿ÀÛÀº Export¸¦ ¼±ÅÃÇÒ ¶§ ¸Æ½º°¡ Ç÷¯±×ÀεéÀÇ À̸§À» ¾ò´Â °úÁ¤ÀÎ °ÍÀ» ¾Ë ¼ö ÀÖ½À´Ï´Ù. ÀúÀåÇÒ À̸§À» ¼±ÅÃÇÏ°í °è¼ÓÇÏ¸é »ý¼ºÀÚ à DoExport() à ¼Ò¸êÀÚ·Î ÇÁ·Î¼¼½º°¡ ÁøÇàµÊÀ» º¼
¼ö ÀÖ½À´Ï´Ù.
ÀÌ µÎ µ¿ÀÛÀ» Á¤¸®ÇÏ¸é ¸Æ½º´Â Ç÷¯±×ÀÎÀ» ÇÁ·Î±×·¥¿¡¼ ·ÎµåÇϰí
ÀÖ°í ¸¸¾à Export°¡ ¿äûÀÌ µÇ¸é SceneExport Ŭ·¡½º¸¦ »ó¼Ó¹ÞÀº °´Ã¼ÀÇ »ý¼ºÀÚ à ÀÛ¾÷¿¡ ÇÊ¿äÇÑ ÇÔ¼ö È£Ãâ à ¼Ò¸êÀÚ¸¦ ¹Ýº¹ÇÑ´Ù°í ÇÒ ¼ö ÀÖ½À´Ï´Ù.
¾Õ¼ ¸Æ½ºÀÇ Ç÷¯±×ÀÎÀº DLLÀ̶ó°í Çß½À´Ï´Ù. Wrapper Ç÷¯±×ÀÎÀÇ ÀÛµ¿ ¼ø¼´Â ÀÛ¾÷ ¿äûÀÌ ¿À¸é ±× ÀÛ¾÷¿¡ ÇØ´çÇÏ´Â
Child Ç÷¯±×ÀÎÀ» ·Îµå Çϰí Child Ç÷¯±×ÀÎÀÇ ÀÛ¾÷À» ½ÇÇàÇÑ ´ÙÀ½, ¼Ò¸êÀÚ¿¡¼ Child DLLÀ» ÇØÁ¦ÇÕ´Ï´Ù. À̰ÍÀ» ±×¸²À¸·Î Ç¥ÇöÇÏ¸é ´ÙÀ½°ú °°½À´Ï´Ù.

<¸Æ½º¿¡ »ç¿ëµÇ´Â Ç÷¯±×ÀÎ: ÀϹÝÀûÀÎ
Ç÷¯±×Àΰú Wrapper Ç÷¯±×ÀÎ>
Wrapper Ç÷¯±×ÀÎÀ» ¸¸µé±â À§Çؼ LcMax Ç÷¯±×ÀÎÀÇ À̸§À» LcWrapper·Î ¹Ù²ß´Ï´Ù. ´ÙÀ½À¸·Î Å×½ºÆ®¸¦ À§ÇØ "plugins" Æú´õ¿¡
ÀÖ´ø "asdexp.dle" C µå¶óÀÌºê ·çÆ®·Î ¿Å°Ü ³õ¾Ò½À´Ï´Ù. ÀÌ Ç÷¯±×ÀÎÀ» LcWrapper Ç÷¯±×ÀÎÀÌ ·¡ÇÎ(Wrapping)ÇÒ °ÍÀÔ´Ï´Ù.
LcWrapper Ŭ·¡½º´Â ´ÙÀ½°ú °°ÀÌ 3 °³ÀÇ ¸â¹ö º¯¼ö¸¦ Ãß°¡ÇÕ´Ï´Ù.
class LcWrapper : public SceneExport
¡¦
HINSTANCE m_hInst; // DLL Instance
ClassDesc* m_pChildDesc; // DLL ¿¡¼ ¾òÀº Child °´Ã¼ ÁÖ¼Ò
SceneExport* m_pChild; // Export¿¡ ¿äûµÇ´Â
ÀÛ¾÷À» ´ã´çÇÒ °´Ã¼
m_pChildDesc º¯¼ö´Â
DLL¿¡¼ ¾òÀº ClassDesc2 Ŭ·¡½º¸¦ »ó¼Ó¹ÞÀº °´Ã¼ÀÇ ÁÖ¼ÒÀÔ´Ï´Ù. ÀÌ °´Ã¼ÀÇ Create()ÇÔ¼ö¸¦ ÀÌ¿ëÇØ¼ m_pChild °´Ã¼¸¦ »ý¼ºÇÕ´Ï´Ù.
À̰ÍÀ» ±¸Ã¼ÀûÀ¸·Î ±¸ÇöÇϸé LcWrapper Ŭ·¡½ºÀÇ »ý¼ºÀÚ´Â ·¡ÇÎ
´ë»ó Ç÷¯±×ÀÎ(DLL)À» ·ÎµåÇϱâ À§ÇØ LoadLibray()ÇÔ¼ö¸¦
»ç¿ëÇÕ´Ï´Ù. ´ÙÀ½À¸·Î GetProcAddress() ÇÔ¼ö¸¦
ÀÌ¿ëÇØ¼ ClassDesc °´Ã¼ÀÇ ÁÖ¼Ò¸¦ ¾ò¾î¿É´Ï´Ù. ¸¶Áö¸·À¸·Î
ClassDesc Ŭ·¡½ºÀÇ Create()ÇÔ¼ö¸¦ È£ÃâÇØ¼
SceneExport °´Ã¼¸¦ »ý¼ºÇÕ´Ï´Ù.
LcWrapper::LcWrapper()
{
m_hInst = NULL;
m_pChildDesc =
NULL;
m_pChild =
NULL;
// Load Plugin(DLL)
m_hInst
= LoadLibrary( "c:/asdexp.dle");
if (!m_hInst)
{
MessageBox(NULL, "Load c:/asdexp.dle Failed", "Err", MB_ICONWARNING);
m_hInst =
NULL;
return;
}
// DLL¿¡¼ Á¦°øÇÏ´Â ÇÔ¼ö
Áß Export¸¦ »ý¼ºÇÒ ¼ö ÀÖ´Â °´Ã¼ ÁÖ¼Ò ¹Ýȯ ÇÔ¼ö ¾ò±â
typedef ClassDesc* (__stdcall *_LibClassDesc)(int i);
_LibClassDesc pLibClassDesc
= (_LibClassDesc) GetProcAddress(m_hInst, "LibClassDesc");
if (pLibClassDesc)
{
m_pChildDesc
= pLibClassDesc(0);
// Export¸¦ ´ã´çÇÒ °´Ã¼
»ý¼º
m_pChild
= (SceneExport*)m_pChildDesc->Create();
}
}
DLLÀÇ .def ÆÄÀÏ¿¡
ÀÖ´Â EXPORTS ¼½¼Ç¿¡ "LibClassDesc @3"·Î
Á¤ÀǵǾî ÀÖ¾î ÇÔ¼öÀÇ À̸§´ë½Å ¼ýÀÚ·Î ´ë½ÅÇØµµ µË´Ï´Ù. ¼ýÀÚ¸¦ »ç¿ëÇϸé 󸮰¡ Á» ´õ »¡¶óÁø´Ù°í ÇÕ´Ï´Ù.
GetProcAddress(m_hInst, (LPCSTR)3);
¼Ò¸êÀÚ´Â »ý¼ºÀÚ¿¡¼ ¸¸µé¾îÁø SceneExport °´Ã¼ m_pChild¸¦ ¸ÕÀú ÇØÁ¦ Çϰí Ç÷¯±×ÀÎÀ» ÇØÁ¦ÇÕ´Ï´Ù.
LcWrapper::~LcWrapper()
{
if(m_pChild)
{
delete m_pChild;
m_pChild
= NULL;
}
// Plugin ÇØÁ¦
if(m_hInst)
{
FreeLibrary(m_hInst);
m_hInst
= NULL;
}
}
°¡Àå Áß¿äÇÑ ÇÔ¼ö DoExport() ÇÔ¼ö¸¦ ´ÙÀ½°ú °°ÀÌ ¼öÁ¤ÇÕ´Ï´Ù.
int LcWrapper::DoExport(const TCHAR *name,ExpInterface *ei
,Interface *i, BOOL suppressPrompts, DWORD options)
{
if(m_pChild)
return m_pChild->DoExport(name, ei, i,
suppressPrompts, options);
return FALSE;
}
ÀÌ·± ¹æ½ÄÀ¸·Î ³ª¸ÓÁö ÇÔ¼öµéµµ ÀüºÎ ¹Ù²Ù¾î ÁÝ´Ï´Ù.
const TCHAR *LcWrapper::Ext(int n)
{
if(m_pChild)
return m_pChild->Ext(n);
return _T("Failed Ext");
}

<Wrapper Plugin: mxp01_wrapper.zip>
Àüü ÄÚµå´Â mxp01_wrapper.zipÀ»
Âü°í Çϱ⠹ٶø´Ï´Ù. ·¡ÇÎÀÌ Á¦´ë·Î µÇ°í ÀÖ´ÂÁö È®ÀÎÇϱâ À§Çؼ ´ÙÀ½°ú °°ÀÌ ¸¸µé¾î º¸¾Ò½À´Ï´Ù.
const TCHAR *LcWrapper::ShortDesc()
static TCHAR s[1024];
if(m_pChild) _stprintf(s, "Wrap(%s)",
m_pChild->ShortDesc());
else _stprintf(s, _T("Failed to load Wrap"));
return s;
5.2 Data Export
5.2.1 Node Export
¸Æ½º´Â ¸ðµç °´Ã¼¸¦ ³ëµå(Node)·Î °ü¸®ÇÕ´Ï´Ù. ÀÌ ³ëµå´Â ´ÙÀ½ ±×¸²°ú °°ÀÌ ³ª¹« ÀÚ·á ±¸Á¶(Tree Data
Structure)·Î ±¸¼ºµÇ¾î ÀÖ½À´Ï´Ù.

<³ª¹« ÀÚ·á ±¸Á¶(Tree
Data Structure)>
¸Æ½º´Â INode ¶ó´Â ÀÎÅÍÆäÀ̽º¸¦ Á¦°øÇϸç INode ÀÎÅÍÆäÀ̽º ÀÇ ¿©·¯ ÇÔ¼ö Áß¿¡¼ NumberOfChildren(),
GetChildNode(index), GetParentNode(), GetParentNode() ÇÔ¼ö µîÀ¸·Î ÇÏÀ§³ëµå ¼ýÀÚ, ÇÏÀ§ ³ëµå, ºÎ¸ð ³ëµå, Root
³ëµå µîÀ» ãÀ» ¼ö ÀÖ½À´Ï´Ù.
¸Æ½º´Â Exporter ¸í·ÉÀÌ ÁÖ¾îÁö¸é SceneExport Ŭ·¡½º¸¦ »ó¼Ó¹ÞÀº
Ŭ·¡½º ¸â¹ö ÇÔ¼ö Áß¿¡¼ DoExport() ÇÔ¼öÀÇ ¼¼ ¹øÂ° ÀμöÀÎ Interface* °´Ã¼ÀÇ GetRootNode() ÇÔ¼ö¸¦ ÀÌ¿ëÇØ¼ Root Node¸¦ ¾òÀ»
¼ö ÀÖ½À´Ï´Ù. °£´ÜÇÏ°Ô Root Node¿Í À̸§, ÇÏÀ§³ëµåµéÀ» ã´Â´Ù¸é ´ÙÀ½°ú °°ÀÌ ÄÚµù ÇÏ¸é µË´Ï´Ù.
int LcMax::DoExport(¡¦,Interface *pi,¡¦)
INode* pRoot = m_pI->GetRootNode();
TCHAR* sName =
pRoot->GetName();
INT nChild = pRoot->NumberOfChildren();
À̰ÍÀ» ½ÇÇàÇÏ¸é ¸Æ½ºÀÇ Root Node À̸§Àº "Scene Root"·Î Ãâ·ÂÀÌ µË´Ï´Ù.
¸¸¾à ¸Æ½º¿¡ ÀÛ¾÷ÇÑ ¸ðµç Node¸¦
ExportÇÒ ¶§´Â Scene RootºÎÅÍ ÇÏÀ§ ³ëµå(Child
Node)µéÀ» Àç±Í(Recursive) ¼øÈ¯À» Àû¿ëÇØ¼ ã¾Æ¾ß ÇÕ´Ï´Ù. À̸¦ À§Çؼ ¸ÕÀú ´ÙÀ½°ú °°ÀÌ INode °´Ã¼ ÁÖ¼Ò¸¦ ÀúÀå Çϱâ
À§ÇØ STLÀÇ º¤ÅÍ ÄÁÅ×À̳ʸ¦ ¼±¾ðÇÕ´Ï´Ù.
std::vector<INode*> m_vMaxNode; // ¸Æ½ºÀÇ ³ëµå ÀڷᱸÁ¶
±×¸®°í ´ÙÀ½°ú °°Àº Àç±Í ÇÔ¼ö¸¦ ÀÌ¿ëÇØ¼ ÀÌ º¤ÅÍ ÄÁÅ×À̳ʿ¡ ³ëµåÀÇ ÁÖ¼Ò¸¦ ÀúÀåÇÕ´Ï´Ù.
void LcMax::GatherNode(INode* pNode)
{
if(!pNode)
return;
INT iChild = pNode->NumberOfChildren();
for(int i=0; i<iChild; ++i)
{
INode* pChild =
pNode->GetChildNode(i);
if(pChild)
GatherNode(pChild);
}
}
ÀÌ ¹æ½ÄÀº ±íÀÌ ¿ì¼± Ž»ö ¹æ½Ä(DFS)ÀÔ´Ï´Ù. ÀÌ·¸°Ô ³ëµå¸¦ ¸ðÀ¸°í À̰ÍÀ» ÆÄÀÏ·Î ÀúÀåÇÕ´Ï´Ù.
FILE* fp = fopen(m_sN, "wt");
INode* pRoot = m_pI->GetRootNode();
GatherNode(pRoot);
for(n =0; n<m_vMaxNode.size(); ++n)
{
INode* pNode = m_vMaxNode[n];
TCHAR* sName
= pNode->GetName();
INT nChild
= pNode->NumberOfChildren();
if(pRoot == pNode->GetParentNode())
fprintf(fp, "\n");
fprintf(fp, "Node Name: %s, Child Number: %d\n", sName, nChild);
}
fclose(fp);
ÇÁ·Î±×·¥À» ¿ÏÀüÇϱâ À§ÇØ ¸®¼Ò½º ºä¿¡¼ ´ÙÀ̾ó·Î±×¿¡ ´ÙÀ½°ú °°Àº ¹öưÀ» ¸¸µì´Ï´Ù.

¶ÇÇÑ DoExport¹öưÀ» ´©¸£¸é
Export°¡ ½ÇÇàµÇµµ·Ï ´ÙÀ½°ú °°ÀÌ Äݹé ÇÔ¼ö¸¦ ¼öÁ¤ÇÕ´Ï´Ù.
INT_PTR CALLBACK LcMaxOptionsDlgProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
¡¦
WPARAM wLoParam = LOWORD(wParam);
WPARAM wHiParam = HIWORD(wParam);
if( WM_INITDIALOG == uMsg)
¡¦
else if( WM_COMMAND == uMsg)
{
if(imp && IDC_EXPORT ==
wLoParam)
{
imp->m_bDoExport
= TRUE;
SendMessage(hWnd, WM_CLOSE, 0, 0);
}
return TRUE;
}
¡¦
´ÙÀ̾ó·Î±×¿¡ ¹öư Ãß°¡¿Í ¸Þ½ÃÁö 󸮿¡ ´ëÇÑ ÀÚ¼¼ÇÑ ³»¿ëÀº WinAPI¸¦ Âü°í Çϱ⠹ٶø´Ï´Ù.
ÀÌ·¸°Ô ¸¸µç Äڵ带 Å×½ºÆ®Çϱâ À§Çؼ ´ÙÀ½°ú °°ÀÌ ¸Æ½º¸¦ ½ÇÇàÇϰí
¸Þ´º à
Create à System à Biped¸¦ ¼±ÅÃÇØ¼ Biped ÀÎÇü 2°³¸¦ ȸ鿡 ±×¸³´Ï´Ù.

<Biped Ãß°¡>
¶Ç´Â ¿ìÃøÀÇ Create
Tab¿¡¼ Åé´Ï¹ÙÄû µÎ °³°¡ ¹°·Á ÀÖ´Â ¹öưÀ» ´©¸£¸é Systems ¹öưÀÌ ³ª¿À°í ÀÌÁß¿¡¼ Biped ¹öưÀ» ¼±ÅÃÇÑ ´ÙÀ½ Biped¸¦ Ãß°¡ÇÕ´Ï´Ù.
ÀÌ Biped´Â
¸Æ½º°¡ ¾Ö´Ï¸ÞÀ̼ÇÀ» Æí¸®ÇÏ°Ô ÀÛ¼ºÇÒ ¼ö ÀÖµµ·Ï Á¦°øµÇ´Â À¯Æ¿¸®Æ¼ÀÌ¸ç ³ª¹« ±¸Á¶(Tree Structure)·Î
±¸¼ºµÇ¾î ÀÖ½À´Ï´Ù. ÀÌ BipedÀÇ ³ëµå¸¦ ÆÄÀÏ·Î ÀúÀåÇÒ
¼ö ÀÖÀ¸¸é ³ª¸ÓÁö ¸Æ½º¿¡¼ ±¸¼ºµÈ ¿ÀºêÁ§Æ®ÀÇ ³ëµåµéµµ °°Àº ¹æ¹ýÀ¸·Î ÆÄÀÏ¿¡ ÀúÀåÇÒ ¼ö ÀÖ½À´Ï´Ù.
ÀÌ·¸°Ô Biped 2°³¸¦
¸¸µé°í ExportÇÑ ´ÙÀ½ ÆÄÀÏÀ» ¿¾îº¸¸é "Scene
Root" ºÎÅÍ "Bip01", " Bip02"·Î
½ÃÀÛÇÏ´Â ³ëµåµéÀÌ ¸ðµÎ ±â·ÏµÇ¾î ÀÖÀ½À» º¼ ¼ö ÀÖ½À´Ï´Ù.
Âü°í·Î ¸Æ½ºÀÇ Schematic View¸¦ ¼±ÅÃÇϸé ÇöÀç ¸Æ½º¿¡ ÀÖ´Â
°´Ã¼°¡ ³ªÅ¸³³´Ï´Ù.

<Schematic View>
Àüü ÄÚµå´Â mxp11_nodes.zip¸¦ Âü°í Çϱ⠹ٶø´Ï´Ù.
5.2.2 Object
Export
Root ³ëµå¸¦
Á¦¿ÜÇÑ ¸ðµç ³ëµå´Â Object¸¦ °¡Áö°í ÀÖ½À´Ï´Ù. ÀÌ Object´Â NodeÀÇ ¿ªÇÒÀ̶ó »ý°¢ÇÏ¸é µË´Ï´Ù. ¸Æ½ºÀÇ Object´Â ½Ã½ºÅÛ¿¡¼ ÆÄ»ýµÈ Derived Object¿Í Procedural Object µÎ Á¾·ù°¡
ÀÖ½À´Ï´Ù. Derived Object´Â ½Ã½ºÅÛÀÇ ÇÑ ºÎºÐÀ¸·Î¼
º¯°æÀÌ ºÒ°¡´ÉÇϸç Procedural Object´Â Ä«¸Þ¶ó, Á¶¸í, Helper, Geometry µî ¼öÁ¤ÀÌ °¡´ÉÇÑ ObjectÀÔ´Ï´Ù.

<¸Æ½ºÀÇ ¿©·¯
Á¾·ù Object>
³ëµåÀÇ ¿ªÇÒÀ» ¾Ë¾Æº¸±â À§ÇØ ´ÙÀ½°ú °°ÀÌ Object TypeÀ» È®ÀÎÇÕ´Ï´Ù.
Object* pObject = pNode->GetObjectRef();
if(pObject)
{
SClass_ID lSuperID =
pObject->SuperClassID();
Class_ID lClassID =
pObject->ClassID();
if(GEOMOBJECT_CLASS_ID ==
lSuperID)
{
if( BONE_OBJ_CLASSID ==
lClassID || Class_ID(BONE_CLASS_ID, 0) == lClassID)
{
}
else
{
}
}
else if(CAMERA_CLASS_ID ==
lSuperID)
¡¦
else if(LIGHT_CLASS_ID ==
lSuperID)
¡¦
}
Ä«¸Þ¶ó, Á¶¸í, Helper, Shape µîÀº °ÔÀÓ ³»ºÎ¿¡¼ Á¤ÇÑ µ¥ÀÌÅ͸¦ »ç¿ëÇÕ´Ï´Ù. µû¶ó¼
À̵éÀº Ưº°ÇÑ °æ¿ì°¡ ¾Æ´Ï¶ó¸é º¸ÅëÀº Á¦¿Ü´ë»óÀÌ¸ç ¿ì¸®ÀÇ ÁÖ °ü½ÉÀº Geometry Object ÀÔ´Ï´Ù.
Geometry Objectµµ
ClassID() ÇÔ¼ö·Î ÇÑ ¹ø Á¶»çÇØ¾ß ÇÒ ³»¿ëÀÌ ÀÖ½À´Ï´Ù. ¾Ö´Ï¸ÞÀ̼ÇÀ» Á» ´õ Æí¸®ÇϰÔ
Çϱâ À§Çؼ Bone, ¶Ç´Â Bipe¸¦ ÀÌ¿ëÇÕ´Ï´Ù. À̵鵵 Æú¸®°ïÀÌ ÀÖÀ¸¸ç Geometry class ÀÔ´Ï´Ù. ExportµÈ µ¥ÀÌÅ͸¦ È®ÀÎÇÏ´Â Viewer ÇÁ·Î±×·¥¿¡¼ ¾Ö´Ï¸ÞÀ̼ÇÀ»
´«À¸·Î »ìÇDZâ À§ÇØ BoneÀ» ȸ鿡 Ç¥½ÃÇϹǷΠÀûÁ¤ÇÑ Á¤Á¡ ±¸Á¶Ã¼¿Í Æ÷¸ËÀ¸·Î À̵鵵 ÃßÃâÇØ¾ß ÇÕ´Ï´Ù. Bone 󸮿¡ ´ëÇØ¼´Â ÀÌÈÄ ¾Ö´Ï¸ÞÀ̼ǿ¡¼ ´Ù½Ã ÇϰڽÀ´Ï´Ù.
Àüü ÄÚµå´Â mxp12_object.zipÀÇ
LcMax::DoExport() ÇÔ¼ö¸¦ Âü°íÇϱ⠹ٶø´Ï´Ù.
5.2.3 Mesh
¸Æ½º´Â Mesh¸¦ ÅëÇØ¼ ȸ鿡 ¿ÀºêÁ§Æ®¸¦ Ç¥ÇöÇÕ´Ï´Ù. ¸Þ½¬´Â Á¤Á¡ µ¥ÀÌÅÍ, À妽º µ¥ÀÌÅÍ µîÀ» Æ÷ÇÔÇϰí ÀÖ¾î¼ ¿ì¸®´Â
À̰ÍÀ» ExportÇØ¼ °ÔÀÓ¿¡¼ Á¤Á¡ ¹öÆÛ¿Í À妽º ¹öÆÛ·Î »ç¿ëÇØ¾ß ÇÕ´Ï´Ù.
¿ì¸®´Â °ÔÀÓ¿¡¼ ÁÖ·Î »ï°¢ÇüÀ» ±âº»À¸·Î ·»´õ¸µ ¿ÀºêÁ§Æ®¸¦ ±¸¼ºÇÕ´Ï´Ù. ±×·±µ¥
¸Æ½ºÀÇ Primitive´Â D3D º¸´Ù ´Ù¾çÇØ¼ ¸Æ½ºÀÇ ¸Þ½¬¸¦ D3D¿¡¼ »ç¿ëÇÒ ¼ö ÀÖµµ·Ï ¹Ù²Ù¾î¾ß ÇÕ´Ï´Ù.
¸ÕÀú ¸Æ½ºÀÇ Object¿¡°Ô »ï°¢ÇüÀ¸·Î ¸Þ½¬ÀÇ ±¸Á¶¸¦ ¹Ù²Ü ¼ö ÀÖ´ÂÁö
CanConvertToType()
ÇÔ¼ö·Î È®ÀÎÇϰí, ÀüȯÀÌ °¡´ÉÇϸé ConvertToType() ÇÔ¼ö·Î Æú¸®°ïÀ» ±¸¼ºÇÏ´Â TriObject¸¦ ´ÙÀ½°ú °°ÀÌ ¾ò¾î ³À´Ï´Ù.
if(!pObj->CanConvertToType(Class_ID(TRIOBJ_CLASS_ID, 0)))
continue;
TriObject* pTri = (TriObject *)pObj->ConvertToType(0, Class_ID(TRIOBJ_CLASS_ID, 0));
´ÙÀ½À¸·Î TriObject¿¡¼ Mesh¸¦ ´ÙÀ½°ú °°ÀÌ ¾ò½À´Ï´Ù.
Mesh* pMesh =
&pTri->GetMesh();
ÀÌ Mesh¿¡ Æú¸®°ïÀ»
±¸¼ºÇÏ´Â °¢°¢ÀÇ »ï°¢Çü¿¡ ´ëÇÑ À妽º µ¥ÀÌÅÍ¿Í Á¤Á¡ µ¥ÀÌÅͰ¡ Æ÷ÇÔµÇ¾î ´ÙÀ½°ú °°ÀÌ À妽º, Á¤Á¡ÀÇ ¼ýÀÚ¸¦
¾ò°í, ÀÌ ¼ýÀÚ¸¸Å ȸÀüÇÏ¸é¼ À妽º, Á¤Á¡ µ¥ÀÌÅ͸¦ ¾ò¾î
³À´Ï´Ù.
INT iNvtx =
pMesh->getNumVerts();
INT iNfce =
pMesh->getNumFaces();
// À妽º µ¥ÀÌÅÍ Ãâ·Â
for (i=0; i<iNfce; ++i)
{
INT a, b, c;
a
= pMesh->faces[i].v[0];
b
= pMesh->faces[i].v[1];
c
= pMesh->faces[i].v[2];
fprintf(fp, " %4d %4d %4d\n", a, b, c);
}
// Á¤Á¡ µ¥ÀÌÅÍ Ãâ·Â
for (i=0; i<iNvtx; ++i)
{
Point3 v =
pMesh->verts[i];
fprintf(fp, " %12.5f %12.5f %12.5f\n", v.x, v.y, v.z);
}
Àüü ÄÚµå´Â mxp13_mesh01.zipÀ» Âü°íÇϱ⠹ٶø´Ï´Ù.
5.2.4 Viewer
¿ì¸®°¡ Exporter¸¦ ¸¸µå´Â °ÍÀº °ÔÀÓ¿¡¼ ÇÊ¿äÇÑ µ¥ÀÌÅ͸¦ ¸¸µé±â
À§ÇÔÀÔ´Ï´Ù. µû¶ó¼ Áö±ÝºÎÅÍ ÃßÃâÇÑ µ¥ÀÌÅͰ¡ ¿øÇÏ´Â ÇüÅ·Π±¸¼ºµÇ¾î ÀÖ´ÂÁö ºä¾î(Viewer) ÇÁ·Î±×·¥À¸·Î È®ÀÎ ÇØ¾ß Çϰí À̸¦ À§Çؼ ÀڷᱸÁ¶°¡ ÇÊ¿äÇÕ´Ï´Ù.
ÀÌÀü¿¡ ÀÛ¼ºÇÑ Mesh¸¦ ¼öÁ¤Çؼ
View¿¡ ¿Ã¸± ¼ö ÀÖ´Â ÇüÅ·ΠÀڷᱸÁ¶¸¦ ±¸¼ºÇØ º¾½Ã´Ù.
¸ÕÀú Á¤Á¡ÀÇ À妽º¿Í À§Ä¡¸¦ ÀúÀåÇÒ ´ÙÀ½°ú °°Àº ±¸Á¶Ã¼¸¦ ¼±¾ðÇÕ´Ï´Ù.
struct VtxIdx
{
WORD a, b, c;
};
struct VtxPos
{
FLOAT x, y, z;
};
struct LcGeo
{
INT nFce; // Number of Face
INT nPos; // Number of Position
VtxIdx* pFce; // Face List
VtxPos* pPos; // Position List
};
LcMax Ŭ·¡½º¿¡ ´ÙÀ½°ú °°Àº ¸â¹ö º¯¼ö¸¦ Ãß°¡ÇÕ´Ï´Ù.
class LcMax : public SceneExport
¡¦
INT m_nGeo; // Number of Geometry
LcGeo* m_pGeo; // Geometry Data
ÀÌÀüó·³ ÆÄÀÏ¿¡ ±×³É Ãâ·ÂÀ» ÇÏ¸é ºä¾î¿¡¼ µ¥ÀÌÅ͸¦ Àоî¿À´Âµ¥ Àϰü¼ºÀÌ ¶³¾îÁö¹Ç·Î Node¸¦ ¸ðÀ¸°í ³ª¼ Geometry Data¸¦ ¸¸µé°í µ¥ÀÌÅ͸¦
ä¿î ÈÄ¿¡ ÆÄÀÏ·Î Ãâ·ÂÀ» ÇØ¾ß ÆÄÀÏ ±¸Á¶°¡ ¿Ï¼º µË´Ï´Ù. ¶ÇÇÑ
Geometry¿¡ ´ëÇÑ ÀÚ·á ±¸Á¶°¡ ¿Ï¼ºµÇ¾î ÀÖÀ¸¸é ºä¾î¿¡¼ ÅØ½ºÆ® ÆÄÀÏÀ» Àд °Íº¸´Ù ÀÌÁø(Binary)
ÆÄÀÏÀ» Àд °ÍÀÌ Æí¸®Çؼ °ÔÀÓ ¶Ç´Â ºä¾î¿¡¼´Â ÀÌÁø ÆÄÀÏÀ» »ç¿ëÇÏ°í ´«À¸·Î È®ÀÎ Çϱâ À§ÇÑ ¿ëµµ·Î´Â ÅØ½ºÆ® ÆÄÀÏÀ» »ç¿ëÇÕ´Ï´Ù. À̸¦ À§ÇØ ¸¶Áö¸·¿¡ ÀÌ µÎ Á¾·ùÀÇ ÆÄÀÏ¿¡ µ¥ÀÌÅ͸¦ ÀúÀåÇÕ´Ï´Ù.
int LcMax::DoExport(¡¦)
¡¦
// 1. Gather Node
INode* pRoot = m_pI->GetRootNode();
GatherNode(pRoot);
// 2. Create and Setup
Geometry
if(FAILED(SetupGeometry()))
return
FALSE;
// 3. Geometry¸¦ ÀÌ¿ëÇØ Binary, Text ÆÄÀÏ·Î Ãâ·Â
WriteBinary();
WriteText();
¡¦
void LcMax::WriteBinary()
¡¦
fwrite(&m_nGeo, 1, sizeof(INT), fp);
for(n =0; n<m_nGeo; ++n)
{
LcGeo* pGeo = &m_pGeo[n];
fwrite(pGeo->sName,
1, sizeof(char)*32, fp); // Node Name
fwrite(&pGeo->nType,
1, sizeof(INT ) , fp); // Node Type
fwrite(&pGeo->nFce,
1, sizeof(INT ) , fp); // Index Number
fwrite(&pGeo->nPos,
1, sizeof(INT ) , fp); // Vertex Number
¡¦
fwrite(pGeo->pFce, pGeo->nFce,
sizeof(VtxIdx), fp);
fwrite(pGeo->pPos, pGeo->nPos,
sizeof(VtxPos), fp);
}
Àüü ÄÚµå´Â mxp13_mesh02.zip¸¦ Âü°í Çϱ⠹ٶø´Ï´Ù.
´ÙÀ½À¸·Î ºä¾î¸¦ ¸¸µé¾î¾ß ÇÕ´Ï´Ù. ºä¾î¿¡¼ ÀÌÁø ÆÄÀÏÀ» Àд ¹æ¹ýÀº
void LcMax::WriteBinary()
ÇÔ¼öÀÇ fwrite() ÇÔ¼ö ´ë½Å
fread() ÇÔ¼ö·Î ¹Ù²Ù°í new ¿¬»êÀÚ·Î µ¿Àû ÇÒ´çÀ» ÇÏ¸é µË´Ï´Ù.
mxp13_viewer1.zip˼
mxp13_mesh02.zip¿¡¼ ÃßÃâÇÑ µ¥ÀÌÅ͸¦
È®ÀÎÇÏ´Â ºä¾îÀ̸ç CLcmAcm Ŭ·¡½º´Â ÀÌÁø ÆÄÀÏÀ» ÀÐ¾î¼ È¸é¿¡ Ãâ·ÂÇϴ Ŭ·¡½º ÀÔ´Ï´Ù. ÀÌ Å¬·¡½ºÀÇ LoadMdl() ÇÔ¼ö´Â ¸ðµ¨À» ÀÐ¾î ¿À´Â ÇÔ¼ö·Î LcMax::WriteBinary()¿Í ´ëÀÀÇÏ´Â ÇÔ¼öÀÔ´Ï´Ù. ÆÄÀÏ¿¡¼
µ¥ÀÌÅ͸¦ Àоî¿Ã ¶§ Geometry¿Í À妽º, ¹öÅØ½º µ¥ÀÌÅÍ´Â
new ¿¬»êÀÚ·Î µ¥ÀÌÅ͸¦ µ¿Àû ÇÒ´çÇϰí ÀÖÀ½À» ÁÖÀÇÇØ¾ß ÇÕ´Ï´Ù.
INT CLcmAcm::LoadMdl(char* sFile)
¡¦
fread(&m_nGeo, 1, sizeof(INT), fp);
¡¦
m_pGeo
= new LcGeo[m_nGeo];
for(n =0; n<m_nGeo; ++n)
{
LcGeo* pGeo =
&m_pGeo[n];
fread(&pGeo->nFce,
1, sizeof(INT) , fp);
fread(&pGeo->nPos,
1, sizeof(INT) , fp);
¡¦
pGeo->pFce
= new VtxIdx[pGeo->nFce];
pGeo->pPos = new VtxPos[pGeo->nPos];
fread(pGeo->pFce,
pGeo->nFce, sizeof(VtxIdx), fp);
fread(pGeo->pPos,
pGeo->nPos, sizeof(VtxPos), fp);
}
·»´õ¸µÀº User
Memory Pointer DrawIndexedPrimitiveUP() ÇÔ¼ö¸¦ ÀÌ¿ëÇϰí ÀÖ½À´Ï´Ù.
void CLcmAcm::Render()
¡¦
for(i=0; i<m_nGeo; ++i)
{
LcGeo* pGeo =
&m_pGeo[i];
¡¦
m_pDev->SetFVF(VtxPos::FVF);
m_pDev->DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST, 0, pGeo->nPos
,
pGeo->nFce, pGeo->pFce, (D3DFORMAT)VtxIdx::FVF
,
pGeo->pPos, sizeof(VtxPos)
);
}
mxp13_viewer1.zip¸¦ ½ÇÇàÇϰí
"_Exec/model/object.acm" À» ºÒ·¯¿À¸é ´ÙÀ½ÀÇ ¿À¸¥ÂÊ ±×¸²°ú °°ÀÌ Ãâ·ÂµË´Ï´Ù.

<¸Æ½º µ¥ÀÌÅÍ: max_object1.zip. Viewer¿¡¼ È®ÀÎÇÑ
µ¥ÀÌÅÍ: mxp13_viewer1.zip>
±×¸²À» ºñ±³ÇØ º¸¸é ¸Æ½º ȸé°ú ViewerÀÇ È¸éÀÌ Â÷À̰¡ ÀÖ½À´Ï´Ù. À̰ÍÀº ASE Parsing¿¡¼µµ À̾߱â ÇßµíÀÌ ´ÙÀ½ ±×¸²°ú °°ÀÌ ¸Æ½º´Â ¿À¸¥¼Õ ÁÂÇ¥°è¸¦ »ç¿ëÇϰí D3D´Â ¿Þ¼Õ ÁÂÇ¥°è¸¦ »ç¿ëÇϱ⠶§¹®ÀÔ´Ï´Ù.

<¸Æ½º¿Í D3D ÁÂÇ¥°è>
ASE¿¡¼´Â ÆÄÀÏÀ»
Àоî¿Ã ¶§ À§Ä¡¿¡ ´ëÇØ¼´Â y¿Í z¸¦ ±³È¯Çϰí À妽º´Â b¿Í c¸¦ ±³È¯ÇÑ´Ù°í Çß½À´Ï´Ù. À̰ÍÀ»
ÆÄÀÏÀ» ÀÐ¾î ¿Ã ¶§ ó¸®ÇÏÁö ¾Ê°í Ç÷¯±×ÀÎ ³»ºÎ¿¡¼ À妽º¿Í Á¤Á¡ µ¥ÀÌÅ͸¦ ÀúÀåÇÒ ¶§ ´ÙÀ½°ú °°ÀÌ Ã³¸®ÇÕ´Ï´Ù.
INT LcMax::SetupGeometry()
¡¦
// À妽º µ¥ÀÌÅÍ ÀúÀå
for (i=0; i<iNfce; ++i)
{
pGeo->pFce[i].a
= pMesh->faces[i].v[0];
pGeo->pFce[i].b
= pMesh->faces[i].v[2]; // b <--> c ±³È¯
pGeo->pFce[i].c
= pMesh->faces[i].v[1];
}
// Á¤Á¡ µ¥ÀÌÅÍ ÀúÀå
for (i=0; i<iNvtx; ++i)
{
Point3 v =
pMesh->verts[i];
pGeo->pPos[i].x
= v.x;
pGeo->pPos[i].y
= v.z; //y <--> z ±³È¯
pGeo->pPos[i].z = v.y;
}
µÎ ¹øÂ°·Î ºä¾î¿¡¼ È®ÀÎÇÑ ¸ðµ¨Àº ÀüºÎ (0, 0, 0)À» Áß½ÉÀ¸·Î ±×¸®°í ÀÖÀ½À» º¼ ¼ö ÀÖ½À´Ï´Ù. À̰ÍÀº
°¢°¢ÀÇ Geometry°¡ Áö¿ªÁÂÇ¥°è·Î ±×¸®±â ¶§¹®ÀÔ´Ï´Ù. ³ëµå¿¡
Àû¿ëµÈ ¿ùµå Çà·ÄÀ» ¾ò±â À§Çؼ INode ÀÎÅÍÆäÀ̽º¿¡¼ GetObjTMAfterWSM()
ÇÔ¼ö¸¦ ÀÌ¿ëÇÕ´Ï´Ù. ÀÌ ÇÔ¼ö´Â WSM(World
Space Modifier)°¡ Àû¿ëµÈ ÈÄÀÇ Transform Matrix¸¦ ¹ÝȯÇÏ´Â ÇÔ¼öÀÔ´Ï´Ù. ƯÈ÷, ¾Ö´Ï¸ÞÀ̼ÇÀÌ ÀÖ´Â °æ¿ì¿¡ ÀÌ ÇÔ¼ö¸¦ »ç¿ëÇØ¼ ¿ùµå Çà·ÄÀ»
¾ò¾î ¿É´Ï´Ù. ³ëµå¿¡ Àû¿ëµÇ´Â ¿ùµå Çà·ÄÀº ´ÙÀ½ °ø½Äó·³ ¸¸µé ¼ö ÀÖ½À´Ï´Ù.
³ëµåÀÇ ¿ùµå Çà·Ä = ³ëµåÀÇ
Áö¿ª Çà·Ä (Local Matrix) * ºÎ¸ð ³ëµåÀÇ ¿ùµå Çà·Ä
¾Ö´Ï¸ÞÀ̼ÇÀÌ ¾ø´Â µ¥ÀÌÅͶó¸é ¿ùµå Çà·Ä¸¸ °¡Áö°í Àְųª ¾Æ´Ï¸é
Á¤Á¡ÀÇ À§Ä¡¿¡ ¿ùµå Çà·ÄÀ» °öÇÑ °ªÀ» Àû¿ëÇÏ´Â °ÍÀÌ ´õ ³ªÀ» ¼ö ÀÖ½À´Ï´Ù. ÇÏÁö¸¸ ¾Ö´Ï¸ÞÀ̼ÇÀÌ ÀÖ´Ù¸é
Å©±â º¯È¯, ȸÀü º¯È¯, À̵¿ º¯È¯¿¡ ´ëÇÑ Çà·ÄÀ» °¡Áö°í
Áö¿ª Çà·ÄÀ» ¸¸µé¾î¾ß Çϱ⠶§¹®¿¡ Node¿¡ Áö¿ªÇà·ÄÀ» ÀúÀåÇÏ°í ·»´õ¸µ ÇÒ ¶§¸¶´Ù ¿ùµå Çà·ÄÀ» °è»êÇϵµ·Ï
±¸¼ºÇÏ´Â °ÍÀÌ ¾Ö´Ï¸ÞÀ̼ÇÀ» Àû¿ëÇÒ ¶§ Æí¸®ÇÕ´Ï´Ù. ³ëµåÀÇ Áö¿ª Çà·ÄÀº ÀÌÀüÀÇ ½Ä ¾çº¯¿¡ ºÎ¸ð ³ëµåÀÇ
¿ùµå Çà·ÄÀÇ ¿ªÇà·ÄÀ» °öÇÏ¸é ´ÙÀ½°ú °°ÀÌ ±¸ÇØÁý´Ï´Ù.
³ëµåÀÇ Áö¿ª Çà·Ä = ³ëµåÀÇ
¿ùµå Çà·Ä * ºÎ¸ð ³ëµåÀÇ ¿ùµå Çà·ÄÀÇ ¿ªÇà·Ä
ºÎ¸ð ³ëµå¿¡ ´ëÇÑ À妽º¸¦ Æ÷ÇÔ ½ÃÄÑ µ¥ÀÌÅͰ¡ ³ª¹« ±¸Á¶(Tree Struct)ÀÇ °èÃþÀû(Hierarchy)À¸·Î ±¸¼º µÇµµ·Ï
´ÙÀ½°ú °°ÀÌ LcGeo ±¸Á¶Ã¼¿¡ ºÎ¸ð ³ëµåÀÇ À妽º¸¦ Ãß°¡ÇÏ°í ¶ÇÇÑ ÀÚ½ÅÀÇ Áö¿ª Çà·Äµµ Ãß°¡ÇÕ´Ï´Ù.
struct LcGeo
¡¦
INT nPrn; // Parent Index
D3DXMATRIX mtLcl; // Local Matrix
LcGeo()
¡¦
nPrn =
-1; // ºÎ¸ð°¡ ¾øÀ½
D3DXMatrixIdentity(&mtLcl); // Áö¿ªÇà·ÄÀ» ´ÜÀ§ Çà·Ä·Î
¸¸µç´Ù.
}
¡¦
LcMax::SetupGeometry() ÇÔ¼ö¸¦ ¼öÁ¤Çؼ ´ÙÀ½°ú °°ÀÌ
ºÎ¸ð ³ëµå¿¡ ´ëÇÑ À妽º¸¦ ¼³Á¤ÇÕ´Ï´Ù.
// Setup Parent Index
for(n =0; n<m_nGeo; ++n)
{
LcGeo* pGeo =
&m_pGeo[n];
INode* pNode =
m_vMaxNode[n];
INode* pPrn =
pNode->GetParentNode();
// ºÎ¸ðÀÇ ³ëµå¸¦ ã¾Æ À妽º¸¦
¼³Á¤
if(pPrn)
{
for(i=0; i<m_nGeo; ++i)
{
INode* pCur =
m_vMaxNode[i];
if(pCur == pPrn
&& i != n )
{
pGeo->nPrn
= i;
break;
}
}
}
}
¶ÇÇÑ Áö¿ªÇà·Äµµ ´ÙÀ½°ú °°ÀÌ °è»êÇØ¼ ÀúÀåÇÕ´Ï´Ù.
// Setup Local Matrix
for(n =0; n<m_nGeo; ++n)
{
LcGeo* pGeo =
&m_pGeo[n];
INode* pNode =
m_vMaxNode[n];
INode* pPrnt =
pNode->GetParentNode();
Matrix3 tmLocal;
Matrix3 tmWorld =
pNode->GetObjTMAfterWSM(0);
if(!pPrnt)
tmLocal
= tmWorld;
else
{
Matrix3 tmParent=
pPrnt->GetObjTMAfterWSM(0);
tmLocal
= tmWorld * Inverse(tmParent);
}
MaxMatrixToD3D(&pGeo->mtLcl,
&tmLocal);
}
Inverse() ÇÔ¼ö´Â ¸Æ½º
SDK¿¡¼ Á¦°øÇÏ´Â ¿ªÇà·ÄÀ» ±¸ÇÏ´Â ÇÔ¼öÀÔ´Ï´Ù. MaxMatrixToD3D()´Â ¸Æ½ºÀÇ
Çà·ÄÀ» D3D¿¡ ¸Â°Ô ÀÚ¸® ±³È¯À» ÇÏ´Â ÇÔ¼öÀÔ´Ï´Ù. À̰ÍÀº ASE Parsing¿¡¼µµ ÇßµíÀÌ ¸Æ½ºÀÇ Çà·ÄÀÇ 2,3 ÇàÀ» ±³È¯Çϰí
2, 3¿ ±³È¯Çϸé D3D¿¡¼ »ç¿ëÇÏ´Â Çà·Ä·Î ¸¸µé¾î Áý´Ï´Ù.
void LcMax::MaxMatrixToD3D(D3DXMATRIX* pDst, Matrix3* pSrc, BOOL bIdentity)
{
Point3 v3;
v3
= pSrc->GetRow(0);
pDst->_11 = v3.x; pDst->_12 = v3.z; pDst->_13
= v3.y;
v3
= pSrc->GetRow(2);
pDst->_21 = v3.x; pDst->_22 = v3.z; pDst->_23
= v3.y;
v3
= pSrc->GetRow(1);
pDst->_31 = v3.x; pDst->_32 = v3.z; pDst->_33
= v3.y;
v3
= pSrc->GetRow(3);
pDst->_41 = v3.x; pDst->_42 = v3.z; pDst->_43
= v3.y;
¡¦
}
ºÎ¸ð ³ëµåÀÇ À妽º¿Í Áö¿ªÇà·ÄÀ» ÀúÀåÇÒ ¼ö ÀÖµµ·Ï LcMax:: WriteBinary()
ÇÔ¼ö¿Í LcMax:: WriteText() ÇÔ¼ö¸¦ ¼öÁ¤ÇÕ´Ï´Ù.
void LcMax::WriteBinary()
¡¦
for(n =0; n<m_nGeo; ++n)
{
LcGeo* pGeo =
&m_pGeo[n];
¡¦
fwrite(&pGeo->nPrn,
1, sizeof(INT ), fp); // Parent Index
fwrite(&pGeo->mtLcl,
1, sizeof(D3DXMATRIX),fp); // Local Matrix
}
Àüü ÄÚµå´Â mxp14_transform.zip¸¦
Âü°í Çϱ⠹ٶø´Ï´Ù.
Ç÷¯±×Àο¡¼´Â Áö¿ª Çà·Ä¸¸ °¡Áö°í ÀÖÁö¸¸ Viewer¿¡¼´Â ¿ùµå Çà·Äµµ
°¡Áö°í ÀÖ¾î¾ß ÇÏÀ§ ³ëµå¿¡¼ °è»êÀÌ µË´Ï´Ù. µû¶ó¼ ºÎ¸ð À妽º, Áö¿ª
Çà·Ä°ú ¿ùµå Çà·ÄÀÌ ÀÖ¾î¾ß ÇÕ´Ï´Ù. ¶ÇÇÑ ¸Å ¹ø ºÎ¸ð ³ëµå¸¦ ã°Ô µÇ¸é ºÒÆíÇϹǷΠÆÄÀÏ¿¡¼ Àоî¿Ã ¶§
ºÎ¸ð ³ëµå¸¦ ÁöÁ¤ÇÒ ¼ö ÀÖµµ·Ï ºÎ¸ðÀÇ Æ÷ÀÎÅ͸¦ Ãß°¡ÇÕ´Ï´Ù.
struct LcGeo
¡¦
INT nPrn; // Parent Index
LcGeo* pPrn; // Parent Node
D3DXMATRIX mtLcl; // Local Matrix
D3DXMATRIX mtWld; // World Matrix
ÆÄÀÏÀ» Àд ÇÔ¼öµµ ¼öÁ¤ÇÕ´Ï´Ù.
INT CLcmAcm::LoadMdl(char* sFile)
¡¦
for(n =0; n<m_nGeo; ++n)
{
LcGeo* pGeo =
&m_pGeo[n];
¡¦
fread(&pGeo->nPrn,
1, sizeof(INT ), fp); // Parent Index
fread(&pGeo->mtLcl,
1, sizeof(D3DXMATRIX),fp); // Local Matrix
// ºÎ¸ð ³ëµå ÁöÁ¤
if(-1 != pGeo->nPrn)
pGeo->pPrn
= &m_pGeo[pGeo->nPrn];
¾Ö´Ï¸ÞÀ̼ÇÀÌ ÀÖ´Ù´Â ÀüÁ¦ÇÏ¿¡ ¸Å ÇÁ·¹ÀÓ ¸¶´Ù Çà·ÄÀ» °»½ÅÇÒ ¼ö ÀÖµµ·Ï ´ÙÀ½°ú °°ÀÌ CLcmAcm::FrameMove() ÇÔ¼ö¸¦ ¼öÁ¤ÇÕ´Ï´Ù. °¢°¢ÀÇ GeometryÀÇ ¿ùµå Çà·ÄÀº ´ÙÀ½°ú °°Àº °ø½ÄÀ» ÀÌ¿ëÇØ¼ ±¸ÇöÇÕ´Ï´Ù.
³ëµåÀÇ ¿ùµå Çà·Ä = ³ëµåÀÇ
Áö¿ª Çà·Ä (Local Matrix) * ºÎ¸ð ³ëµåÀÇ ¿ùµå Çà·Ä
¸¸¾à ºÎ¸ð ³ëµå°¡ ¾øÀ¸¸é ÀÚ½ÅÀÇ Áö¿ª Çà·ÄÀ» ¿ùµå Çà·Ä·Î ¼³Á¤ÇÕ´Ï´Ù.
INT CLcmAcm::FrameMove()
¡¦
for(i=0; i<m_nGeo; ++i)
{
LcGeo* pCur =
&m_pGeo[i];
LcGeo* pPrn =
pCur->pPrn;
if(pPrn)
pCur->mtWld
= pCur->mtLcl * pPrn->mtWld;
else
pCur->mtWld
= pCur->mtLcl;
}
Çà·ÄÀÌ Æ÷ÇÔ µÇ¾î ÀÖÀ¸¹Ç·Î °¢°¢ÀÇ Geometry¿¡ ´ëÇØ¼ ¿ùµå Çà·ÄÀ»
¼³Á¤ÇØ¾ß ÇÕ´Ï´Ù.
void CLcmAcm::Render()
¡¦
for(i=0; i<m_nGeo; ++i)
{
LcGeo* pGeo =
&m_pGeo[i];
¡¦
m_pDev->SetTransform(D3DTS_WORLD,
&pGeo->mtWld);
m_pDev->DrawIndexedPrimitiveUP(¡¦);
¡¦
m_pDev->SetTransform(D3DTS_WORLD,
&mtI); // ¿ùµå Çà·Ä º¹±Í
Àüü ÄÚµå´Â mxp14_viewer2.zip¸¦
½ÇÇàÇÏ¸é ´ÙÀ½°ú °°Àº ȸéÀ» º¼ ¼ö ÀÖ½À´Ï´Ù.

<¿ùµå Çà·ÄÀÌ Àû¿ëµÈ
Export µ¥ÀÌÅÍ: max_object2_rigid.zip,
mxp14_viewer2.zip>
5.3 Animation
Á¤Á¡ÀÇ À§Ä¡¿¡ ´ëÇÑ º¯È¸¦ ½Ã°£ÀÇ ¼ø¼´ë·Î ¸¸µç °ÍÀÌ ¾Ö´Ï¸ÞÀ̼ÇÀÔ´Ï´Ù. ¾Ö´Ï¸ÞÀ̼ÇÀº
Á¤Á¡ÀÇ À§Ä¡ ÀÚü¸¦ º¯È¯ÇÏ´Â ¹æ¹ýÀÌ ÀÖÀ» ¼ö ÀÖ°í, Á¤Á¡¿¡ ¿µÇâÀ» ÁÖ´Â ¿ùµå Çà·Ä¸¸ ½Ã°£¿¡ µû¶ó º¯È¯½Ã۰í
³ ´ÙÀ½¿¡ À̰ÍÀ» ÆÄÀÌÇÁ¶óÀο¡ Àû¿ëÇÏ´Â ¹æ¹ýÀÌ ÀÖÀ» ¼ö ÀÖ½À´Ï´Ù. Á» ´õ ³ªÀº ¹æ¹ýÀº ¹Ì¸® °èÃþ ±¸Á¶¸¦
¸¸µé¾î ³õ°í ÀÌ °èÃþ ±¸Á¶ÀÇ Çà·ÄÀ» º¯È¯ÇÑ ´ÙÀ½¿¡ Á¤Á¡¿¡ Àû¿ëÇÏ´Â ¹æ¹ýÀÌ ÀÖ½À´Ï´Ù.
3D ¸Æ½º´Â ¿ÀºêÁ§Æ®¿¡ ¾Ö´Ï¸ÞÀ̼ÇÀ» Æí¸®ÇÏ°Ô Àû¿ëÇÒ ¼ö ÀÖ°Ô Bone°ú Biped¸¦ Áö¿øÇÏ¸ç ´ëºÎºÐÀÇ ±×·¡ÇÈ ÀÛ¾÷Àº ÀÌ µÑÀ» ÀÌ¿ëÇØ¼
¾Ö´Ï¸ÞÀ̼ÇÀ» ±¸ÇöÇÕ´Ï´Ù.
BoneÀº ±× ¾ð¾î ÀÚü·Î »À´ëÀÌ¸ç ¿©·¯ »À´ë¸¦ °èÃþ ±¸Á¶(Hierarchy) °áÇÕÇÏ°í »ç¿ëÀÚ´Â °áÇÕµÈ BoneÀ» ȸÀü, À̵¿ µîÀ» Àû¿ëÇØ¼ ¾Ö´Ï¸ÞÀ̼ÇÀ» ±¸ÇöÇÕ´Ï´Ù. ¸Æ½º´Â BoneÀ» Á» ´õ Æí¸®ÇÏ°Ô »ç¿ëÇϰíÀÚ BoneÀ» ƯÈÇÑ Biped¸¦ Áö¿øÇÕ´Ï´Ù.

<¸Æ½ºÀÇ Bone°ú Biped>
BoneÀº »ç¿ëÀÚ°¡ ÀÚÀ¯·Ó°Ô °èÃþ ±¸Á¶¸¦ ¸¸µé ¼ö ÀÖ¾î¼ ¼÷·ÃµÈ ¾Ö´Ï¸ÞÀÌÅÍ(Animator)´Â ÃÖ¼ÒÇÑÀÇ BoneÀ¸·Î ´Ù¾çÇÑ µ¿ÀÛÀ» ¸¸µé¾î ³¾
¼ö ÀÖ½À´Ï´Ù. Biped´Â ±Ô°ÝÈ µÇ¾î ¾Ö´Ï¸ÞÀÌ¼Ç Á¦ÀÛÀÌ Æí¸®Çϰí ÀϰüµÈ ÀÛ¾÷À» À¯µµÇؼ °øµ¿ ÀÛ¾÷¿¡
À¯¸®ÇÕ´Ï´Ù. ¾Ö´Ï¸ÞÀ̼ÇÀÌ ¸¹°í º¹ÀâÇÑ Ä³¸¯ÅÍ ¸ðµ¨ÀÇ °æ¿ì Biped¸¦
±âº»À¸·Î Çϰí ÇÊ¿äÇÏ´Ù¸é BoneÀ» Ãß°¡ ½ÃÄÑ ¾Ö´Ï¸ÞÀ̼ÇÀ» ÀÛ¾÷À» ÇÕ´Ï´Ù. ³ª¹«³ª Ç®°ú °°Àº °üÀýÀÌ °£´ÜÇÑ °æ¿ì¶ó¸é BoneÀ¸·Î ÀÛ¾÷À» ¸¹ÀÌ
ÇÕ´Ï´Ù.
±×·¡ÇÈ ÀÛ¾÷ÀÚ´Â ¸Æ½º·Î Biped ¶Ç´Â BoneÀ¸·Î ¾Ö´Ï¸ÞÀ̼ÇÀ» ¸¸µì´Ï´Ù. ±×¸®°í ¹Ì¸® ¸¸µé¾î ³õÀº 3D ¸ðµ¨ µ¥ÀÌÅ͸¦ À̵é Biped/Bone¿¡ ¿¬°áÇÏ´Â ¸®±ë(Rigging) ÀÛ¾÷À» ÇÕ´Ï´Ù. ÀÌ ¸®±ë ÀÛ¾÷Àº PHYSIQUE¿Í SKIN µÎ Á¾·ù°¡ ÀÖ½À´Ï´Ù. ÀÛ¾÷ÀÇ ¹æ¹ýÀº Â÷À̰¡ ÀÖÁö¸¸ PHYSIQUE/SKIN ´Â Á¤Á¡¿¡
¿µÇâÀ» ÁÖ´Â BoneÀ» ¼³Á¤ÇÏ´Â ÀÏÀ̸ç À̰ÍÀº D3DÀÇ ½ºÅ°´×
¾Ö´Ï¸ÞÀÌ¼Ç ±¸ÇöÀ̶ó ÇÒ ¼ö ÀÖ½À´Ï´Ù.
¸Æ½º¿¡¼ÀÇ ÀÛ¾÷ÀÌ Á¤Á¡¿¡ ´ëÇØ¼ ÇϳªÀÇ Bone¿¡¸¸ ¿µÇâ ¹Þµµ·Ï µÇ¾î
ÀÖ´Ù¸é °Ã¼(Rigid) ¾Ö´Ï¸ÞÀ̼ÇÀ» ¹ÙÅÁÀ¸·Î Ç÷¯±×ÀÎÀ» ±¸¼ºÇØ¾ß Çϰí, ¿©·¯ Bone¿¡ ¿µÇâ ¹ÞÀ¸¸é ½ºÅ°´× ¾Ö´Ï¸ÞÀ̼ÇÀ¸·Î Ç÷¯±×ÀÎÀ» ¸¸µé¾î¾ß
ÇÕ´Ï´Ù.
¾Ö´Ï¸ÞÀ̼ǿ¡ ´ëÇÑ Ç÷¯±×ÀÎÀº ±¸ÇöÇϱ⠽¬¿î °Ã¼ ¾Ö´Ï¸ÞÀ̼ÇÀ» ¸ÕÀú ¸¸µé°í ´ÙÀ½À¸·Î ½ºÅ°´×¿¡ ´ëÇØ¼ ¸¸µé¾î º¸°Ú½À´Ï´Ù.
5.3.1 Rigid Body
Animation
°Ã¼ ¾Ö´Ï¸ÞÀ̼Ç(Rigid Body Animation)¿¡ ´ëÇÑ Ç÷¯±×ÀÎ
Á¦ÀÛÀº ÀǿܷΠ°£´ÜÇÕ´Ï´Ù. Ç÷¯±×ÀÎ Á¦ÀÛ ¼ø¼´Â ¸ÕÀú ½Ã°£ Á¤º¸¸¦ ¾ò½À´Ï´Ù. ´ÙÀ½À¸·Î BoneÀÇ °èÃþ ±¸Á¶¿Í ¸Þ½¬¸¦ ÀúÀåÇÏ°í ¸¶Áö¸·¿¡ ½Ã°£¿¡
´ëÇÑ ¿ùµå Çà·Ä ¶Ç´Â Áö¿ª Çà·ÄÀ» ÃßÃâÇÏ¸é µË´Ï´Ù.
¸ÕÀú ½Ã°£ÀÇ Á¤º¸¸¦ ÀúÀåÇϱâ À§ÇØ ´ÙÀ½°ú °°Àº ±¸Á¶Ã¼¸¦ ¸¸µì´Ï´Ù.
struct LcHeader
{
INT nFrmB; // Begin Frame
INT nFrmE; // End Frame
INT nFrmP; // Frame Rate(FPS)
INT nFrmT; // Tick Frame
INT nGeo; // Number of Geometry
};
ÀÌÀü¿¡´Â Geometry °³¼ö¸¦ ¸â¹ö·Î °¡Á®°¬´Âµ¥ ÇÁ·Î±×·¥ÀÇ Æí¸®¼ºÀ»
À§ÇØ LcHeader¿¡ Æ÷ÇÔ½ÃÄ×½À´Ï´Ù.
½Ã°£ Á¤º¸´Â ´ÙÀ½°ú °°ÀÌ ±¸Çö ÇÕ´Ï´Ù. ÀÌ ¹æ¹ýÀº ase Ç÷¯±×ÀÎ ¿¹Á¦¿Íµµ ºñ½ÁÇÕ´Ï´Ù.
int
iTick = GetTicksPerFrame();
Interval range = m_pI->GetAnimRange();
m_Header.nFrmB
= range.Start() / iTick;
m_Header.nFrmE
= range.End() / iTick;
m_Header.nFrmP
= GetFrameRate();
m_Header.nFrmT = iTick;
ÇÁ·Î±×·¥À» Æí¸®ÇÏ°Ô ÀÛ¼ºÇϱâ À§ÇØ LcGeo¸¦ ´ÙÀ½°ú °°ÀÌ ¼öÁ¤ÇÕ´Ï´Ù.
struct LcGeo
{
char sName[32]; // Node Name
INT nType; // 1:Geometry, 2: Bone, 0: Etc
INode* pNode; // Node
INT nPrn; // Parent Index
D3DXMATRIX mtLcl; // Local Matrix
INT nFce; // Number of Face
INT nPos; // Number of Position
VtxIdx* pFce; // Face List
VtxPos* pPos; // Position List
INT nAni; // Number of Animation
D3DXMATRIX* pAni; // Animation Matrix
};
ÀÌ ±¸Á¶Ã¼¸¦ ÀÌ¿ëÇØ¼ ³ëµå¸¦ ¸ðÀ¸°í °èÃþ ±¸Á¶ÀÇ Node¸¦ STLÀ» ÀÌ¿ëÇØ¼ ¹è¿·Î ±¸¼ºÇÕ´Ï´Ù. ÀÌ ºÎºÐÀº ÀÌÀü Àå¿¡¼ ¼³¸íÇßÀ¸¹Ç·Î
»ý·«ÇϰڽÀ´Ï´Ù.
¸Æ½º´Â »ç¿ëÀÚ°¡ ¹Ù²ÙÁö ¾Ê´Â ÇÑ Default·Î Bone¿¡ ´ëÇØ¼ "Bone"À̶ó´Â Ű¿öµå°¡ Biped´Â "Bip" Ű¿öµå°¡ ¿ÀºêÁ§Æ®ÀÇ À̸§¿¡
Àû¿ëµÇ¾î ´ÙÀ½°ú °°ÀÌ BoneÀÎÁö ÆÇ´ÜÇÏ´Â ÇÔ¼ö ¾È¿¡ ±¸Çö ÇÕ´Ï´Ù.
void LcMax::SetupIsBone(LcGeo* pGeo)
¡¦
if( 0 == _strnicmp(pNode->GetName(), "Bone", 4) ||
0 == _strnicmp(pNode->GetName(), "Bip", 3))
pGeo->nType
= LCX_BONE;
¡¦
´ÙÀ½À¸·Î Áö¿ª Çà·Ä, ¸Þ½¬ Á¤º¸¸¦ ÃßÃâÇÏ°í ¸¶Áö¸· ´Ü°è¿¡¼ ´ÙÀ½°ú
°°ÀÌ ¾Ö´Ï¸ÞÀ̼ǿ¡ ´ëÇÑ Çà·ÄÀ» ÃßÃâÇÕ´Ï´Ù.
typedef D3DXMATRIX MATA;
void LcMax::SetupAnimation(LcGeo* pGeo)
¡¦
nAni
= m_Header.nFrmE - m_Header.nFrmB +1;
INode* pNode =
pGeo->pNode;
INode* pPrnt =
pNode->GetParentNode();
pGeo->nAni =
nAni;
pGeo->pAni =
new MATA[nAni];
dTime
= dTimeB;
i =
0;
for(; dTime<=dTimeE ;
dTime += dTick, ++i)
{
MATA* pDest =
&pGeo->pAni[i];
Matrix3 tmLocal;
Matrix3 tmWorld =
pNode->GetObjTMAfterWSM(dTime);
if(!pPrnt)
tmLocal
= tmWorld;
else
{
Matrix3 tmParent=
pPrnt->GetObjTMAfterWSM(dTime);
tmLocal
= tmWorld * Inverse(tmParent);
}
MaxMatrixToD3D(pDest,
&tmLocal);
}
¾Ö´Ï¸ÞÀ̼ǿ¡ ´ëÇÑ Áö¿ª Çà·ÄÀº ÀÌÀüÀÇ transform ¿¹Á¦Ã³·³ ´ÙÀ½
°ø½ÄÀ» ÀÌ¿ëÇÕ´Ï´Ù.
¾Ö´Ï¸ÞÀÌ¼Ç Áö¿ª Çà·Ä = ³ëµåÀÇ ¾Ö´Ï¸ÞÀÌ¼Ç ¿ùµå Çà·Ä * ºÎ¸ð ¾Ö´Ï¸ÞÀÌ¼Ç ¿ùµå Çà·ÄÀÇ ¿ªÇà·Ä
GetObjTMAfterWSM() ÇÔ¼ö´Â ÁÖ¾îÁø ½Ã°£¿¡¼ Modifier¿¡ ÀÇÇÑ ¿ùµå Çà·ÄÀ» ¹Ýȯ ÇϹǷΠÀ̸¦ ÀÌ¿ëÇØ¼ °¢ ³ëµåÀÇ ¿ùµå Çà·ÄÀ» ±¸ÇÑ ÈÄ¿¡ °ø½Ä¿¡ Àû¿ëÇØ¼
½Ã°£¿¡ ´ëÇÑ Áö¿ª Çà·ÄÀ» ¸¸µé¾î ³À´Ï´Ù.
ÆÄÀÏ¿¡ ÀúÀåÇÒ ¶§´Â ¾Ö´Ï¸ÞÀÌ¼Ç Á¤º¸´Â ¸Þ½¬ Á¤º¸¸¦ ÀúÀåÇÑ ´ÙÀ½¿¡ ÀúÀåÇÕ´Ï´Ù.
void LcMax::WriteBinary()
// Write Geometry
¡¦
// Write Animation
for(n =0; n<m_Header.nGeo;
++n)
{
LcGeo* pGeo =
&m_pGeo[n];
if(1>pGeo->nAni)
continue;
fwrite(pGeo->pAni,
pGeo->nAni, sizeof(MATA), fp); //
Animation Matrix
}
Àüü ÄÚµå´Â mxp21_ani_rigid1.zipÀ»
Âü°í Çϱ⠹ٶø´Ï´Ù.
ÀÌ·¸°Ô ¸¸µç µ¥ÀÌÅ͸¦ °ÔÀÓ¿¡ Àû¿ëÇÏ·Á¸é ¸ÕÀú ¾Ö´Ï¸ÞÀÌ¼Ç Çà·ÄÀÇ À妽º¸¦ ±¸ÇØ¾ß ÇÕ´Ï´Ù. ÀÌ À妽º´Â ½Ã°£À» FrameÀ¸·Î ³ª´©°í ´Ù½Ã Àüü ÇÁ·¹ÀÓÀ¸·Î Modular ¿¬»êÀÚ(%)¸¦ ÀÌ¿ëÇϸé ÃÖ´ë ÇÁ·¹ÀÓÀ» ³ÑÁö ¾Ê°í ¹Ýº¹µÈ
¾Ö´Ï¸ÞÀ̼ÇÀ» ±¸ÇöÇÒ ¼ö ÀÖ½À´Ï´Ù.
m_nAni = INT(
dTime/m_Header.nFrmP);
m_nAni %= m_Header.nFrmE;
Ç÷¯±×ÀÎÀ¸·Î ÃßÃâÇÑ ¾Ö´Ï¸ÞÀÌ¼Ç Çà·ÄÀº ¾Ö´Ï¸ÞÀÌ¼Ç Áö¿ª Çà·ÄÀ̹ǷΠ´ÙÀ½ °ø½Ä°ú °°ÀÌ ¾Ö´Ï¸ÞÀ̼ǿ¡ ´ëÇÑ ¿ùµå Çà·ÄÀ»
±¸ÇÕ´Ï´Ù.
³ëµåÀÇ ¾Ö´Ï¸ÞÀÌ¼Ç ¿ùµå Çà·Ä = ³ëµåÀÇ ¾Ö´Ï¸ÞÀÌ¼Ç Áö¿ª Çà·Ä * ºÎ¸ðÀÇ ¾Ö´Ï¸ÞÀÌ¼Ç ¿ùµå Çà·Ä
À̰ÍÀº ÀÌÀüÀÇ transform ¿¹Á¦¿Í °ÅÀÇ °°À¸¸ç mxp21_viewer_rigid1.zipÀº
´ÙÀ½°ú °°ÀÌ ÀÌ °ø½ÄÀ» ±¸ÇöÇϰí ÀÖ½À´Ï´Ù.
INT CLcmAcm::FrameMove()
¡¦
m_TimeC
= GetTickCount();
DWORD dTime = m_TimeC -
m_TimeB;
m_nAni
= INT(
dTime/m_Header.nFrmP);
m_nAni
%= m_Header.nFrmE;
for(i=0; i<m_Header.nGeo;
++i)
{
LcGeo* pCur =
&m_pGeo[i];
LcGeo* pPrn =
pCur->pPrn;
D3DXMatrixIdentity(&pCur->mtWld);
if(pPrn)
{
if(pCur->pAni)
pCur->mtWld
= pCur->pAni[m_nAni]* pPrn->mtWld;
else
pCur->mtWld
= pCur->mtLcl * pPrn->mtWld;
}
else
pCur->mtWld
= m_mtWld;
}
mxp21_viewer_rigid1.zip¸¦
½ÇÇàÇÏ¸é ´ÙÀ½°ú °°Àº ȸéÀ» ¾òÀ» ¼ö ÀÖ½À´Ï´Ù.

<°Ã¼ ¾Ö´Ï¸ÞÀ̼Ç: mxp21_viewer_rigid1.zip>
5.3.2 Skinning
Animation Ç÷¯±×ÀÎ
½ºÅ°´× ¾Ö´Ï¸ÞÀ̼ǿ¡ ´ëÇÑ Ç÷¯±×ÀÎ Á¦ÀÛÀº ±ÛÀ» ¾²°í ÀÖ´Â Àúµµ ¸¹Àº ÁÂÀýÀ» °Þ¾ú´ø ºÎºÐÀÔ´Ï´Ù. ´ÙÇàÈ÷µµ Game Programming Gems 2 ±Ç 1.21 Àå "½ºÅ² ÀͽºÆ÷ÅÍ" ºÎºÐ¿¡¼ Physique¿¡¼ Á¤Á¡¿¡ ´ëÇÑ BoneÀÇ ºñÁß(Weight)°ú À妽º¸¦ ±¸ÇÏ´Â ¹æ¹ýÀÌ ¼Ò°³µÇ¾î ÀÖ°í, À̰ÍÀ» ¿¬±¸Çؼ Physique¿Í SKIN µÎ ºÎºÐ ¸ðµÎ¿¡ ´ëÇÑ Ç÷¯±×ÀÎÀ» ÀÛ¼ºÇÒ ¼ö ÀÖ¾ú½À´Ï´Ù.
¸¸¾à PHYSIQUE/SKIN ÀÌ Àû¿ëµÈ Ç÷¯±×ÀÎÀ» Á¦ÀÛÇÑ´Ù¸é Á¦ÀÏ
¸ÕÀú Á¤Á¡ÀÇ À§Ä¡¸¦ ÃßÃâÇÏ´Â ºÎºÐÀ» ´ÙÀ½°ú °°ÀÌ ¼öÁ¤ÇØ¾ß ÇÕ´Ï´Ù.
Matrix3 tmWSM = pNode->GetObjTMAfterWSM(0);
// ¶Ç´Â
tmWSM = pNode->GetObjectTM(0);
¡¦
for (n=0; n<iNvtx; ++n)
{
Point3 v = tmWSM * pMesh->verts[n]; // º¯È¯µÈ Á¤Á¡À» »ç¿ë
pGeo->pPos[n].x
= v.x;
pGeo->pPos[n].y
= v.z;
pGeo->pPos[n].z
= v.y;
}
ÀÌÀüÀÇ °Ã¼ ¾Ö´Ï¸ÞÀ̼ǿ¡¼´Â º¯È¯ÇÏÁö ¾ÊÀº Á¤Á¡À» »ç¿ëÇßÀ¸³ª ½ºÅ°´×ÀÌ Àû¿ëµÇ´Â Á¤Á¡Àº ½ÃÀÛ ½Ã°£ (Zero Time)ÀÇ Çà·ÄÀ» Àû¿ëÇØ¼ »ç¿ëÇÕ´Ï´Ù. À̰ÍÀº ¸®±ë ÀÛ¾÷¿¡
ÀÇÇØ º¯È¯µÈ ¸ðµ¨¸µ µ¥ÀÌÅÍÀÇ Á¤Á¡À» »ç¿ëÇÏ´Â °ÍÀ» ÀǹÌÇÕ´Ï´Ù.
PHYSIQUE/SKIN ¿¡¼
BoneÀÇ À妽º¿Í ºñÁßÀ» ±¸ÇÏ´Â ¹æ¹ýÀ» °£´ÜÈ÷ ¼³¸íÇϸé ù ¹øÂ°·Î PHYSIQUE/SKIN¿¡
´ëÇÑ ¼öÁ¤ÀÚ(Modifier) ã°í, ±× ´ÙÀ½À¸·Î ¼öÁ¤ÀÚ¿¡¼ PHYSIQUE/SKIN °´Ã¼¸¦ ¾ò´Â °ÍÀÔ´Ï´Ù. ¼¼ ¹øÂ°·Î PHYSIQUE/SKIN °´Ã¼¿¡¼ ¹®¸Æ(Context)¸¦ ¾ò°í ÀÌ
¹®¸Æ¿¡¼ ¿µÇâ ¹Þ´Â Á¤Á¡ÀÇ ¼ö¸¦ ±¸Çϰí ÀÌ ¼ö¸¸Å Loop¸¦ µ¹¸é¼ ÀÌ ¹®¸Æ¿¡ ¿¬°áµÈ Á¤Á¡À» ¾ò°í ÀÌ
Á¤Á¡¿¡ ¿¬°áµÈ ³ëµå¿Í ºñÁßÀ» ±¸ÇÕ´Ï´Ù.
¼öÁ¤ÀÚÀÇ ¿ªÇÒÀº °´Ã¼ÀÇ º¯È¯ÀÌ¸ç ¿©·¯ ¼öÁ¤ÀÚµéÀÌ °´Ã¼¿¡ Àû¿ëÀÌ µÇ¾î Àå¸é¿¡ ´ëÇØ¼ °´Ã¼ÀÇ ÃÖÁ¾ÀûÀÎ °á°ú¹°(¿ÜÇü)À» ¸¸µé¾î³À´Ï´Ù. ÀÌ·¯ÇÑ
ÀÌÀ¯·Î ¼öÁ¤Àڵ鿡 ÀÇÇÑ °´Ã¼ÀÇ º¯È¯ °úÁ¤À» °´Ã¼ÀÇ ÆÄÀÌÇÁ¶óÀÎÀ̶ó ºÎ¸£±âµµ ÇÕ´Ï´Ù. °¢°¢ÀÇ ³ëµå´Â ¼öÁ¤Àڵ鿡
ÀÇÇØ º¯È¯µÈ ÃÖÁ¾ °´Ã¼(Derived Object)°¡ ¿¬°áµÇ¾î ÀÖ°í ÀÌ ÃÖÁ¾ °´Ã¼´Â ¸Æ½ºÀÇ ¼öÁ¤ÀÚ ½ºÅÃ
½Ã½ºÅÛÀÌ Àû¿ëµÈ °á°ú ÀÔ´Ï´Ù.
¿ì¸®´Â ÀÌ ¼öÁ¤ÀÚ ½ºÅÃÀ» Ž»öÇÏ¸é¼ ´ÙÀ½°ú °°ÀÌ ¼öÁ¤ÀÚ(Modifier)¸¦
ãÀ¸¸é µË´Ï´Ù.
void* LcMax::FindModifier(INode *pNode, Class_ID nType)
{
// ³ëµå¿¡ ¿¬°áµÈ ¿ÀºêÁ§Æ®¸¦
±¸ÇÑ´Ù.
Object* ObjectPtr =
pNode->GetObjectRef();
if(!ObjectPtr)
return NULL;
// Derived ¿ÀºêÁ§Æ®¶ó¸é
ÀÌ ¿ÀºêÁ§Æ®¿¡¼ ¼öÁ¤ÀÚ¸¦ ã´Â´Ù.
while(ObjectPtr
&& ObjectPtr->SuperClassID() == GEN_DERIVOB_CLASS_ID)
{
IDerivedObject
*pDerivedObj = (IDerivedObject *)ObjectPtr;
// ¼öÁ¤ÀÚ ½ºÅÃÀ» ÀüºÎ Ž»öÇÑ´Ù.
int ModStackIndex = 0;
while(ModStackIndex <
pDerivedObj->NumModifiers())
{
// ½ºÅà À妽º¿¡ ´ëÇÑ ¼öÁ¤ÀÚ¸¦
¾ò´Â´Ù.
Modifier* ModifierPtr =
pDerivedObj->GetModifier(ModStackIndex);
//ÀÌ ¼öÁ¤ÀÚÀÇ ¾ÆÀ̵𰡠PHYSIQUE ¶Ç´Â SKINÀÎÁö ºñ±³ÇÑ´Ù.
if(nType ==
ModifierPtr->ClassID())
return ModifierPtr;
// ¼öÁ¤ÀÚ°¡ PHYSIQUE ¶Ç´Â SKINÀÌ ¾Æ´Ï¸é À妽º¸¦ ¿Ã¸°´Ù.
ModStackIndex++;
}
// Derived ¿ÀºêÁ§Æ®¿¡
¿¬°áµÈ ´Ù¸¥ ¿ÀºêÁ§Æ®¸¦ ¾ò´Â´Ù.
ObjectPtr
= pDerivedObj->GetObjRef();
}
// ¹ß°ß ¸øÇÔ.
return NULL;
}
Derived °´Ã¼¸¦ ÅëÇØ¼ ±¸ÇÑ ¼öÁ¤ÀÚ(Modifier) ¾ÈÀÇ ¹®¸Æ(Context)¸¦ ±¸Çϸé BoneÀÇ ¿µÇâµµ¸¦ ±¸ÇÒ ¼ö ÀÖ½À´Ï´Ù. ¹®¸ÆÀ» ±¸ÇÏ´Â ¹æ¹ýÀº ¼öÁ¤ÀÚ¿¡¼ PHYSIQUE/SKIN °´Ã¼¸¦ ¾ò°í ÀÌ °´Ã¼¿¡¼ ¹®¸ÆÀ» ´ÙÀ½°ú °°ÀÌ ¾ò½À´Ï´Ù.
IPhysiqueExport(¶Ç´Â ISkin)* pExport = NULL;
IPhyContextExport(¶Ç´Â ISkinContextData)* pContext = NULL;
pExport = pMod->GetInterface(I_PHYINTERFACE/I_SKIN); // PHYSIQUE/SKIN °´Ã¼
pContext = pExport->GetContextInterface(pNode); // Context
¹®¸ÆÀ» ¾ò°í ³ª¼ PHYSIQUE¿¡¸¸ ¹®¸Æ¿¡ ´ëÇØ¼ Rigidº¯°æ°ú ºí·»µù Ȱ¼ºÈ¸¦ Áö½ÃÇÕ´Ï´Ù.
pContext->ConvertToRigid(TRUE); // Context¿¡ ´ëÇØ¼ Rigid·Î º¯°æ
pContext->AllowBlending(TRUE); // Á¤Á¡ Blending Ȱ¼ºÈ
´ÙÀ½À¸·Î Bone¿¡ ¿µÇâ ¹Þ´Â Á¤Á¡ÀÇ ¼ö¸¦ ±¸ÇÕ´Ï´Ù.
int nVtx = pContext->GetNumberVertices(); // Bone¿¡ ¿µÇâ ¹Þ´Â Á¤Á¡ÀÇ
°³¼ö
ÀÌ Á¤Á¡ÀÇ ¼ö´Â ½ÇÁ¦·Î
GeometryÀÇ Á¤Á¡ °³¼ö¿Í ÀÏÄ¡ÇÕ´Ï´Ù. ÀÌ °³¼ö¸¸Å ´ÙÀ½°ú °°ÀÌ for ¹® ¾È¿¡¼ ¹®¸Æ¿¡¼ BoneÀÇ À妽º¿Í ºñÁßÀ» ±¸ÇÕ´Ï´Ù. ÁÖÀÇÇÒ °ÍÀº RIGID_TYPE ÀÌ¸é ºñÁßÀ» 1·Î ÇÏ¸ç ³Ê¹« ÀÛÀº °ªÀÌ¸é ¹«½Ã¸¦ ÇÕ´Ï´Ù.
// PHYSIQUE
for(int j=0;
j<nVtx; ++j)
{
IPhyVertexExport* pPhyVtxExpt = pContext->GetVertexInterface(j);
IPhyBlendedRigidVertex* pPhyBlend = pPhyVtxExpt;
¡¦
if(RIGID_TYPE == pPhyVtxExpt->GetVertexType())
{
INode* pBone = ((IPhyRigidVertex*)pPhyVtxExpt)->GetNode();
INT nBone = FindBoneId(pBone); //º» À妽º
FLOAT fWgt = 1.f; //RIGID_TYPE´Â Weight=1
pGeo->pBlnd[j].vB.insert(std::pair<INT, FLOAT>(nBone, fWgt));
continue;
}
int numBones = pPhyBlend->GetNumberNodes();
for(int k = 0; k< numBones; ++k)
{
// k¹øÂ°ÀÇ º»À» ã´Â´Ù.
INode* pBone = pPhyBlend->GetNode(k);
INT nBone = FindBoneId(pBone);
FLOAT fWgt = pPhyBlend->GetWeight(k);
// °ªÀÌ ÀÛÀ¸¸é ¹«½Ã
if(fWgt<0.00005f)
continue;
pGeo->pBlnd[j].vB.insert(std::pair<INT, FLOAT>(nBone, fWgt));
}
}
¡¦
// SKIN
for(int j=0;
j<nVtx; ++j)
{
int numBones = pContext->GetNumAssignedBones(j);
for(int k=0; k<numBones; ++k)
{
int assignedBone = pContext->GetAssignedBone(j, k);
if(assignedBone < 0)
continue;
INode* pBone = pExport->GetBone(assignedBone);
INT nBone = FindBoneId(pBone);
FLOAT fWgt = pContext->GetBoneWeight(j, k);
// °ªÀÌ ÀÛÀ¸¸é ¹«½Ã
if(fWgt<0.00005f)
continue;
pGeo->pBlnd[j].vB.insert(std::pair<INT, FLOAT>(nBone, fWgt));
}
}
PHYSIQUE/SKIN ¿¡
´ëÇÑ ¾Ö´Ï¸ÞÀÌ¼Ç Çà·ÄÀ» ±¸ÇÏ´Â ¹æ¹ýÀº °Ã¼ ¾Ö´Ï¸ÞÀ̼ǰú Â÷À̰¡ ÀÖ½À´Ï´Ù. D3D¸¦ ±âÁØÀ¸·Î ¾Ö´Ï¸ÞÀ̼Ç
Çà·ÄÀº ´ÙÀ½°ú °°ÀÌ °è»ê µË´Ï´Ù.
¾Ö´Ï¸ÞÀÌ¼Ç ¿ùµå Çà·Ä = Pivot Çà·ÄÀÇ ¿ªÇà·Ä * ½Ã°£¿¡ ´ëÇÑ ³ëµåÀÇ ¿ùµå Çà·Ä
À̰ÍÀ» ±¸ÇöÇÏ·Á¸é ¸ÕÀú ³ëµå¿¡ ´ëÇÑ Pivot Çà·ÄÀÇ ¿ªÇà·ÄÀ» ±¸ÇÕ´Ï´Ù.
MATA mtPivot;
Matrix3 tmPivot = pNode->GetNodeTM(0);
tmPivot.Invert();
MaxMatrixToD3D(&mtPivot, &tmPivot);
½Ã°£¿¡ ´ëÇØ¼ ³ëµåÀÇ GetObjTMAfterWSM() ÇÔ¼ö·Î ½Ã°£¿¡
´ëÇÑ ³ëµåÀÇ ¿ùµå Çà·ÄÀ» ±¸ÇÏ°í ¾ÕÀÇ °ø½ÄÀ» ´ÙÀ½°ú °°ÀÌ Àû¿ëÇÕ´Ï´Ù.
for(n=0, dTime = dTimeB; dTime<=dTimeE ;
dTime += dTick, ++n)
{
MATA* pDest =
&pGeo->pAni[n];
Matrix3 tmWorld =
pNode->GetObjTMAfterWSM(dTime);
tmWorld.NoScale();
MATA mtAni;
MaxMatrixToD3D(&mtAni,
&tmWorld);
mtAni
= mtPivot * mtAni;
*pDest
= mtAni;
}
ÀÌ ¶§ Å©±â º¯È¯ÀÌ Àû¿ëµÇÁö ¾Êµµ·Ï "tmWorld.NoScale();"
±¸¹®À» ²À ³Ö´Â °ÍÀÌ °¡Àå Áß¿äÇÕ´Ï´Ù. ¶ÇÇÑ ¾Ö´Ï¸ÞÀ̼ÇÀº °èÃþ ±¸Á¶¸¦ Àû¿ëÇÏÁö ¾Ê°í °ð
¹Ù·Î ¿ùµå º¯È¯À» ÀÌ¿ëÇϰí ÀÖ´Â °Í ¶ÇÇÑ ÁÖÀÇÇØ¾ß ÇÕ´Ï´Ù.
°èÃþ ±¸Á¶°¡ ¾Æ´Ñ ¿ùµå º¯È¯À» ÀÌ¿ëÇÏ°Ô µÇ¸é Ç÷¯±×Àο¡¼ ¸¸µç µ¥ÀÌÅ͸¦ °ÔÀÓ¿¡¼ ¾Ö´Ï¸ÞÀ̼ÇÀ» ±¸ÇöÇÒ ¶§ ´ÙÀ½°ú
°°ÀÌ Àû¿ëÇØ¾ß ÇÕ´Ï´Ù.
DWORD m_TimeB; // Start Time
DWORD m_TimeC; // Current Time
INT m_nAni; // Animation Index
¡¦
INT CLcmAcm::FrameMove()
¡¦
m_TimeC = GetTickCount();
DWORD dTime = m_TimeC - m_TimeB;
m_nAni = INT( dTime/m_Header.nFrmP);
m_nAni %=
m_Header.nFrmE;
// World Çà·Ä ¾÷µ¥ÀÌÆ®
for(n=0; n<m_Header.nGeo; ++n)
{
LcGeo* pGeo =
&m_pGeo[n];
MATA mtAni;
D3DXMatrixIdentity(&mtAni);
if(pGeo->pAni)
mtAni
= pGeo->pAni[m_nAni];
// World Çà·Ä ¼³Á¤
¡¦
}
À̰ÍÀ¸·Î PHYSIQUE/SKIN¿¡ ´ëÇÑ Á¤Á¡ÀÇ À§Ä¡, Bone À妽º¿Í ºñÁß, ¾Ö´Ï¸ÞÀ̼ǿ¡ ´ëÇÑ Ç÷¯±×Àο¡¼ Áß¿ëÇÑ ºÎºÐÀ»
»ìÆìº¸¾Ò½À´Ï´Ù. Àüü ÄÚµå´Â mxp23_skinning.zip¸¦ Âü°íÇϱ⠹ٶø´Ï´Ù. ´ÙÀ½Àº ÀÌ Ç÷¯±×ÀÎÀ¸·Î ÃßÃâÇÑ µ¥ÀÌÅ͸¦ D3D ¿¡¼ ½ºÅ°´× ¾Ö´Ï¸ÞÀ̼ÇÀ¸·Î
±¸ÇöÇØº¼ Â÷·ÊÀÔ´Ï´Ù.
5.3.3 Skinning
Animation
½ºÅ°´× ¾Ö´Ï¸ÞÀÌ¼Ç ±¸ÇöÀº ÀÌ¹Ì °íÁ¤ ±â´É ÆÄÀÌÇÁ¶óÀο¡¼ DirectXÀÇ X-FileÀ» °¡Áö°í ÇØ º»ÀûÀÌ ÀÖ½À´Ï´Ù. ÇϳªÀÇ Á¤Á¡
¿¡ ¿µÇâÀ» ÁÖ´Â Çà·ÄÀ»
, ºñÁßÀ»
¶ó ÇÏ¸é º¯È¯ ÈÄÀÇ Á¤Á¡ À§Ä¡
´Â ´ÙÀ½°ú °°ÀÌ °è»êÀÌ µÇ°í,

°ýÈ£ ¾ÈÀÇ Á¡
Àº ¥Ò¹ÛÀ¸·Î »©³»¿Ã ¼ö ÀÖ°í, ¼ö½ÄÀ» Á¤¸®Çϸé
, 
ÀÌ µÇ¸ç
¸¦ °¢°¢ ¼öÇàÇϰí À̵éÀ» ´õÇÑ ÃÖÁ¾ Çà·ÄÀ»
À¸·Î °è»êÇÑ´Ù°í Çß½À´Ï´Ù. ÀÌ
³»¿ëÀ» CPU¿¡ ÀÇÇÑ ¼ÒÇÁÆ®¿þ¾î(Software) ¹æ¹ý, GPU¿¡ ÀÇÇÑ Çϵå¿þ¾î Áö¿ø ¹æ¹ý, ±×¸®°í ½¦ÀÌ´õ¸¦ ÀÌ¿ëÇÑ ¹æ¹ý, 3°¡Áö·Î ³ª´©¾î¼ Àû¿ëÇØ º¾½Ã´Ù.
¸ÕÀú ¼ÒÇÁÆ®¿þ¾îÀûÀÎ ¹æ¹ýÀÔ´Ï´Ù. ¿ì¸®ÀÇ ¸ñÇ¥´Â
À» ±¸ÇÏ´Â °ÍÀÔ´Ï´Ù. ´ÙÀ½ÀÇ
Äڵ忡¼
Àº ÀÌÁß for¹®
¾ÈÀÇ mtW º¯¼ö ÀÔ´Ï´Ù.
(mtW)´Â ´©ÀûµÇ¾î¾ß
ÇϹǷΠº¯¼ö¸¦ ¼±¾ðÇÏ°í ³ª¼ memset() ÇÔ¼ö·Î ÀüºÎ 0À¸·Î
ÃʱâÈ ÇÕ´Ï´Ù.
´ÙÀ½À¸·Î
¸¦ Àû¿ëÇÏ´Â °ÍÀε¥ À̰Ϳ¡ ÇØ´çÇÏ´Â ºÎºÐÀº ÄÚµåÀÇ
"mtT * fW" ÀÔ´Ï´Ù.
ÀÌ·¸°Ô
À» ±¸ÇßÀ¸¸é ¸¶Áö¸·À¸·Î
¸¦
Àû¿ëÇØ¾ß ÇÕ´Ï´Ù. À̰ÍÀº ¿øº» Á¤Á¡Àº ±×´ë·Î µÎ°í ¿øº»À» º¹»çÇÑ Á¤Á¡ÀÇ À§Ä¡¸¦ º¯°æÇÏ´Â D3DXVec3TransformCoord(¡¦); ºÎºÐÀÔ´Ï´Ù.
INT CLcmAcm::FrameMove()
¡¦
LcGeo* pGeo =
&m_pGeo[n];
¡¦
for(j=0; j<pGeo->nBlnd; ++j)
{
LcmBone* pBlnd
= &pGeo->pBlnd[j];
INT iBone
= pBlnd->vB.size();
MATA mtW;
memset(&mtW, 0, sizeof(mtW));
for(k=0; k<iBone; ++k)
{
FLOAT fW
=pBlnd->vB[k].fW;
INT nM
=pBlnd->vB[k].nB;
MATA mtT
= m_pGeo[nM].mtWld;
mtW
+= (mtT * fW);
}
D3DXVec3TransformCoord(&pGeo->pVxD[j].p,
&pGeo->pVtx[j].p, &mtW);
}
·»´õ¸µ¿¡¼´Â ¿ÀºêÁ§Æ® ÀÚüÀÇ ¿ùµå Çà·Äµµ ´ÙÀ½°ú °°ÀÌ Àû¿ëµÇ¾î¾ß ÇÕ´Ï´Ù.
void CLcmAcm::Render()
¡¦
VtxPos* pVtx = NULL;
¡¦
pVtx= pGeo->pVxD;
m_pDev->SetTransform(D3DTS_WORLD,
&m_mtWld);
¡¦
m_pDev->DrawIndexedPrimitiveUP(¡¦, pVtx, );
Àüü ÄÚµå´Â mxp23_skinning_view1_soft.zipÀ» Âü°í
Çϱ⠹ٶø´Ï´Ù.
¼ÒÇÁÆ®¿þ¾î ó¸® ¹æ¹ýÀº Çϵå¿þ¾îÀÇ ¼º´É¿¡ »ó°ü¾øÀÌ µ¿ÀÛÇÑ´Ù´Â ÀåÁ¡ÀÌ ÀÖÁö¸¸ Á¤Á¡ÀÇ º¹»çº»À» °¡Áö°í ÀÖ¾î¾ß Çϱâ
¶§¹®¿¡ °´Ã¼°¡ ¸¹¾ÆÁö¸é »ç¿ë ¸Þ¸ð¸®°¡ °´Ã¼¿¡ ºñ·ÊÇØ¼ ´Ã¾î³ª°í, Á¤Á¡ÀÇ °³¼ö°¡ ¸¹¾ÆÁú¼ö·Ï ¿¬»ê ·®µµ
Áõ°¡ÇÑ´Ù´Â ´ÜÁ¡ÀÌ ÀÖ½À´Ï´Ù.
»õ·Î¿î °´Ã¼°¡ ÀÌÀü °´Ã¼¿Í °°Àº ÇüÅÂÀÇ ¿ÀºêÁ§Æ®ÀÇ °æ¿ì Á¤Á¡À» º¹»çÇÏÁö ¾Ê°í ½ºÅ°´× ¾Ö´Ï¸ÞÀÌ¼Ç Çà·Ä¸¸ ´Ã¸®´Â
Çϵå¿þ¾î ó¸® ¹æ¹ýÀº ¾Ö´Ï¸ÞÀÌ¼Ç °»½Å¿¡¼´Â ½ºÅ°´× ¾Ö´Ï¸ÞÀÌ¼Ç Çà·Ä ¹öÆÛ¿¡ °»½ÅµÈ ¾Ö´Ï¸ÞÀÌ¼Ç Çà·ÄÀ» º¹»çÇϰí, ·»´õ¸µ¿¡¼´Â
À̸¦ ±×·¡ÇÈ ÆÄÀÌÇÁ¶óÀο¡ ¿¬°áÇϱ⸸ ÇÏ¸é µË´Ï´Ù.
¸ÕÀú ½ºÅ°´×ÀÌ GPU¿¡¼ ó¸®µÉ ¼ö ÀÖµµ·Ï ´ÙÀ½°ú °°Àº ±¸Á¶Ã¼¸¦ ÁغñÇÕ´Ï´Ù. ½ºÅ°´×¿¡ ´ëÇÑ ±¸Á¶Ã¼ ¼³Á¤Àº ÀÌÀüÀÇ °íÁ¤ ±â´É ÆÄÀÌÇÁ¶óÀο¡¼ÀÇ ½ºÅ°´× ºÎºÐÀ» Âü°í Çϱ⠹ٶø´Ï´Ù.
struct VtxBlend
{
VEC3 p;
FLOAT g[3]; // BLEND WEIGHT
BYTE m[4]; // MATRIX INDEX
enum { FVF = (D3DFVF_XYZB4 | D3DFVF_LASTBETA_UBYTE4), };
};
´ÙÀ½À¸·Î ±×·¡ÇÈ ÆÄÀÌÇÁ¶óÀο¡ ¼³Á¤ÇÒ Blending Çà·Ä ¹è¿À» ¼±¾ðÇÕ´Ï´Ù.
D3DXMATRIX m_mtBlnd[LCM_MAX_BLEND]; // Blending
Matrix Buffer
¾Ö´Ï¸ÞÀÌ¼Ç °»½Å¿¡¼ ¾ÕÀÇ Çà·Ä ¹è¿¿¡ ÃÖÁ¾ ¿ùµå Çà·ÄÀÎ "¾Ö´Ï¸ÞÀ̼Ç
°»½Å Çà·Ä * ÀÚ½ÅÀÇ ¿ùµå Çà·Ä" °ªÀ» º¹»çÇÕ´Ï´Ù.
INT CLcmAcm::FrameMove()
¡¦
// World Çà·Ä ¾÷µ¥ÀÌÆ®
for(n=0; n<m_Header.nGeo;
++n)
{
LcGeo* pGeo =
&m_pGeo[n];
MATA mtAni;
D3DXMatrixIdentity(&mtAni);
if(pGeo->pAni)
mtAni
= pGeo->pAni[m_nAni];
m_mtBlnd[n]
= mtAni * m_mtWld;
}
·»´õ¸µ¿¡¼´Â µð¹ÙÀ̽ºÀÇ Software Vertex ProcessingÀ»
Ȱ¼ºÈ ÇÕ´Ï´Ù. À̰ÍÀº µð¹ÙÀ̽º´Â Mixed ¶Ç´Â Software·Î »ý¼ºµÇ¾î¾ß °¡´ÉÇÕ´Ï´Ù.
´ÙÀ½À¸·Î µð¹ÙÀ̽ºÀÇ ·»´õ¸µ »óÅ¿¡ ´ëÇÑ INDEXEDVERTEXBLENDENABLEÀ»
Ȱ¼ºÈ Çϰí, VERTEXBLEND¿¡ ÀûÀýÇÑ °ª(D3DVBF_3WEIGHTS)À»
¼³Á¤ÇÕ´Ï´Ù. ¸¶Áö¸·À¸·Î SetTransform() ÇÔ¼ö¸¦
ÀÌ¿ëÇØ¼ ½ºÅ°´× Çà·Ä ¹è¿À» Àü´ÞÇÕ´Ï´Ù.
void CLcmAcm::Render()
¡¦
for(n=0; n<m_Header.nGeo;
++n)
{
LcGeo* pGeo =
&m_pGeo[n];
m_pDev->SetSoftwareVertexProcessing(TRUE);
m_pDev->SetRenderState(D3DRS_INDEXEDVERTEXBLENDENABLE, TRUE );
m_pDev->SetRenderState(D3DRS_VERTEXBLEND, D3DVBF_3WEIGHTS );
for(k=0; k<LCM_MAX_BLEND; ++k)
m_pDev->SetTransform( D3DTS_WORLDMATRIX(k),
&m_mtBlnd[k] );
m_pDev->DrawIndexedPrimitiveUP(¡¦);
}
Àüü ÄÚµå´Â mxp23_skinning_view2_hard.zipÀ» Âü°í
Çϱ⠹ٶø´Ï´Ù.
½¦ÀÌ´õ¸¦ ÀÌ¿ëÇÑ ¹æ¹ýÀº
¸¦ Àú¼öÁØ ¶Ç´Â °í¼öÁØ ¾ð¾î(High Level Shading Language)·Î ±¸ÇöÇÏ´Â °ÍÀÔ´Ï´Ù. °í¼öÁØ
¾ð¾î HLSL·Î ÀÛ¼ºÇÒ ¶§ °¡Àå Áß¿äÇÑ ºÎºÐÀº Á¤Á¡ ó¸® ÇÔ¼öÀÇ ÀÔ·Â Àμö¿Í ½Ã¸àƽ Á¤ÀÇ´Â ½ÅÁßÇØ¾ß
ÇÕ´Ï´Ù. ´ÙÀ½ ÇÔ¼ö´Â ½ºÅ°´×¿¡ ´ëÇÑ HLSL ÄÚµåÀÔ´Ï´Ù. À妽º¿¡ ´ëÇÑ Àμö Á¤ÀǸ¦ int4·Î
¼³Á¤Çϰí ÀÖÀ½À» ±â¾ïÇϱ⠹ٶø´Ï´Ù.
ÀÔ·Â ·¹Áö½ºÅÍ °ªÀº Read OnlyÀ̱⠶§¹®¿¡ °ªÀ» º¯°æÇÒ ¼ö ¾ø½À´Ï´Ù. ÀÌ·± ÀÌÀ¯·Î Wgx º¯¼ö¿¡ ÀÔ·Â ·¹Áö½ºÅÍ °ª(Wgt)À» º¹»çÇϰí À妽º 3¿¡ ´ëÇÑ °ªÀ» ¼³Á¤Çϰí ÀÖ½À´Ï´Ù. °£´ÜÈ÷ for¹®¿¡¼ ºñÁß°ú Çà·ÄÀ» °ö¼ÀÇÑ ÈÄ ÀÌ °á°ú¸¦ ´©Àû½ÃÄÑ
¸¦ ±¸Çϰí ÀÖ½À´Ï´Ù.
¶ÇÇÑ
ÀÇ ¸¶Áö¸· _44 °ªÀÌ 1 º¸´Ù ¸Ö¸® ¶³¾îÁ® ÀÖÀ¸¸é
ÀÇ Çà·ÄÀ» ´ÜÀ§Çà·Ä·Î ¸¸µé¾î¾ß
ÇÕ´Ï´Ù.
À» ±¸ÇÏ°í ³ª¼ ÀÌ Çà·Ä¿¡ °´Ã¼ÀÇ ¿ùµå Çà·ÄÀ» °öÇØ¼ ÃÖÁ¾
¿ùµå Çà·ÄÀ» ¸¸µç ´ÙÀ½ Á¤Á¡À» ¿ùµå º¯È¯, ºä º¯È¯, Åõ¿µ
º¯È¯¿¡ ´ëÇÑ ¿¬»êÀ» ÁøÇàÇÕ´Ï´Ù.
float4x4 m_mtBlnd[128]: WORLDMATRIXARRAY; // Blending Matrix Buffer
float4 VtxBlend( float4 Pos: POSITION
,
float4 Wgt: BLENDWEIGHT
,
int4
Idx: BLENDINDICES ) : POSITION
{
float4 Pout
=0.0f;
float4x4 mtW
= 0.0f;
float4 Wgx
= Wgt;
Wgx[3] = 1.0f - (Wgx[0] + Wgx[1] + Wgx[2]);
// ¥ÒMi * Wi ¿¬»ê
for(int i=0; i<4; ++i)
mtW
+= Wgx[i] * m_mtBlnd[Idx[i]];
// _44 °ªÀÌ 1¿¡¼ ¸Ö¸® ¶³¾îÁ® ÀÖÀ¸¸é ´ÜÀ§Çà·Ä·Î ¸¸µç´Ù.
if(mtW._44 <0.001f)
mtW
= float4x4(1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1);
mtW = mul(mtW, m_mtWld); // °´Ã¼ÀÇ ¿ùµå Çà·Ä°ú °ö¼À
Pout
= mul(Pos,
mtW); // ¿ùµå º¯È¯
Pout
= mul(Pout,
m_mtViw); // ºä º¯È¯
Pout
= mul(Pout,
m_mtPrj); // Åõ¿µ º¯ÇÑ
return P;
}
½¦ÀÌ´õ ÄÚµå´Â mxp23_skinning_view3_shader1.zipÀÇ "data/shader.fx"¸¦ Âü°í Çϱ⠹ٶø´Ï´Ù.
·»´õ¸µ¿¡¼´Â ºä Çà·Ä, Åõ¿µ Çà·Ä,
¿ùµå Çà·Ä, Blending Çà·ÄÀ» ¼³Á¤Çϰí Àå¸éÀ» ¿¬ÃâÇÕ´Ï´Ù. Blending Çà·ÄÀº ÀÌÀüÀÇ Çϵå¿þ¾î 󸮿¡¼ »ç¿ëÇÑ Çà·Ä ¹è¿À» ±×´ë·Î »ç¿ë ÇÕ´Ï´Ù.
m_pEft->SetMatrix("m_mtViw",
&mtViw); // ºä Çà·Ä ¼³Á¤
m_pEft->SetMatrix("m_mtPrj",
&mtPrj); // Åõ¿µ Çà·Ä ¼³Á¤
m_pEft->SetMatrix("m_mtWld",
&m_mtWld); // ¿ùµå Çà·Ä ¼³Á¤
m_pEft->SetMatrixArray("m_mtBlnd",
m_mtBlnd, LCM_MAX_BLEND); // Blending Çà·Ä ¼³Á¤
¡¦
hr =
m_pDev->DrawIndexedPrimitiveUP(¡¦);
Àüü ÄÚµå´Â mxp23_skinning_view3_shader1.zipÀ»
Âü°íÇϱ⠹ٶø´Ï´Ù.
¸¸¾à ½¦ÀÌ´õ ÄÚµå ÀÛ¼º¿¡¼ ÀÔ·Â ·¹Áö½ºÅÍ(ÀÔ·Â Àμö)ÀÇ ¼³Á¤¿¡ ¾î·Á¿òÀÌ ÀÖÀ¸¸é ºñÁß°ú Çà·ÄÀÇ À妽º¸¦ ÅØ½ºÃ³ ÁÂÇ¥¿¡ Àû¿ëÇØ¼ ±¸ÇöÇØµµ µË´Ï´Ù. ´ÙÀ½Àº ·»´õ¸µ ¿ÀºêÁ§Æ®°¡ µÎ °³ÀÇ ÅØ½ºÃ³ ÁÂÇ¥¸¦ »ç¿ëÇϰí ÀÖÀ» ¶§ ½ºÅ°´× ±¸Çö ¿¹ÀÔ´Ï´Ù.
float4 VtxBlend( float4 Pos: POSITION
,
float2 Tx0: TEXCOORD0 // ÅØ½ºÃ³ ÁÂÇ¥ 0
,
float2 Tx1: TEXCOORD1 // ÅØ½ºÃ³ ÁÂÇ¥ 1
,
float4 Wgt: TEXCOORD2 // Blending Weight
,
float4 Idx: TEXCOORD3 // Blending Index
) : POSITION
{
float4 Pout =0.0f;
float4x4 mtW = 0.0f;
// ¥ÒMi * Wi ¿¬»ê
for(int i=0; i<4; ++i)
mtW
+= Wgt[i] * m_mtBlnd[Idx[i]];
¡¦
ÅØ½ºÃ³ ÁÂÇ¥¸¦ »ç¿ëÇÏ°Ô µÇ¸é ´ÙÀ½°ú °°ÀÌ Á¤Á¡ ±¸Á¶Ã¼¿Í FVF¸¦ ¼öÁ¤Çؾß
ÇÕ´Ï´Ù.
struct VtxBlend
{
VEC3 p;
VEC2 t0; // Texture Coordinate 0
VEC2 t1; // Texture Coordinate 1
VEC4 g; // BLEND WEIGHT
VEC4 m; // MATRIX INDEX
enum { FVF = (D3DFVF_XYZ | D3DFVF_TEX4 | \
D3DFVF_TEXCOORDSIZE4(2)
| D3DFVF_TEXCOORDSIZE4(3)),
};
};
Blend Weight¿Í
Matrix Index´Â 4°³¸¦ »ç¿ëÇϹǷÎ
D3DXVECTOR4¸¦ »ç¿ëÇϸç ÀÌ °æ¿ì ÅØ½ºÃ³ ÁÂÇ¥ ½Ã½ºÅÛÀ» D3DFVF_TEXCOORDSIZE4·Î
º¯°æÇØ¾ß ÇÕ´Ï´Ù.
ÅØ½ºÃ³ ÁÂÇ¥¸¦ »ç¿ëÇÏ°Ô µÇ¾î Á¤Á¡ÀÇ Å©±â°¡ 16Byte ´õ »ç¿ëÇÏÁö¸¸
°¡Àå ¹«³ÇÏ°í ¾ÈÀüÇÏ°Ô »ç¿ëÇÒ ¼ö ÀÖ´Â ¹æ¹ýÀÔ´Ï´Ù. mxp23_skinning_view3_shader2.zipÀ»
Âü°íÇϱ⠹ٶø´Ï´Ù.

<½ºÅ°´× ¾Ö´Ï¸ÞÀ̼Ç:
Software, Hardware, Shader>
5.3.4
Interpolation
°ÔÀÓÀ» ½ÇÇàÇÏ´Â °³Àοë ÄÄÇ»ÅÍÀÇ ¼º´ÉÀº Â÷À̰¡ ÀÖÀ¸¹Ç·Î ÇÁ·¹ÀÓ°ú ÇÁ·¹ÀÓ »çÀ̸¦ º¸Á¤Çؼ Àå¸éÀ» ¿¬ÃâÇØ¾ß ÇÕ´Ï´Ù. °¡Àå °£´ÜÇÑ º¸Á¤ ¹æ¹ýÀº ¼±Çü º¸°£(Linear Interpolation)À¸·Î
¿ì¸®´Â ASEÀ» ParsingÇÒ ¶§ ÇØºÃ½À´Ï´Ù.
ASE¿¡¼´Â À§Ä¡, ȸÀü¿¡
»ç¿ø¼ö¸¦ °¡Áö°í ÀÖ´Â »óȲ¿¡¼ ¼±Çü º¸°£À» ±¸¼ºÇßÀ¸³ª Áö±ÝÀº Çà·Ä·Î ¾Ö´Ï¸ÞÀÌ¼Ç Á¤º¸¸¦ °¡Áö°í ÀÖ¾î¼ ÀÌ Çà·Ä¿¡¼ À§Ä¡¿Í »ç¿ø¼ö¸¦ ¾ò¾î¼ ¼±Çüº¸°£
ÇÑ ´ÙÀ½ ´Ù½Ã Çà·Ä·Î ¸¸µé¾î¾ß ÇÕ´Ï´Ù.
Çà·Ä¿¡¼ _41, _42, _43ÀÇ °ªÀº À̵¿¿¡ ´ëÇÑ º¯È¯À¸·Î À§Ä¡¸¦
³ªÅ¸³À´Ï´Ù. ȸÀüÀÇ °æ¿ì¿¡´Â D3DXQuaternionRotationMatrix()ÇÔ¼ö¸¦
ÀÌ¿ëÇØ¼ »ç¿ø¼ö¸¦ ±¸ÇÕ´Ï´Ù.
À§Ä¡´Â ´ÙÀ½ÀÇ ¼±Çü º¸°£ °ø½ÄÀ¸·Î ±¸ÇÕ´Ï´Ù.
v' = (1 - t) * v1 + t * v2
»ç¿ø¼ö´Â D3DXQuaternionSlerp() ÇÔ¼ö¸¦ ÀÌ¿ëÇÕ´Ï´Ù.
´ÙÀ½Àº µÎ Çà·Ä°ú ºñÁß t°¡ ÁÖ¾îÁú ¶§ À§Ä¡¿Í ȸÀü¿¡ ´ëÇÑ ¼±Çü º¸°£ÀÔ´Ï´Ù.
void CLcmAcm::MatrixLerp(D3DXMATRIX* pOut
, const D3DXMATRIX* m1, const D3DXMATRIX* m2, DOUBLE t)
{
D3DXQUATERNION q, q1, q2;
D3DXVECTOR3 v,
v1, v2;
D3DXQuaternionRotationMatrix(&q1, m1); // ȸÀü ÃßÃâ
D3DXQuaternionRotationMatrix(&q2, m2);
v1
= D3DXVECTOR3(m1->_41, m1->_42, m1->_43); // À§Ä¡ ÃßÃâ
v2 = D3DXVECTOR3(m2->_41, m2->_42, m2->_43);
v
= (1 - t) *
v1 + t * v2; // À§Ä¡¿¡ ´ëÇÑ ¼±Çü º¸°£
D3DXQuaternionSlerp(&q,
&q1, &q2, t); // ȸÀüÀÇ ¼±Çü º¸°£
D3DXMatrixRotationQuaternion(pOut, &q); // ȸÀüÀ» Çà·Ä·Î Àüȯ
pOut->_41
= v.x; pOut->_42 = v.y; pOut->_43 = v.z; // À§Ä¡ Àû¿ë
}
±×·±µ¥ ½Ã°£¿¡ ´ëÇÑ ¾Ö´Ï¸ÞÀÌ¼Ç °£°ÝÀ» Á¼°Ô ¼³Á¤Çϰí Çà·ÄÀ» ÃßÃâÇßÀ¸¸é ¾ÕÀÇ ÄÚµåó·³ °è»êÇÏÁö ¾Ê°í Çà·Ä ÀÚü¸¦
¼±Çü º¸°£Çصµ µË´Ï´Ù.
*pOut = (1 - t) * (*m1) + t * (*m2);
À̰ÍÀÌ °¡´ÉÇÑ ÀÌÀ¯´Â ȸÀüÀÇ °æ¿ì º¸°£ÇÏ´Â µÎ »ç¿ø¼öÀÇ °¢µµ°¡ ÀÛÀ¸¸é
°¡ µÇ¾î
´ÙÀ½°ú °°ÀÌ È¸ÀüÀÇ »ç¿ø¼ö º¸°£ °ø½ÄÀÌ ¼±Çü º¸°£À¸·Î ¹Ù²î°Ô µÇ±â ¶§¹®¿¡ Çà·ÄÀ» ¼±Çü º¸°£ ÇØµµ µÇ´Â °ÍÀÔ´Ï´Ù.



mxp24_interpolation.zip˼
Çà·ÄÀ» ¼±Çü º¸°£ÇÒ ¶§¿Í »ç¿ø¼ö¸¦ ºÐ¸®Çؼ º¸°£ÇÏ´Â ¿¹ÀÔ´Ï´Ù. ¾Ö´Ï¸ÞÀ̼ÇÀÇ °£°ÝÀÌ Á¼±â ¶§¹®¿¡ ´«¿¡
¶ç°Ô º¸ÀÌ´Â Â÷ÀÌ´Â ¾ø½À´Ï´Ù.

<¾Ö´Ï¸ÞÀÌ¼Ç º¸°£: mxp24_interpolation.zip>
5.4 ±âŸ
5.4.1 Normal
¸Æ½ºÀÇ ¸ðµç ¸Þ½¬´Â ¹ý¼± º¤ÅÍ(Normal Vector)¸¦ °¡Áö°í
ÀÖ½À´Ï´Ù. ¶ÇÇÑ ¹ý¼± º¤ÅÍÀÇ °³¼ö´Â Á¤Á¡ÀÇ ¼ö¿Í ÀÏÄ¡ ÇÕ´Ï´Ù. ¹ý¼±
º¤Å͸¦ ÃßÃâÇϱâ À§Çؼ ´ÙÀ½°ú °°ÀÌ ¸Þ½¬¿¡°Ô Á¤Á¡ÀÇ ¹ý¼±°ú Face(»ï°¢Çü Æò¸é)¿¡ ´ëÇÑ ¹ý¼± º¤ÅÍ »ý¼ºÀ» ¿äûÇÕ´Ï´Ù.
Mesh* pMesh = &pTri->GetMesh();
¡¦
pMesh->buildNormals();
´ÙÀ½À¸·Î ¹ý¼± º¤Å͸¦ ÀúÀåÇÒ °ø°£À» »ý¼ºÇÏ°í ¸Þ½¬ÀÇ getNormal() ÇÔ¼ö¸¦
ÀÌ¿ëÇØ¼ ¹ý¼± º¤Å͸¦ ¾ò¾î¿Í ÀúÀåÇÕ´Ï´Ù.
INT iNvtx = pMesh->getNumVerts();
¡¦
pGeo->pNor = new D3DXVECTOR3[iNvtx];
for (n=0; n<iNvtx; ++n)
{
Point3 v = Normalize(pMesh->getNormal(n)); // ¹ý¼±º¤ÅÍ ÃßÃâ
pGeo->pNor[n].x
= v.x;
pGeo->pNor[n].y
= v.z; //y <--> z ±³È¯
pGeo->pNor[n].z
= v.y;
}
5.4.2 Material
Geometry¿¡ Àû¿ëµÈ ÅØ½ºÃ³ ÆÄÀÏ À̸§Àº ¸Æ½ºÀÇ ÀçÁú(Material)¿¡¼ ã¾Æ¾ß ÇÕ´Ï´Ù. ±×·±µ¥ D3DÀÇ ÀçÁúÀº ÇϳªÀÇ ¸Þ½¬ µ¢¾î¸®(Geometry Object)¿¡
ÇϳªÀÇ ÀçÁúÀÌ Àû¿ëµÇ´Â µ¥ ¹ÝÇØ¼ ¸Æ½ºÀÇ ÀçÁúÀº ÇϳªÀÇ ¸Þ½¬ ¾È¿¡¼µµ ¿©·¯ ÀçÁúÀ» »ç¿ëÇϱ⵵ ÇÕ´Ï´Ù. ÀÌ·¯ÇÑ
°æ¿ì¿¡´Â »ï°¢Çüµé °¢ ÀçÁú¿¡ µû¶ó ºÐ¸®ÇÏ°í ´Ù½Ã ±¸ÃàÇØ¾ß ÇÏÁö¸¸ À̰ÍÀº ÇÁ·Î±×·¡¸Ó¿¡°Ô ³Ê¹«³ª ¸¹Àº ³ë·Â°ú ½Ã°£À» ¿ä±¸ÇÏ°Ô µÇ¸ç Àß ÇØ°áµÇÁöµµ ¾Ê½À´Ï´Ù. ¿©±â¼ ¿øÄ¢À» ¼¼¿ì´Â °ÍÀÌ Áß¿äÇѵ¥ ³ªÀÇ ¸Þ½¬¿¡´Â ÇϳªÀÇ ÅØ½ºÃ³¸¸ Àû¿ëÇÏ°í ¿©·¯ ¸Þ½¬°¡ °áÇÕÇÏ´Â °æ¿ì¶ó¸é °¢°¢ÀÇ
¸Þ½¬¸¦ µû·Î ÃßÃâÇÑ ´ÙÀ½ ÇÁ·Î±×·¥¿¡¼ ¸µÅ©(link)ÇÏ´Â °ÍÀÔ´Ï´Ù. ÀÌ·¸°Ô
ÇÏ¸é °ÔÀÓ¿¡ ¿Ã·ÈÀ» ¶§ ¾û¶×ÇÑ ÅØ½ºÃ³°¡ ºÙ°Å³ª ¾È ºÙ´Â ¹®Á¦µéÀ» ¾î´À Á¤µµ ÇØ°áÇÒ ¼ö ÀÖ½À´Ï´Ù.
º»°ÝÀûÀ¸·Î ÀçÁú¿¡¼ ÅØ½ºÃ³ ÆÄÀÏ À̸§À» ±¸ÇØ º¾½Ã´Ù.
INode °´Ã¼¿¡¼ ¿ì¸®´Â ÀçÁúÀ» ´ÙÀ½°ú °°ÀÌ ¾ò¾î¿Ã ¼ö ÀÖ½À´Ï´Ù.
INode* pNode = m_vMaxNode[i];
Mtl* pMtrl = pNode->GetMtl();
¸Æ½ºÀÇ ÀçÁúÀº INodeó·³ ÇÏÀ§ ÀçÁúÀ» ³ª¹« ±¸Á¶(Tree Structure)·Î °¡Áö°í ÀÖ½À´Ï´Ù. µû¶ó¼ ÀçÁúÀ» ¾òÀº
´ÙÀ½¿¡ ÇÏÀ§ ÀçÁúÀ» ´ÙÀ½°ú °°ÀÌ ¾ò¾î¾ß ÇÕ´Ï´Ù.
int iSub = pMtl->NumSubMtls();
for(int i=0; i<iSub; ++i)
Mtl* pSub = pMtl->GetSubMtl(i);
À̰ÍÀº ³ëµå¸¦ ¸ðÀ» ¶§Ã³·³ Àç±Í È£Ãâ(Recursive Call) ÇÔ¼ö¸¦
¸¸µé¾î¼ Àüü ÀçÁúÀ» ¸ð¾Æ¾ß ÇÕ´Ï´Ù. ÀçÁúÀ» ¸ðÀ» ¶§ ¾î´À ³ëµå¿¡¼ ¾ò¾îÁø ÀçÁúÀÎÁö ´ÙÀ½°ú °°Àº ±¸Á¶Ã¼¸¦
ÀÛ¼ºÇÕ´Ï´Ù.
struct LcMtl
{
INode* pNode; // Node
Mtl* pMtrl; // Material
};
³ëµå¿Í ÀçÁúÀ» ÀúÀåÇÒ ¼ö ÀÖµµ·Ï ÀÌ ±¸Á¶Ã¼¸¦ ÀÌ¿ëÇØ¼ ´ÙÀ½°ú °°Àº STLÀÇ
º¤ÅÍ ÄÁÅ×À̳ʸ¦ ¸¸µì´Ï´Ù.
std::vector<LcMtl> m_vMaxMtrl;
Àç±Í È£Ãâ ÇÔ¼ö ¾È¿¡¼ ¸ÕÀú ÀÔ·Â ¹ÞÀº ³ëµå¿Í ÀçÁúÀ» ¹¾î¼ ÀúÀåÇÕ´Ï´Ù. ´ÙÀ½À¸·Î
ÇÏÀ§ ÀçÁúÀ» ¾ò°í ÀÌ ÇÔ¼ö¸¦ ´Ù½Ã È£ÃâÇÕ´Ï´Ù.
void LcMax::GatherMaterial(INode* pNode, Mtl* pMtl)
¡¦
m_vMaxMtrl.push_back(LcMtl(pNode, pMtl));
int iSub = pMtl->NumSubMtls();
for(int i=0; i<iSub; ++i)
{
Mtl* pSub = pMtl->GetSubMtl(i);
GatherMaterial(pNode,
pSub);
}
ÀÌ·¸°Ô ³ëµå¿¡ ´ëÇÑ ¸ðµç ÀçÁúÀ» ÀúÀåÇß½À´Ï´Ù. ´ÙÀ½À¸·Î ÀçÁú ¾È¿¡¼
ÅØ½ºÃ³ ÆÄÀÏ À̸§À» °¡Á®¿Í¾ß ÇÕ´Ï´Ù. ¸Æ½ºÀÇ ÀçÁúÀº ¿©·¯ ÅØ½ºÃ³¸¦ °¡Áö°í ÀÖ½À´Ï´Ù. À̵é ÅØ½ºÃ³´Â Á¶¸í È¿°ú¿Í ¹Ý»ç È¿°ú µî¿¡ ´ëÇÑ ¿ªÇÒÀ» ¼öÇàÇÕ´Ï´Ù. ¿ì¸®°¡
°¡Á®¿À·Á´Â ÅØ½ºÃ³´Â Á¶¸í È¿°ú Áß¿¡¼ Diffuse Map¿¡ ´ëÇÑ ÅØ½ºÃ³À̸ç ÀÌ ¾ÆÀ̵ð´Â " ID_DI" ÀÔ´Ï´Ù.
ÀçÁú¿¡¼ À̸§À» °¡Á®¿À´Â ¹æ¹ýÀº ¸ÕÀú ÀçÁú¿¡¼ ÇÏÀ§ ÅØ½ºÃ³ÀÇ ¼ýÀÚ¸¦ ¾Ë¾Æ³»°í ÀÌ ¼ýÀÚ¸¸Å ¼øÈ¸ÇÏ¸é¼ Texmap °´Ã¼¸¦ ¾ò½À´Ï´Ù. Texmap °´Ã¼¸¦ BitmapTex À¸·Î ij½ºÆÃÇØ¼ GetMapName() ÇÔ¼ö¸¦ È£ÃâÇϸé
À̸§À» °¡Á®¿À°Ô µË´Ï´Ù.
INT iSub = pMtrl->NumSubTexmaps();
for( j=0; j<iSub; ++j)
{
Texmap* subTex =
pMtrl->GetSubTexmap(j);
DumpTexture(pLcMtl,
subTex, j);
}
¡¦
void LcMax::DumpTexture(LcMtl* pLcMtrl, Texmap* txm, INT iSubIdx)
¡¦
// °æ·Î¸¦ Æ÷ÇÔÇÑ ÅØ½ºÃ³ ÆÄÀÏ
À̸§À» °¡Á®¿Â´Ù.
TSTR bitmapFile = ((BitmapTex *)txm)->GetMapName();
¡¦
// ÇÏÀ§ ÅØ½ºÃ³ °Ë»ç
INT iSub = txm->NumSubTexmaps();
for(i=0; i<iSub; ++i)
{
Texmap* pSub = txm->GetSubTexmap(i);
DumpTexture(pLcMtrl,
pSub, iSubIdx);
}
°¢ ³ëµå´Â °°Àº ÀçÁúÀ» »ç¿ëÇÒ ¼ö ÀÖ½À´Ï´Ù. µû¶ó¼ ÅØ½ºÃ³ ÆÄÀÏÀ̸§ÀÌ
Áߺ¹ µÉ ¼ö Àִµ¥ STLÀÇ Set ÄÁÅ×À̳ʸ¦ ÀÌ¿ëÇϸé Áߺ¹µÈ
À̸§À» Á¦°ÅÇÒ ¼ö ÀÖ½À´Ï´Ù. ³ëµå¿Í ÅØ½ºÃ³ ÆÄÀÏ À̸§ ¿¬°áÀº ±â¼úÀûÀÎ ºÎºÐÀ̹ǷΠmxp25_lcm_skinning_plugin.zip
¿¹Á¦ÀÇ GatherTexture(), SetupTextureIndex(), FindTextureIndex()
ÇÔ¼ö µîÀ» Âü°í Çϱ⠹ٶø´Ï´Ù.
5.4.3 ÅØ½ºÃ³ ÁÂÇ¥
Ç÷¯±×ÀÎÀÇ ¸¶Áö¸·ÀÎ ÅØ½ºÃ³ ÁÂÇ¥ ÃßÃâÀÔ´Ï´Ù. ASE¿¡¼ "¸Æ½ºÀÇ Á¤Á¡Àº ÅØ½ºÃ³ ÁÂÇ¥¿¡¼ °øÀ¯ µÉ ¼ö ÀÖ´Ù"¶ó°í
¾ð±ÞÇÑ ÀûÀÌ ÀÖ½À´Ï´Ù. µû¶ó¼ Á¤Á¡ÀÇ °³¼ö¸¦ ÅØ½ºÃ³ ÁÂÇ¥¸¸Å ´Ã·ÁÁÖ¾î¾ß ÇÕ´Ï´Ù. ±×¸®°í ¸Æ½º´Â ÅØ½ºÃ³ ÁÂÇ¥ÀÇ À妽º°¡ ²À 0¿¡¼ºÎÅÍ ½ÃÀÛÇÏÁö ¾ÊÀ¸¸ç
¶ÇÇÑ Áß°£¿¡ »ç¿ëÇÏÁö ¾Ê´Â À妽ºµµ ÀÖ½À´Ï´Ù. ¿Ïº®¿¡ °¡±î¿î Ç÷¯±×ÀÎÀº ÀÌ·± °Íµµ ó¸®ÇØ¾ß ÇÏÁö¸¸ ¿ª½Ã
°£´ÜÇÑ ¹æ¹ýÀº ±×·¡ÇÈ ´ã´çÀÚ¿Í ÇùÀǸ¦ ÇØ¼ UV Á¤¸®¸¦ ºÎŹÇÏ´Â °ÍÀÌ °¡Àå Çö¸íÇÑ ¹æ¹ýÀÔ´Ï´Ù.
UV°¡ Àû¿ëµÈ ¸Þ½¬¿¡¼
Geometry¸¦ ±¸¼ºÇÏ´Â ¹æ¹ýÀ» Á¤¸®ÇÏ¸é ´ÙÀ½°ú °°½À´Ï´Ù.
1. T-face¿¡¼ UV »ï°¢Çü¿¡
´ëÇÑ À妽º ¸®½ºÆ®¸¦ ÃßÃâÇÑ´Ù.
2. T-vertex¿¡¼ UV¸¦
ÃßÃâÇÑ´Ù.
3. T-face¿¡ ´ëÀÀÇÏ´Â À妽º´Â FaceÀ妽º¿Í °°À¸¹Ç·Î À̵éÀ» Çϳª·Î ¹°í, U, V °ªµµ ¼³Á¤ÇÑ´Ù.
4. »õ·Î¿î Á¤Á¡ÀÇ °³¼ö¸¦
T-vertex °³¼ö¸¸Å ¼³Á¤ÇÑ´Ù.
5. Á¤Á¡ÀÇ À§Ä¡, ¹ý¼±
º¤ÅÍ, BoneÀÇ À妽º¿Í ºñÁß °ª µîÀ» »õ·Î ¸¸µé°í 3¹ø¿¡¼
¹Àº À妽º µîÀ» Âü°íÇØ¼ °ªÀ» »õ·Î ¼³Á¤ÇÑ´Ù.
6. ÀÌÀüÀÇ À§Ä¡, ¹ý¼±, Bone¿¡ ´ëÇÑ °ªµéÀ» Áö¿ì°í »õ·Î¿î °ªµé·Î ¼³Á¤ÇÑ´Ù.
ÀÌ °úÁ¤Àº mxp25_lcm_skinning_plugin.zipÀÇ LcMax::SetupUV() ÇÔ¼ö¿¡ ±¸ÇöµÇ¾î ÀÖ½À´Ï´Ù. ÁÖ¿ä Äڵ带
¼³¸íÇÏ¸é ¸ÕÀú ¸Þ½¬¿¡¼ T-faceÀÇ ¼ýÀÚ¿Í T-vertex(UV) ¼ýÀÚ¸¦
¾ò´Â ¹æ¹ýÀº ´ÙÀ½°ú °°½À´Ï´Ù.
nTfce =
pMesh->getNumFaces(); // T-face¿Í Face¼ýÀÚ´Â °°À½
nTvtt = pMesh->getNumTVerts(); // T-vertex(UV) Number
´ÙÀ½À¸·Î Àӽà ¹öÆÛ¿¡ T-face¿Í
T-vertex¸¦ ÀúÀåÇÕ´Ï´Ù.
// T-face List ÀúÀå
for(n=0; n<nTfce; ++n)
{
pNewFce[n]=VtxIdx( pMesh->tvFace[n].t[0]
,
pMesh->tvFace[n].t[2]
,
pMesh->tvFace[n].t[1]);
}
// T-vertex(UV) ÀúÀå
for(n=0; n<nTvtt; ++n)
{
UVVert t =
pMesh->tVerts[n];
pTvtt[n].x
= t.x;
pTvtt[n].y
= 1.f - t.y; // DXÀÇ UV¿¡ ¸Â°Ô ¼öÁ¤
}
T-faceÀÇ °æ¿ì Faceó·³
À妽º°¡ 0, 2, 1·Î µÇ¾î¾ß ÇÕ´Ï´Ù. ±×¸®°í UV¿¡¼ V°ªµµ ASEó·³ "1.0- V" ·Î ¼³Á¤ÇØ¾ß ÇÕ´Ï´Ù.
´ÙÀ½À¸·Î T-face, Face, U, V¸¦ ÀÛ¾÷À» Æí¸®ÇÏ°Ô Çϱâ
À§ÇØ ÇϳªÀÇ ¹À½À» ¸¸µì´Ï´Ù.
std::vector<_Tpck > lsFceVtxUV;
for(; itF != itL; ++itF)
{
int nT = (*itF).first.n;
int nV = (*itF).second;
FLOAT U = pTvtt[nT].x;
FLOAT V = pTvtt[nT].y;
lsFceVtxUV.push_back( _Tpck(nT, nV, U, V));
}
Face´ë½Å T-face¸¦
À妽º ¸®½ºÆ®·Î Á¤Çϰí Á¤Á¡ÀÇ °³¼ö, ¹ý¼±ÀÇ °³¼ö, Á¤Á¡¿¡
´ëÇÑ º»ÀÇ ºñÁßÀ» º¯°æÇϰí ÀÌÀü °ª¿¡¼ ã¾Æ¿Í º¹»çÇÕ´Ï´Ù.
INT nNewVtxSize
= lsFceVtxUV.size();
D3DXVECTOR3* pNewPos = new D3DXVECTOR3[nNewVtxSize]; // new Position List
D3DXVECTOR3* pNewNor = new D3DXVECTOR3[nNewVtxSize]; // new Normal Vector
D3DXVECTOR2* pNewUVW = new D3DXVECTOR2[nNewVtxSize]; // new UVW Vector
¡¦
for(n=0; n<nNewVtxSize; ++n)
{
INT G
= lsFceVtxUV[n].G; // Á¤Á¡ÀÇ À妽º
FLOAT U =
lsFceVtxUV[n].U;
FLOAT V =
lsFceVtxUV[n].V;
pNewPos[n]
= pOldPos[G];
pNewNor[n]
= pOldNor[G];
pNewUVW[n].x
= U;
pNewUVW[n].y
= V;
}
¸¸¾à Á¤Á¡¿¡ BonÀÇ
À妽º¿Í ºñÁßÀÌ ÀÖÀ¸¸é ÀÌµé ¶ÇÇÑ Á¶Á¤ÇÕ´Ï´Ù.
LcmBoneS* pNewBon
= new LcmBoneS[nNewVtxSize]; // new Bones
¡¦
for(n=0; n<nNewVtxSize; ++n)
{
int G = lsFceVtxUV[n].G; // Á¤Á¡ÀÇ À妽º
LcmBoneS* pBlndS=
&pOldBon[G]; // Source
¡¦
std::map<INT, FLOAT >::iterator _F
= pBlndS->vB.begin();
std::map<INT, FLOAT >::iterator _L
= pBlndS->vB.end();
for(; _F != _L; ++_F)
pNewBon[n].vB.insert( *_F );
}
¸¶Áö¸·À¸·Î ÀÌÀü °ªµéÀ» Áö¿ì°í »õ·Î¿î °ªµé·Î º¯°æÇÕ´Ï´Ù.
SAFE_DELETE_ARRAY( pOldFce );
SAFE_DELETE_ARRAY( pOldPos );
SAFE_DELETE_ARRAY( pOldNor );
pGeo->pFce =
pNewFce;
pGeo->pPos =
pNewPos;
pGeo->pNor =
pNewNor;
pGeo->pUVW =
pNewUVW;
pGeo->nVtx =
nNewVtxSize;
ÆÄÀÏ¿¡ ±â·ÏÇÒ ¶§´Â ÀÌÀüÀÇ ±¸Á¶¸¦ °ÅÀÇ ±×´ë·Î À¯ÁöÇÏ°í ¹ý¼± º¤ÅÍ, ÅØ½ºÃ³
ÆÄÀÏ ¸®½ºÆ®, Á¤Á¡ UV ¸®½ºÆ®¸¦ ¸¶Áö¸·¿¡ ±â·Ï ÇÕ´Ï´Ù. Àüü ÄÚµå´Â mxp25_lcm_skinning_plugin.zipÀ» Âü°í
Çϱ⠹ٶø´Ï´Ù.
Ç÷¯±×ÀÎÀÌ ¼öÁ¤µÇ¾î ºä¾îµµ ¼öÁ¤ÇØ¾ß ÇÕ´Ï´Ù. ºä¾î¿¡¼ ¸Þ½¬¿¡ ´ëÇÑ
Á¤Á¡ ±¸Á¶Ã¼¸¦ ´ÙÀ½°ú °°ÀÌ ¹ý¼± º¤ÅÍ, ÅØ½ºÃ³ ÁÂÇ¥¸¦ Æ÷ÇÔ½Ã۰í
FVFµµ º¯°æÇÕ´Ï´Ù.
struct VtxBlend
{
VEC3 p;
FLOAT g[3]; // BLEND WEIGHT
BYTE m[4]; // MATRIX Index
VEC3 n; // Normal Vector
VEC2 t; // Texture Coordinate
enum { FVF = (D3DFVF_XYZB4 | D3DFVF_LASTBETA_UBYTE4
|\
D3DFVF_NORMAL | D3DFVF_TEX1), };
};
ÆÄÀÏÀ» Àд ºÎºÐ°ú ·»´õ¸µ¿¡¼ ÅØ½ºÃ³ ¿¬°áÀº ¾î·ÆÁö ¾ÊÀ¸¹Ç·Î ³Ñ¾î°¡°Ú½À´Ï´Ù.
ÅØ½ºÃ³¿Í Á¶¸íÀ» Çȼ¿ ½¦ÀÌ´õ¿¡¼ ó¸®ÇÒ ¼ö ÀÖµµ·Ï ´ÙÀ½°ú °°Àº ±¸Á¶Ã¼¸¦ ¼±¾ðÇÕ´Ï´Ù.
struct SVsOut
{
float4 Pos: POSITION;
float2 Tex: TEXCOORD0; // Á¤Á¡ÀÇ ÅØ½ºÃ³ ÁÂÇ¥
float3 Nor: TEXCOORD7; // Á¤Á¡ÀÇ ¹ý¼± º¤ÅÍ
};
Á¤Á¡ µ¥ÀÌÅͰ¡ ¹ý¼± º¤ÅÍ, ÅØ½ºÃ³ ÁÂÇ¥¸¦ Æ÷ÇÔÇϰí ÀÖÀ¸¹Ç·Î Á¤Á¡ ó¸®
ÇÔ¼öÀÇ ÀÔ·Â Àμö¿¡ ¹ý¼±°ú ÅØ½ºÃ³ ÁÂÇ¥¸¦ Ãß°¡ÇÕ´Ï´Ù.
SVsOut VtxBlend( float4 Pos: POSITION // Position
,
float4 Wgt: BLENDWEIGHT // Blending Weight
,
int4
Idx: BLENDINDICES //
Blending Index
,
float3 Nor: NORMAL // Normal Vector
,
float2 Tex: TEXCOORD0 // Texture Coordinate
)
{
SVsOut Out
= (SVsOut)0;
¡¦
Out.Nor
= Nor;
Out.Tex
= Tex;
return Out;
}
¹ý¼± º¤ÅÍ¿Í ÅØ½ºÃ³´Â Ưº°È÷ ó¸®ÇØ¾ß ÇÒ ÀÏÀÌ ¾øÀ¸¹Ç·Î ±¸Á¶Ã¼¿¡ º¹»çÇØ¼ ±×´ë·Î Ãâ·ÂÇÕ´Ï´Ù. Çȼ¿ ½¦ÀÌ´õ ó¸® ÇÔ¼ö¿¡¼´Â UV ÁÂÇ¥¸¦ ÀÌ¿ëÇØ¼ ÅØ½ºÃ³¿¡¼ »ö»óÀ»
»ùÇøµ(Sampling) ÇÕ´Ï´Ù.
float4 PxlBlend(SVsOut In) : COLOR0
{
float4 Out = tex2D(smp0,
In.Tex); //
Sampling from Texture by Sampler
return Out;
}
Á¶¸íÀº ó¸®ÇÏÁö ¾Ê¾Ò´Âµ¥ ÀÌ ºÎºÐÀº ¿©·¯ºÐµé²²¼ ä¿öº¸½Ã±â ¹Ù¶ø´Ï´Ù. ´ÙÀ½À¸·Î
Å×Å©´Ð¿¡ Çȼ¿ ó¸® ÇÔ¼ö¸¦ ÁöÁ¤ÇÕ´Ï´Ù.
technique Tech
¡¦
pass P1
{
VertexShader = compile vs_2_0 VtxBlend();
PixelShader = compile ps_2_0 PxlBlend();
}
mxp25_lcm_skinning_viewer.zipÀ»
½ÇÇàÇÏ¸é ´ÙÀ½ ±×¸²Ã³·³ UV°¡ Àû¿ëµÈ ȸéÀ» º¼ ¼ö ÀÖ½À´Ï´Ù.

<ÅØ½ºÃ³°¡ Àû¿ëµÈ ½ºÅ°´× ¿¹Á¦:
mxp25_lcm_skinning_viewer.zip>