[Tutorial] Importing Diablo III models into Torchlight

Forum for discussing the Torchlight mod toolset.

Re: [Tutorial] Importing Diablo III models into Torchlight

Postby Jackalhead » Sat Jul 14, 2012 4:58 am

Zidders wrote:YEah Blender didn't go so well :/

I suck at this. Just wanted to take the Necro from D3 and try and mod him into Torchlight.


That's a good idea. I'll see if I have enough energy to do this after work and yoga today.

Arkham wrote:
Zidders wrote:YEah Blender didn't go so well :/

I suck at this. Just wanted to take the Necro from D3 and try and mod him into Torchlight.

Consider that there's only a four-hour span between you saying "Thanks" and this post.
I would give it more time and practice if I were you. I certainly didn't get where I am with Maya by messing with it for four hours and then giving up.



Exactly. It took me a week to learn how to do this. A full week and a LOT of determination. Then again, I didn't have a tutorial to walk me through it, so it probably took me longer than it will take you. Hahah I had to teach myself how to do most of it and I had to have Arkham and Sixshot teach me how to import the newly rigged model into Torchlight.

Just be patient yet ever persistent and you'll get it to the point it's as easy as slicing bread.
User avatar
Jackalhead
 
Posts: 1587
Joined: Thu Mar 15, 2012 7:47 pm
Location: Omnipresent


Re: [Tutorial] Importing Diablo III models into Torchlight

Postby Phanjam » Sun Jul 15, 2012 3:58 pm

Jackalhead wrote:Here's video footage of the fallen shaman and fallen one minions in Torchlight. :]
http://www.youtube.com/watch?v=csQKjHIs ... e=youtu.be

LOL! Fantastic Jackalhead! I like them minions too :twisted: do they have enough animations to be used as a playable class as-is, or do they have to be re-rigged?
User avatar
Phanjam
 
Posts: 1876
Joined: Mon Nov 30, 2009 11:15 pm
Location: Same as you, at the center of the universe

Re: [Tutorial] Importing Diablo III models into Torchlight

Postby Jackalhead » Sun Jul 15, 2012 6:41 pm

Phanjam wrote:
Jackalhead wrote:Here's video footage of the fallen shaman and fallen one minions in Torchlight. :]
http://www.youtube.com/watch?v=csQKjHIs ... e=youtu.be

LOL! Fantastic Jackalhead! I like them minions too :twisted: do they have enough animations to be used as a playable class as-is, or do they have to be re-rigged?


They are currently using the Mercenary's animations, so if you wanted to take advantage of all of the say Destroyer's abilities, I'd probably want to re-rig them to his animations. :] I just chose the Mercenary cause I liked the way he moved. Reminded me of the fallen ones from Diablo II.
User avatar
Jackalhead
 
Posts: 1587
Joined: Thu Mar 15, 2012 7:47 pm
Location: Omnipresent

Re: [Tutorial] Importing Diablo III models into Torchlight

Postby Phanjam » Mon Jul 16, 2012 2:24 am

Jackalhead wrote:They are currently using the Mercenary's animations, so if you wanted to take advantage of all of the say Destroyer's abilities, I'd probably want to re-rig them to his animations. :] I just chose the Mercenary cause I liked the way he moved. Reminded me of the fallen ones from Diablo II.

Thanks! Yes I like the way they lope too :D .
So to re-rig I'd use CCCenturion's skeleton-fixer scripts, am I right?
User avatar
Phanjam
 
Posts: 1876
Joined: Mon Nov 30, 2009 11:15 pm
Location: Same as you, at the center of the universe

Re: [Tutorial] Importing Diablo III models into Torchlight

Postby Jackalhead » Mon Jul 16, 2012 6:38 am

Phanjam wrote:
Jackalhead wrote:They are currently using the Mercenary's animations, so if you wanted to take advantage of all of the say Destroyer's abilities, I'd probably want to re-rig them to his animations. :] I just chose the Mercenary cause I liked the way he moved. Reminded me of the fallen ones from Diablo II.

Thanks! Yes I like the way they lope too :D .
So to re-rig I'd use CCCenturion's skeleton-fixer scripts, am I right?


I'm not sure cause I've never used those scripts. I just use Grabboi's mesh and skeleton import plugin to do all of this. haha
User avatar
Jackalhead
 
Posts: 1587
Joined: Thu Mar 15, 2012 7:47 pm
Location: Omnipresent

Re: [Tutorial] Importing Diablo III models into Torchlight

Postby Phanjam » Mon Jul 16, 2012 7:17 am

Thanks! and keep up the great work!
User avatar
Phanjam
 
Posts: 1876
Joined: Mon Nov 30, 2009 11:15 pm
Location: Same as you, at the center of the universe

Re: [Tutorial] Importing Diablo III models into Torchlight

Postby Brixtan » Mon Jul 30, 2012 1:56 pm

Jackalhead wrote:Here's video footage of the fallen shaman and fallen one minions in Torchlight. :]

http://www.youtube.com/watch?v=csQKjHIs ... e=youtu.be


lol, that is pretty funny stuff! :lol:
Image
"If a problem is too big to fix, one must break it into smaller problems."
The Ember Adventurer's Club: free toasters while they last.
User avatar
Brixtan
 
Posts: 2134
Joined: Thu Jun 16, 2011 9:12 am
Location: Pittsburgh, PA

Re: [Tutorial] Importing Diablo III models into Torchlight

Postby SparrowHusky » Wed Aug 29, 2012 9:16 pm

Hello friends! I'm trying to do join the fun and import some of these creatures myself, but I can't find this file anywhere online:

ImportOgreXML_0.02 3DSMax Script

Could someone please give me a hand here? Thanks!
SparrowHusky
 
Posts: 17
Joined: Wed Aug 29, 2012 8:02 am

Re: [Tutorial] Importing Diablo III models into Torchlight

Postby Arkham » Thu Aug 30, 2012 12:04 am

Here, copy this text into a text file, and rename the file to "ImportOgreXml_0.02.ms"

(this is a slightly modified version where I added a commented section toward the top, to remind me where I got it from and the instructions for using it)

Code: Select all
-Imports an Ogre SKELETON.xml file
--Author: mostly by Graboi with Inspiration from TaylorMouse and Cascade
--Much of the mesh importer was authored by Taylormouse and tweaked by Cascade
-- 2009

-- from http://forums.runicgames.com/viewtopic.php?f=6&t=8882
-- Actually there is a good importer that imports Torchlight
-- and other Ogre models into 3dsMax. I use it and it hasnt
-- given me any problems. It imports the .mesh and the .skeleton
-- with animations and the mesh is skinned to the bones for 3dsMax.
-- You have to redo the UV coordinates for the texture though.
-- It was pretty easy in all my cases. All i had to do was apply the
-- "Unwrap Modifier" click "edit" and just flip the geometry vertical and
-- lo and behold the UVW was now corrected again and textures looked great.
-- The script is on this forum somewhere but cant remember.
-- Its called ImportOgreXml_0.02.ms. made by graboi.


-- ver 0.02 11-19-09 Graboi
---- added animation browser, double click animation name to set it to the active animation
---- base pose skeleton now loads with mesh
---- added default texture name guessing and attachment
---- added default resource path and resource path setting
---- fixed the animation interval being set to 0 when a skeleton with no animations is loaded
---- changed the way the root bone is recognized , no longer relies on the bone name (tarantula loads now!)

-- ver 0.01a 11-16-09 Graboi
---- fixed keyframe bug with loading multiple animations,
---- fixed a bug with WalkTreeAnimate not being defined (oops! my bad ),
---- keyframes are now set to their encoded time value,
---- Note: time is based on 30 fps (max's default)

-- ver 0.01 11-15-09 Graboi
---- added rollout, animation loading

global pakPath = "c:/program files/runic games/torchlight/pak/media/*.MESH.xml"
global filePath
global skeletonBones = #()
global rootBone
global maxScale = 10.0
global clearRootRotation = true
global maxBoneSize = 0.04 * maxScale

global sharedVertices = #()
global sharedTextureUV = #()
global sharedNormals = #()
global sharedBoneWeights = #()
global subMeshArray = #()
global animLength
global animName
global gAnimations = #()

struct TBoneframe
(
boneName,
position,
rotation,
animationKeys
)
struct TAnimation
(
animLength,
animName,
boneFrames

)

struct TSubMesh
(
meshName,
maxMesh,
numFaces,
numVertices,
numNormals,
faceArray,
vertexArray ,
normalsArray,
uvArray,
boneWeightsArray,
usesShared

)

struct TWeight
(
vindex,
bindex,
weight
)

struct TBone
(
boneID,
boneName,
position,
rotation,
endPosition,
parentName,
parentIndex,
parentBone,
localMatrix,
worldMatrix,
childBones,
animationKeys
)
struct TKeyframe
(
time,
pos,
rot
)

fn GetBoneFrameByName boneFrames name=
(
local theBone
for b in boneFrames do
(
if b.boneName == name then
(
theBone = b
)
)   
theBone
)
function GetBoneByName name =
(
local theBone
for b in skeletonBones do
(
if b.boneName == name then
(
theBone = b
)
)   
theBone
)

function BuildBoneTree =
(
--builds a proper tree
for theBone in skeletonBones do
(
theBone.childBones = #()

if theBone.parentName == undefined then rootBone = theBone

for b in skeletonBones do
(
if b.parentName == theBone.boneName then
(
--b.parentIndex = boneIndex
b.parentBone = theBone
append theBone.childBones b
)
)   
)
)   

fn SetBasePose theBone =
(
maxBone = getNodeByName theBone.boneName
q3 = normalize (theBone.rotation as quat)
pos = theBone.position
mat = (q3 as matrix3)
mat.row4 = pos
theBone.localMatrix = mat

if theBone.parentBone != undefined then
(
theBone.worldMatrix = theBone.localMatrix * theBone.parentBone.worldMatrix
)
else --have root
(
theBone.worldMatrix = theBone.localMatrix
)

maxBone.transform = theBone.worldMatrix

--do childBones
for b in theBone.childBones do
(
SetBasePose b
)
)

fn WalkTreeAnimate theBone keyIndex =
(
animate off
--if this bone has a key add it to the initial position
if theBone.animationKeys != undefined and keyIndex > 0 and keyIndex <= theBone.animationKeys.count then
(
maxBone = getNodeByName theBone.boneName
key = theBone.animationKeys[keyIndex]
q1 = normalize (theBone.rotation as quat)
q2 = normalize (key.rot as quat)
q3 = normalize (q2 * q1)
pos = theBone.position + key.pos
mat = (q3 as matrix3)
mat.row4 = pos
theBone.localMatrix = mat

if theBone.parentBone != undefined then
(
theBone.worldMatrix = theBone.localMatrix * theBone.parentBone.worldMatrix
)
else --have root
(
theBone.worldMatrix = theBone.localMatrix
)

t = (key.time / 0.033333) -- assuming 30 fps AAACK hard coded number TODO: fix this dummy , lol

animate on
(
at time t
maxBone.transform = theBone.worldMatrix
)
)
else
(
q3 = normalize (theBone.rotation as quat)
pos = theBone.position
mat = (q3 as matrix3)
mat.row4 = pos
theBone.localMatrix = mat

if theBone.parentBone != undefined then
(
theBone.worldMatrix = theBone.localMatrix * theBone.parentBone.worldMatrix
)
else --have root
(
theBone.worldMatrix = theBone.localMatrix
)
)   
--do childBones
for b in theBone.childBones do
(
WalkTreeAnimate b keyIndex
)
)


fn GenerateKeyFrames theBone =
(
--get the biggest keyframe count   
numKeyFrames = 0
keyTime = 0.0

for b in skeletonBones do
(
if b.animationKeys != undefined then
(
if b.animationKeys.count > numKeyFrames then numKeyFrames = b.animationKeys.count
k = b.animationKeys[b.animationKeys.count]
if k.time > keyTime then keyTime = k.time
)
)

for i=1 to numKeyFrames do
(
WalkTreeAnimate theBone i
)

keyTime = keyTime / 0.033333 --assumes 30 fps TODO: fix this read the timers setting

sTime = animationRange.start as float
--check for zero length interval
if sTime >= keyTime then keyTime = animationRange.start + 100
animationRange = interval animationRange.start keyTime
)

fn WalkTreeCreateMaxBones theBone =
(
if theBone.parentBone == undefined then --root
(
tempMatrix = theBone.rotation as matrix3
tempMatrix.row4 = theBone.position   
theBone.localMatrix = tempMatrix
theBone.worldMatrix = theBone.localMatrix

)
else
(
tempMatrix = theBone.rotation as matrix3
tempMatrix.row4 = theBone.position
theBone.localMatrix = tempMatrix
theBone.worldMatrix = theBone.localMatrix * theBone.parentBone.worldMatrix
)

posTo = theBone.endPosition

--if a bone has multiple childBones or if its a tag_ bone ,I'm just making it a blob for now

if theBone.childBones.count != 1 or findString theBone.boneName "tag_" != undefined then
(
boneLength = maxBoneSize
currentBone = BoneSys.CreateBone theBone.worldMatrix.row4 (theBone.worldMatrix.row4 + boneLength * (normalize theBone.worldMatrix.row1)) (normalize theBone.worldMatrix.row3)
)
else
(
currentBone = BoneSys.CreateBone theBone.worldMatrix.row4 (posTo * theBone.worldMatrix) (normalize theBone.worldMatrix.row3)
)

currentBone.Name = theBone.boneName
currentBone.Width = maxBoneSize
currentBone.Height = maxBoneSize

currentBone.setBoneEnable false 0
currentBone.pos.controller = TCB_position ()
currentBone.rotation.controller = TCB_rotation ()


if theBone.parentBone!= undefined then
(
currentBone.parent = getnodebyname theBone.parentName
)

for b in theBone.childBones do
(
WalkTreeCreateMaxBones b
)

)

function GetAttribute xmlElement xmlAttribute =
(
if FINDSTRING xmlElement xmlAttribute == 0 then return "ERROR"

attributePos = FINDSTRING xmlElement xmlAttribute

if attributePos == undefined then return "ERROR"
attributeStartPos = attributePos + xmlAttribute.count + 2

attributeOffset = xmlElement.count - attributeStartPos
if attributeOffset < 0 then return "ERROR"

attributeTmp = SUBSTRING xmlElement attributeStartPos attributeOffset

attributeLength = FINDSTRING attributeTmp "\""
attributeLength = attributeLength - 1
strAttributeValue = SUBSTRING attributeTmp 1 attributeLength

strAttributeValue
)

fn OpenOgreSkeletonFileAnimOnly file_name =
(

--clear all old keys if there

for b in skeletonBones do
(
if b.animationKeys != undefined then
(
b.animationKeys = undefined
)

)

if (file_Name != undefined ) then
(
file_stream = openFile file_Name
if file_stream != undefined then
(
--print "File Stream opened"
strLine = readLine file_stream   

-- Check if this file in a correct format
if strLine == "<skeleton>" then
(
lAnimation = TAnimation()
lAnimation.boneFrames = #()
append gAnimations lAnimation
-- Read the bone stuff
strLine = readLine file_stream -- <bones>
if trimleft strLine == "<bones>" then
(
strLine = readLine file_stream -- <bone>


while trimleft strLine != "</bones>" do
(   
--boneID = GetAttribute strLine "id" as integer
lBone = TBoneframe()
lBone.boneName = GetAttribute strLine "name"
if lBone == undefined then --this will happen if the animation bones dont match the base pose bones
(
lBone = TBoneframe() --TODO: bad form , fix this
messagebox "Bone not found: Do you have an animation skeleton mismatch?"

)

strLine = readLine file_stream -- <position>
posX = GetAttribute strLine " x" as float
posY = GetAttribute strLine " y" as float
posZ = GetAttribute strLine " z" as float

lBone.position = point3 (posX*maxScale) (posY*maxScale) (posZ*maxScale)

strLine = readLine file_stream -- <rotation>
rot_angle = GetAttribute strLine "angle" as float

strLine = readLine file_stream -- <axis>
rotX = GetAttribute strLine " x" as float
rotY = GetAttribute strLine " y" as float
rotZ = GetAttribute strLine " z" as float

rot = Point3 rotX rotY rotZ

lBone.rotation = angleaxis ((180/pi)*rot_angle) -rot --had to neg rot axis for max   

strLine = readLine file_stream -- </rotation>
strLine = readLine file_stream -- </bone>
strLine = readLine file_stream -- <bone>

append lAnimation.boneFrames lBone
)


)
-- Read the parent child relation
strLine = readLine file_stream -- <bonehierarchy>
if trimleft strLine == "<bonehierarchy>" then
(

strLine = readLine file_stream
while trimleft strLine != "</bonehierarchy>" do
(   
strLine = readLine file_stream
)
)


-- Read animations
strLine = readLine file_stream -- <animations>
if trimleft strLine == "<animations>" then
(

strLine = readLine file_stream -- <animation>
animName = GetAttribute strLine " name"
animLength = GetAttribute strLine " length" as float

lAnimation.animName = animName
lAnimation.animLength = animLength



strLine = readLine file_stream --<tracks>
if trimleft strLine == "<tracks>" then
(
strLine = readLine file_stream --<track>

while trimleft strLine != "</tracks>" do
(   

boneName = GetAttribute strLine " bone"

--print boneName
theBone = GetBoneFrameByName lAnimation.boneFrames boneName

if theBone == undefined then --this will happen if the animation bones dont match the base pose bones
(
theBone = TBoneFrame() --TODO: bad form , fix this
messagebox "Bone not found: Do you have an animation skeleton mismatch?"
)

theBone.animationKeys = #()

strLine = readLine file_stream --<keyframes>

strLine = readLine file_stream --<keyframe>

while trimleft strLine != "</keyframes>" do
(
local kFrame = TKeyframe()

kFrame.time = GetAttribute strLine " time" as float
--at time keyTime
strLine = readLine file_stream --<translate>
posX = GetAttribute strLine " x" as float
posY = GetAttribute strLine " y" as float
posZ = GetAttribute strLine " z" as float
strLine = readLine file_stream --<rotate>
keyAngle = GetAttribute strLine " angle" as float
strLine = readLine file_stream --<axis>
rotX = GetAttribute strLine " x" as float
rotY = GetAttribute strLine " y" as float
rotZ = GetAttribute strLine " z" as float
strLine = readLine file_stream --</rotate>
strLine = readLine file_stream --</keyframe>
strLine = readLine file_stream --<keyframe>

rot = Point3 rotX rotY rotZ

kFrame.pos = Point3 (posX*maxScale) (posY*maxScale) (posZ*maxScale)

kFrame.rot = angleaxis ((180/pi)*keyAngle) -rot --again with the negating

append theBone.animationKeys kFrame

)
strLine = readLine file_stream --</track>
strLine = readLine file_stream --<track>

)
)
)

--set bones to bone frames
for b in lAnimation.boneFrames do
(
sb = GetBoneByName b.boneName

sb.position = b.position
sb.rotation = b.rotation
sb.animationKeys = b.animationKeys

)
gc light:true
--clear all prev keyframes

for b in skeletonBones do
(
maxBone = getNodeByName b.boneName
deleteKeys maxBone.position.controller #allKeys
deleteKeys maxBone.rotation.controller #allKeys
deleteKeys maxBone.scale.controller #allKeys
maxBone.transform = matrix3 1
)

SetBasePose rootBone
--generate the keyframes

if rootBone == undefined then
(
messagebox "Can't find root bone!"
)
GenerateKeyFrames rootBone

--clear root rotation
if clearRootRotation then
(
aa = angleAxis 90 [1,0,0]
rNode = getNodeByName rootBone.boneName
rotate rNode aa
)

)
else
(
messagebox "SKELETON file is not in the proper format !"

)

close file_stream
--print "File Stream Closed"
--print "Success !"
)

)
return animName
)
fn OpenOgreSkeletonFile file_name =
(

if (file_Name != undefined ) then
(
file_stream = openFile file_Name
if file_stream != undefined then
(
strLine = readLine file_stream   

-- Check if this file in a correct format
if strLine == "<skeleton>" then
(
-- Read the bone stuff
strLine = readLine file_stream -- <bones>
if trimleft strLine == "<bones>" then
(
strLine = readLine file_stream -- <bone>


while trimleft strLine != "</bones>" do
(
local lBone = TBone ()

lBone.boneID = GetAttribute strLine "id" as integer
lBone.boneName = GetAttribute strLine "name"

strLine = readLine file_stream -- <position>
posX = GetAttribute strLine " x" as float
posY = GetAttribute strLine " y" as float
posZ = GetAttribute strLine " z" as float

lBone.position = point3 (posX*maxScale) (posY*maxScale) (posZ*maxScale)

strLine = readLine file_stream -- <rotation>
rot_angle = GetAttribute strLine "angle" as float

strLine = readLine file_stream -- <axis>
rotX = GetAttribute strLine " x" as float
rotY = GetAttribute strLine " y" as float
rotZ = GetAttribute strLine " z" as float

rot = Point3 rotX rotY rotZ

lBone.rotation = angleaxis ((180/pi)*rot_angle) -rot --had to neg rot axis for max

endPosX = posX + maxBoneSize
endPosY = posY
endPosZ = posZ

lBone.endPosition = point3 endPosX endPosY endPosZ

strLine = readLine file_stream -- </rotation>
strLine = readLine file_stream -- </bone>
strLine = readLine file_stream -- <bone>

append skeletonBones lBone
)
nbrBones = skeletonBones.count
--print nbrBones

)
-- Read the parent child relation
strLine = readLine file_stream -- <bonehierarchy>
if trimleft strLine == "<bonehierarchy>" then
(

strLine = readLine file_stream
while trimleft strLine != "</bonehierarchy>" do
(
boneName = GetAttribute strLine " bone"
parentName = GetAttribute strLine " parent"

-- find the parent bone and attach it to it
nbrParentBones = nbrBones
for b = 1 to nbrBones do
(
if skeletonBones[b].boneName == boneName then
(
skeletonBones[b].parentName = parentName

-- Get the xPos yPos zPos of the parent bone to put it as a end pos of this bone
for pb = 1 to nbrParentBones do
(
if skeletonBones[pb].boneName == parentName then
(
--skeletonBones[b].parentIndex = pb
skeletonBones[pb].endPosition = skeletonBones[b].position

exit -- no need to check the rest of the bones
)
)

exit -- no need to continue looping
)

)

strLine = readLine file_stream

)
)

-- Create the bones


--set up the bone hierarchy
BuildBoneTree()
--build the maxbones
WalkTreeCreateMaxBones rootBone

-- Read animations
strLine = readLine file_stream -- <animations>
if trimleft strLine == "<animations>" then
(

strLine = readLine file_stream -- <animation>
animName = GetAttribute strLine " name"
animLength = GetAttribute strLine " length" as float

strLine = readLine file_stream --<tracks>
if trimleft strLine == "<tracks>" then
(
strLine = readLine file_stream --<track>

while trimleft strLine != "</tracks>" do
(   
startframe = 0
--format "should have track %\n" strLine

boneName = GetAttribute strLine " bone"

--print boneName

theBone = GetBoneByName boneName

theBone.animationKeys = #()

strLine = readLine file_stream --<keyframes>

strLine = readLine file_stream --<keyframe>

while trimleft strLine != "</keyframes>" do
(
local kFrame = TKeyframe()

kFrame.time = GetAttribute strLine " time" as float
--at time keyTime
strLine = readLine file_stream --<translate>
posX = GetAttribute strLine " x" as float
posY = GetAttribute strLine " y" as float
posZ = GetAttribute strLine " z" as float
strLine = readLine file_stream --<rotate>
keyAngle = GetAttribute strLine " angle" as float
strLine = readLine file_stream --<axis>
rotX = GetAttribute strLine " x" as float
rotY = GetAttribute strLine " y" as float
rotZ = GetAttribute strLine " z" as float
strLine = readLine file_stream --</rotate>
strLine = readLine file_stream --</keyframe>
strLine = readLine file_stream --<keyframe>

rot = Point3 rotX rotY rotZ

kFrame.pos = Point3 (posX*maxScale) (posY*maxScale) (posZ*maxScale)

kFrame.rot = angleaxis ((180/pi)*keyAngle) -rot --again with the negating

append theBone.animationKeys kFrame

)
strLine = readLine file_stream --</track>
strLine = readLine file_stream --<track>

)
)
)

--set skeleton to first frame of animation (or base pose if no animation)
SetBasePose rootBone

)
else
(
print "File is not in the proper format !"

)

close file_stream
--print "File Stream Closed"
--print "Success !"
)

)
)

fn SetUpSkin aMesh =
(
-- generate skin modifier

aSubMesh = aMesh.maxMesh

max modify mode

select aSubMesh

skinMod = skin ()

if skeletonBones == undefined then
(
messagebox "YOU MUST LOAD THE BASE POSE SKELETON FOR THIS MESH FIRST!! loading with no bones ..."

)
else
(

--load all the bones into the skin modifier

if skeletonBones.count > 0 then
(
addModifier aSubMesh skinMod
for i = 1 to skeletonBones.count do
(
maxbone = getnodebyname skeletonBones[i].boneName
if i != skeletonBones.count then
skinOps.addBone skinMod maxbone 0
else
skinOps.addBone skinMod maxbone 1
)
)

--collect all the weights and bone mappings for each vertex

modPanel.setCurrentObject skinMod

if aMesh.boneWeightsArray != undefined then
(

for i=1 to aMesh.vertexArray.count do
(
bi = #() --bone index array
wv = #() --weight value array

vIndex = i

for wc = 1 to aMesh.boneWeightsArray.count do
(
w = aMesh.boneWeightsArray[wc]
--if weight vertex index equals current vertex array index
if (w.vindex+1) == i then
(
weight = w.weight
bindex = w.bindex + 1 --the ogre xml stores array indices starting at 0 max needs 1

append bi bindex
append wv weight
)

)
--set all weights for this vertex at once
skinOps.ReplaceVertexWeights skinMod i bi wv

)
)
)
max create mode
)

-- 2. Open the file for reading
fn GetOgreMeshFile file_name =
(
if file_Name != undefined then
(
file_stream = openFile file_Name
filePath = getFilenamePath file_name
if file_stream != undefined then
(
strLine = readLine file_stream   

-- 3. Check if this file in a correct format
if strLine == "<mesh>" then
(

-- 4. Keep reading until it hits the closing mesh tag
while strLine != "</mesh>" do
(
strLine = READLINE file_stream
trimmed = TRIMLEFT strLine
--------------------------------------------------------------------   
if SUBSTRING trimmed 1 16 == "<sharedgeometry " then
(
nbrVertexes = GetAttribute trimmed "vertexcount"
nbrVertexes = nbrVertexes as integer

-- Get the vertex data

sharedVertices.count = nbrVertexes
sharedNormals.count = nbrVertexes
sharedTextureUV.count = nbrVertexes

strLine = READLINE file_stream -- <vertexBuffer>

for v = 1 to nbrVertexes do
(
strLine = READLINE file_stream -- <vertex>
strPosition = READLINE file_stream -- <position>
strNormals = READLINE file_stream -- <normals>

strPosition = TRIMLEFT strPosition
strNormals = TRIMLEFT strNormals

p1 = GetAttribute strPosition "x"
p2 = GetAttribute strPosition "y"
p3 = GetAttribute strPosition "z"   

p1 = p1 as float
p2 = p2 as float
p3 = p3 as float

sharedVertices[v] = POINT3 (p1*maxScale) (p2*maxScale) (p3*maxScale)

p1 = GetAttribute strNormals "x"
p2 = GetAttribute strNormals "y"
p3 = GetAttribute strNormals "z"   

p1 = p1 as float
p2 = p2 as float
p3 = p3 as float

sharedNormals[v] = POINT3 p1 p2 p3

strLine = READLINE file_stream -- </vertex>

-- check if UV coord are on vertex level
if (Findstring strLine "<texcoord" != undefined) then
(
strCoord = TRIMLEFT strLine

tu = GetAttribute strCoord "u"
tv = GetAttribute strCoord "v"

tu = tu as float
tv = tv as float --1 - tv as float

sharedTextureUV[v] = POINT3 tu tv 0.0

strLine = READLINE file_stream -- </vertex>
)   
)

strLine = READLINE file_stream -- </vertexBuffer>

-- Read the texture coordinates

strLine = READLINE file_stream -- <vertexbuffer texture_coord>
if (findstring strLine "<vertexbuffer texture_coord" != undefined) then
(

for t = 1 to nbrVertexes do
(
strLine = READLINE file_stream -- <vertex>
strCoord = READLINE file_stream -- <uv>
strCoord = TRIMLEFT strCoord

tu = GetAttribute strCoord "u"
tv = GetAttribute strCoord "v"

tu = tu as float
tv = 1 - tv as float

sharedTextureUV[t] = POINT3 tu tv 0.0

strLine = READLINE file_stream -- </vertex>
)
)

strLine = READLINE file_stream -- </vertexbuffer texture_coord>

)
--------------------------------------------------------------------
-- 5. This requires a new 3D mesh object
if (SUBSTRING trimmed 1 9 == "<submesh ") then
(
theSubMesh = TSubMesh()

-- 6. Get the mesh name
theSubMesh.meshName = GetAttribute trimmed "material"
theSubMesh.usesShared = GetAttribute trimmed "usesharedvertices"
--print theSubMesh.meshName

strLine = READLINE file_stream
trimmed = TRIMLEFT strLine

-- 7. Get the number of faces
theSubMesh.numFaces = GetAttribute trimmed "count"
theSubMesh.numFaces = theSubMesh.numFaces as number

theSubMesh.faceArray = #()
theSubMesh.faceArray.count = theSubMesh.numFaces


if theSubMesh.usesShared == "true" then
(
--format "USES SHARED assigning global arrays %\n" theSubMesh.usesShared
theSubMesh.boneWeightsArray = sharedBoneWeights
theSubMesh.vertexArray = sharedVertices
theSubMesh.normalsArray = sharedNormals
theSubMesh.uvArray = sharedTextureUV
)
else
(
theSubMesh.boneWeightsArray = #()
)

-- 8. Get the face data
for f = 1 to theSubMesh.numFaces do
(
strLine = READLINE file_stream
trimmed = TRIMLEFT strLine

v1 = GetAttribute trimmed "v1"
v2 = GetAttribute trimmed "v2"
v3 = GetAttribute trimmed "v3"
v1 = v1 as float + 1
v2 = v2 as float + 1
v3 = v3 as float + 1
theSubMesh.faceArray[f] = POINT3 v1 v2 v3
)
strLine = READLINE file_stream

-- 9. Get the number of vertices/normals
strLine = READLINE file_stream -- <geometry>
trimmed = TRIMLEFT strLine

----------------------------------------------------------------------------

theSubMesh.numVertices = GetAttribute trimmed "vertexcount"
theSubMesh.numVertices = theSubMesh.numVertices as integer

if theSubMesh.usesShared == "false" then
(

-- 10. Get the vertex data
theSubMesh.vertexArray = #()
theSubMesh.normalsArray = #()
theSubMesh.uvArray = #()

theSubMesh.vertexArray.count = theSubMesh.numVertices
theSubMesh.normalsArray.count = theSubMesh.numVertices
theSubMesh.uvArray.count = theSubMesh.numVertices

strLine = READLINE file_stream -- <vertexBuffer>

for v = 1 to theSubMesh.numVertices do
(
strLine = READLINE file_stream -- <vertex>
strPosition = READLINE file_stream -- <position>
strNormals = READLINE file_stream -- <normals>

strPosition = TRIMLEFT strPosition
strNormals = TRIMLEFT strNormals

p1 = GetAttribute strPosition "x"
p2 = GetAttribute strPosition "y"
p3 = GetAttribute strPosition "z"   

p1 = p1 as float
p2 = p2 as float
p3 = p3 as float

theSubMesh.vertexArray[v] = POINT3 (p1*maxScale) (p2*maxScale) (p3*maxScale)

p1 = GetAttribute strNormals "x"
p2 = GetAttribute strNormals "y"
p3 = GetAttribute strNormals "z"   

p1 = p1 as float
p2 = p2 as float
p3 = p3 as float

theSubMesh.normalsArray[v] = POINT3 p1 p2 p3

strLine = READLINE file_stream -- </vertex>

--check for uv coord at vertex level
if (Findstring strLine "<texcoord" != undefined) then
(
strCoord = TRIMLEFT strLine

tu = GetAttribute strCoord "u"
tv = GetAttribute strCoord "v"

tu = tu as float
tv = 1 - tv as float

theSubMesh.uvArray[v] = POINT3 tu tv 0.0

strLine = READLINE file_stream -- </vertex>
)   

)
strLine = READLINE file_stream -- </vertexBuffer>

-- 11. Read the texture coordinates if they are there

strLine = READLINE file_stream -- <vertexbuffer texture_coord>
if (findstring strLine "<vertexbuffer texture_coord" != undefined) then
(

for t = 1 to theSubMesh.numVertices do
(
strLine = READLINE file_stream -- <vertex>
strCoord = READLINE file_stream -- <uv>
strCoord = TRIMLEFT strCoord

tu = GetAttribute strCoord "u"
tv = GetAttribute strCoord "v"

tu = tu as float
tv = 1 - tv as float

theSubMesh.uvArray[t] = POINT3 tu tv 0.0

strLine = READLINE file_stream -- </vertex>
)   
strLine = READLINE file_stream -- </vertexbuffer >
)

--bone assignments
strLine = READLINE file_stream -- </geometry> / </sharedgeometry

strLine = READLINE file_stream -- <boneassignments>

ba = TRIMLEFT strLine

--format "HAVE <boneassignments> ???? ->%\n" ba

if ba == "<boneassignments>" then
(

strLine = READLINE file_stream -- <vertexboneassignment ... >

while (TRIMLEFT strLine) != "</boneassignments>" do
(
w = TWeight()

strLine = TRIMLEFT strLine

w.vindex = GetAttribute strLine "vertexindex" as integer
w.bindex = GetAttribute strLine "boneindex" as integer
w.weight = GetAttribute strLine "weight" as float

append theSubMesh.boneWeightsArray w

strLine = READLINE file_stream
)
)
----------------------------------------------------------------------------


)


-- 12. Build the mesh



theSubMesh.maxMesh = MESH VERTICES:theSubMesh.VertexArray FACES:theSubMesh.faceArray TVERTS:theSubMesh.uvArray
theSubMesh.maxMesh.Name = theSubMesh.meshName

UPDATE theSubMesh.maxMesh

--13. Build the faces
BUILDTVFACES theSubMesh.maxMesh FALSE

--14. Set the UVW coordinates to the faces.
for i = 1 to theSubMesh.faceArray.count do
(
SETTVFACE theSubMesh.maxMesh i theSubMesh.faceArray[i]
)
UPDATE theSubMesh.maxMesh

append subMeshArray theSubMesh

--try to find texture
tokens = filterString theSubMesh.meshName "/"
texNamePrefix = tokens[2]
if texNamePrefix == undefined then texNamePrefix = theSubMesh.meshName

--check for 'shadow'
strIndex = findString texNamePrefix "_shadow"
if strIndex != undefined then --got shadow
(
newStr = subString texNamePrefix 1 (strIndex-1)   
texNamePrefix = newStr
)
texNameFinal = filePath + texNamePrefix + ".dds"
if doesFileExist texNameFinal then
(
newMat = standard showInviewPort:true
bt = BitmapTexture()
bt.filename = texNameFinal
newMat.diffuseMap = bt
theSubMesh.maxMesh.material = newMat

)
else -- try .png
(
texNameFinal = filePath + texNamePrefix + ".png"
if doesFileExist texNameFinal then
(
newMat = standard showInviewPort:true
bt = BitmapTexture()
bt.filename = texNameFinal
newMat.diffuseMap = bt
theSubMesh.maxMesh.material = newMat

)
else -- try body.png
(
texNameFinal = filePath + "body.png"
if doesFileExist texNameFinal then
(
newMat = standard showInviewPort:true
bt = BitmapTexture()
bt.filename = texNameFinal
newMat.diffuseMap = bt
theSubMesh.maxMesh.material = newMat

)
else -- .tga
(
texNameFinal = filePath + texNamePrefix + ".tga"
if doesFileExist texNameFinal then
(
newMat = standard showInviewPort:true
bt = BitmapTexture()
bt.filename = texNameFinal
newMat.diffuseMap = bt
theSubMesh.maxMesh.material = newMat

)

)
)
)

)

if TRIMLEFT strLine == "<boneassignments>" then
(
strLine = READLINE file_stream -- <vertexboneassignment ... >

while (TRIMLEFT strLine) != "</boneassignments>" do
(
w = TWeight()

strLine = TRIMLEFT strLine

w.vindex = GetAttribute strLine "vertexindex" as integer
w.bindex = GetAttribute strLine "boneindex" as integer
w.weight = GetAttribute strLine "weight" as float

append sharedBoneWeights w

strLine = READLINE file_stream
)

)


)


for i=1 to subMeshArray.count do
(
if subMeshArray[i].boneWeightsArray.count > 0 then
SetUpSkin subMeshArray[i]
)

)
else
(
print "MESH File is not in the correct format."
)
close file_stream
)
)

)

fn SwapAnimations aName=
(
if rootBone != undefined then
(
for a in gAnimations do
(
if a.animName == aName then
(
--set bones to bone frames

for b in skeletonBones do
(
b.animationKeys = undefined

)

for b in a.boneFrames do
(
sb = GetBoneByName b.boneName

sb.position = b.position
sb.rotation = b.rotation
sb.animationKeys = b.animationKeys

)

--clear all prev keyframes

for b in skeletonBones do
(
maxBone = getNodeByName b.boneName
deleteKeys maxBone.position.controller #allKeys
deleteKeys maxBone.rotation.controller #allKeys
deleteKeys maxBone.scale.controller #allKeys
maxBone.transform = matrix3 1
)

SetBasePose rootBone
--generate the keyframes

GenerateKeyFrames rootBone

--clear root rotation
if clearRootRotation then
(
aa = angleAxis 90 [1,0,0]
rNode = getNodeByName rootBone.boneName
rotate rNode aa
)
)

)
)
else
messagebox "root bone not found!"

gc light:true
)

rollout ogreImportRollout "Ogre Torchlight Importer"
(
local animList
-- copyright label
label Label1 "Version 0.02"
label Label2 "\xA9 2009 Graboi"
label Label3 "graboi008@yahoo.com"

Group "Settings"
(
checkbox ChkClearRootRotation "Clear Root Rotation" checked:clearRootRotation
spinner SpnMeshScale "Mesh scale" range:[0.01,1000,maxScale] type:#float scale:0.10 align:#center

edittext resPath "Resource Path" text:pakPath   labelOnTop:true readOnly:true   
button BtnResourcePath "Set Resource Path" enabled:true
)


Group "MESH.xml Import"
(
button BtnImportMesh "Import Mesh ..." enabled:true
)

Group "SKELETON.xml Import"
(
button BtnImportSkeleton "Import Animation ..." enabled:false
)

Group "Animation"
(
listbox animationList "Tracks"
)

on animationList doubleClicked itm do
(
SwapAnimations animationList.items[itm]
)
on BtnResourcePath pressed do
(

res = getSavePath caption:"Set Resource Path"
if res != undefined then
(
resPath.text = res
pakPath = res + "/*.MESH.xml"
)

)

-- event handlers

on BtnImportMesh pressed do
(

MeshFileName = getOpenFileName types:"Ogre Mesh (*.MESH.xml)|*.MESH.xml|All (*.*)|*.*|" filename:pakPath

if MeshFileName != undefined then
(
if DoesFileExist MeshFileName then
(
--get the skeleton file
sfName = filenameFromPath MeshFileName
tokens = filterString sfName "."
sfName = tokens[1] + ".SKELETON.xml"
sfPath = getFilenamePath MeshFileName
sfName = sfPath + sfName

if DoesFileExist sfName then
(
with undo off
(
disableSceneRedraw()

OpenOgreSkeletonFile sfName

GetOgreMeshFile MeshFileName

enableSceneRedraw()
redrawViews()
)
BtnImportMesh.enabled = false
BtnImportSkeleton.enabled = true
)
else
messagebox "Cant find base skeleton file"

)

)

)

on BtnImportSkeleton pressed do
(
AnimFileName = getOpenFileName types:"Ogre Skeleton (*SKELETON.xml)|*SKELETON.xml|All (*.*)|*.*|"

if AnimFileName != undefined then
(
if DoesFileExist AnimFileName then
(
anim = OpenOgreSkeletonFileAnimOnly AnimFileName
--lAnimation.animName
if animList == undefined then animList = #()
append animList anim
ogreImportRollout.animationList.items = animList
ogreImportRollout.animationList.selection = ogreImportRollout.animationList.items.count

)

)
)

on SpnMeshScale changed val do
(
maxScale = val
maxBoneSize = 0.04 * maxScale
)
on ChkClearRootRotation changed state do clearRootRotation = state

on ogreImportRollout close do
(
skeletonBones = undefined
sharedVertices = undefined
sharedTextureUV = undefined
sharedNormals = undefined
sharedBoneWeights = undefined
subMeshArray = undefined
gAnimations = undefined
gc()

)

)
-- Create plugin window
if ogreImportFloater != undefined do closeRolloutFloater ogreImportFloater   -- close old window if visible
ogreImportFloater = newRolloutFloater "OgreXML Torchlight Import" 250 550 30 100 -- create new window

-- add controls
addRollout ogreImportRollout ogreImportFloater
Image

Mods:
Arkham's Armory (TL2) | Lego Wizard pet (TL1)

Check out the Torchlight fan group #The-Lure-of-Ember on dA!
User avatar
Arkham
 
Posts: 2842
Joined: Tue Jan 19, 2010 12:20 am
Location: Seattle, WA

Re: [Tutorial] Importing Diablo III models into Torchlight

Postby SparrowHusky » Thu Aug 30, 2012 1:02 am

THANK YOU! Thank you very much good sir Arkham. :)
SparrowHusky
 
Posts: 17
Joined: Wed Aug 29, 2012 8:02 am


Re: [Tutorial] Importing Diablo III models into Torchlight

Postby SparrowHusky » Thu Aug 30, 2012 8:59 am

Ah yes, but thank you just the same. :)
SparrowHusky
 
Posts: 17
Joined: Wed Aug 29, 2012 8:02 am

Re: [Tutorial] Importing Diablo III models into Torchlight

Postby mrbison » Mon Jan 07, 2013 8:44 am

hi all , i get one error on run plugin

3ds max 2009

-- Type error: Call needs function or class, got: undefined

any correction?
User avatar
mrbison
 
Posts: 3
Joined: Mon Jan 07, 2013 8:39 am

Re: [Tutorial] Importing Diablo III models into Torchlight

Postby lorm » Thu Feb 21, 2013 6:06 pm

mrbison how did you make out with 3ds? Did you get it to work? Does the TL1 method work for TL2? I know some Chinese did some models but I would just like to hear from someone that they got any method to work.
Majority rules? If 10 monkeys told you to jump off of a cliff, would you do it just because there are more of them then there are you?
User avatar
lorm
 
Posts: 59
Joined: Tue Nov 06, 2012 6:27 pm
Location: The link leads to Nightmare Mod

Previous

Return to Torchlight Mod Discussion

Who is online

Users browsing this forum: No registered users and 6 guests