Page 5 of 7

Re: Dragon Age 2 (PC)

Posted: Mon Apr 04, 2011 3:47 am
by lpss
I still can't get the hair/beard meshes with UV maps on Blender... :[
Does anyone know a way to do it? I'm using the Blender 2.49 script as I already had Blender 2.49

Re: Dragon Age 2 (PC)

Posted: Wed Apr 06, 2011 12:27 am
by figuresculptor
lpss wrote:I still can't get the hair/beard meshes with UV maps on Blender... :[
Does anyone know a way to do it? I'm using the Blender 2.49 script as I already had Blender 2.49
lpss:

The same problem exists with the 2.5.6 script - I've actually combed through the beard and hair, and it just looks like all the UVs are set to 0,0 or 1,0. I've looked through the vertex data for other potential UV data, and found nothing. I'm not sure what's going on with the hair or beards, but it's not anything you're doing - it is the script.

Re: Dragon Age 2 (PC)

Posted: Wed Apr 06, 2011 12:35 am
by figuresculptor
Blender 2.57, which is the Release Candidate for the 2.5 branch, was posted a few days ago… and broke compatibility with most scripts.

I've updated my 2.56 script to work with 2.57. I haven't had time to add the armature parsing yet, but I did add an option to rotate the object to face front.

NB: For some reason, this isn't working correctly as an addon right now. If you open the script in Blender and run it, it will add a menu item. When I've figured out why it doesn't work as an addon, I'll post the fixed version.

Code: Select all

bl_addon_info = {
	"name": "Import Dragon Age 2 Mesh files (.msh)",
	"author": "FigureSculptor",
	"version": (2, 1),
	"blender": (2, 5, 7),
	"api": 35622,
	"location": "File > Import ",
	"description": "Import Dragon Age 2 Mes (.msh)",
	"warning": "",
	"wiki_url": "",
	"tracker_url": "",
	"category": "Import-Export"}

"""
Version': '1.0' 

This is a straight port of the 3DS Max Script from this forum
posting:

http://forum.xentax.com/viewtopic.php?f=16&t=6119&hilit=dragon+age+2

This version is based on the script posted with this timestamp

Posted: Mon Mar 14, 2011 3:22 am 

All credit to chrrox for figuring the format out.

"""

import bpy
import mathutils
import os
import sys
import string
import math
import re
from string import *
from struct import *
from math import *
import mathutils
from bpy.props import *


DEBUGLOG = False
LONGSIZE = 4
FLOATSIZE = 4
HALFFLOATSIZE = 2
SHORTSIZE = 2

def unpack_list(list_of_tuples):
	l = []
	for t in list_of_tuples:
		l.extend(t)
	return l

def halfToFloatPrivate(h):
	s = int((h >> 15) & 0x00000001)		# sign
	e = int((h >> 10) & 0x0000001f)		# exponent
	f = int(h &			0x000003ff)		# fraction

	if e == 0:
		if f == 0:
			return int(s << 31)
		else:
			while not (f & 0x00000400):
				f <<= 1
				e -= 1
			e += 1
			f &= ~0x00000400
	elif e == 31:
		if f == 0:
			return int((s << 31) | 0x7f800000)
		else:
			return int((s << 31) | 0x7f800000 | (f << 13))

	e = e + (127 -15)
	f = f << 13

	return int((s << 31) | (e << 23) | f)

def halfToFloat(h):
	result = halfToFloatPrivate(h)
	str = pack('I',result)
	f = unpack('f', str)
	return f[0]
	
def mshImport(infile, props):
	global DEBUGLOG
	print ("--------------------------------------------------")
	print ("---------SCRIPT EXECUTING PYTHON IMPORTER---------")
	print ("--------------------------------------------------")
	print ("Importing file: ", infile)
	
	mshfile = open(infile,'rb')
	if (DEBUGLOG):
		logpath = infile.replace(".msh", ".txt")
		print("logpath:",logpath)
		logf = open(logpath,'w')
		
	def printlog(strdata):
		if (DEBUGLOG):
			logf.write(strdata + "\n")

	basename = os.path.basename(infile)	
	
	printlog("basename:" + basename)
	
	mshfile.seek(0x1A0)
	baseoff = 0x1A0
	

	namebase, garbage, unkbase, vertbase, facebase, garbage1, garbage2, meshcount = unpack('<8l', mshfile.read(8*LONGSIZE))

	printlog("baseoff: " + str(baseoff))
	printlog("unkbase: " + str(unkbase))
	printlog("vertbase: " + str(vertbase))
	printlog("facebase: " + str(facebase))
	printlog("meshcount: " + str(meshcount))
	
	vertSizeArray = []
	vertCountArray = []
	faceCountArray = []
	vertPosArray = []
	facePosArray = []
	
	for i in range(meshcount):
		printlog("assessing mesh " + str(i))
		float01, float02, float03, float04, float11, float12, float13, float14, float21, float22, float23, float34 = unpack('<12f', mshfile.read(12*FLOATSIZE))
		unk01, vertSize, vertCount, faceCount, vertPos, facePos, unk2, long01, long02, long03, long04, vertCount2 = unpack('<12l', mshfile.read(12*LONGSIZE))
		printlog("\tvertsize: " + str(vertSize))
		printlog("\tvertCount: " + str(vertCount))
		printlog("\tfaceCount: " + str(faceCount))
		printlog("\tvertPos: " + str(vertPos))
		printlog("\tfacePos: " + str(facePos))
		vertSizeArray.append(vertSize)
		vertCountArray.append(vertCount)
		faceCountArray.append(faceCount)
		vertPosArray.append(vertPos)
		facePosArray.append(facePos)
	
	faceStart = baseoff + facebase + 4
	vertStart = baseoff + vertbase + 4
	nameStart = baseoff + namebase
	unkStart = baseoff + unkbase
	
	if (DEBUGLOG):
		printlog("faceStart: " + str(faceStart))
		printlog("vertStart: " + str(vertStart))
		printlog("nameStart: " + str(nameStart))
		printlog("unkStart: " + str(unkStart))
	
	for a in range(meshcount):
		me_ob = bpy.data.meshes.new(basename + str(a))
		printlog(("New Mesh = " + me_ob.name))
		vertArray = []
		uvArray = []
		normalArray = []
		faceArray = []
		printlog("===Offset = " + str(vertStart + vertPosArray[a]))
		printlog("===vertStrt = " + str(vertStart))
		printlog("===vertPos[a] = " + str(vertPosArray[a]))
		mshfile.seek(vertStart + vertPosArray[a])
		for b in range(vertCountArray[a]):
			data = mshfile.read(3*FLOATSIZE)
			vx, vy, vz = unpack('<3f', data)
			bytesOfUnknown = (vertSizeArray[a] - 16)
			unknown = mshfile.read(bytesOfUnknown)
			tu_h = unpack('H', mshfile.read(HALFFLOATSIZE))
			tv_h = unpack('H', mshfile.read(HALFFLOATSIZE))
			tu = halfToFloat(tu_h[0])
			tv = halfToFloat(tv_h[0])
			vertArray.extend([(vx, vy, vz)])
			uvArray.extend([(tu, tv)])
	
		printlog("facePosArray: " + str(facePosArray[a]))
		mshfile.seek(faceStart + facePosArray[a] * 2)
		faceLen = faceCountArray[a]
		
		printlog("faceCountArray length: " + str(faceLen))
		
		if (faceLen > 0):
			faceLen = faceLen / 3
		else:
			faceLen = 0
		printlog("facelen: " + str(faceLen))
		
		faceUVArray = []
		
		for b in range(int(faceLen)):
			f1, f2, f3 = unpack('<3h', mshfile.read(3*SHORTSIZE))
			if (f1 < len(vertArray) and f2 < len(vertArray) and f3 < len(vertArray)):
				faceArray.extend([f1, f2, f3, 0])
				faceUVArray.extend([(uvArray[f1], uvArray[f2], uvArray[f3])])
			#printlog("Adding array:" + str(f1) + ", " + str(f2) + ", " + str(f3))
			
		printlog("vertArray length: " + str(len(vertArray)))
		printlog("faceArray length: " + str(len(faceArray)))
		me_ob.vertices.add(len(vertArray))
		me_ob.faces.add(len(faceArray)//4)
		me_ob.vertices.foreach_set("co", unpack_list(vertArray))
		me_ob.faces.foreach_set("vertices_raw", faceArray)
		me_ob.faces.foreach_set("use_smooth", [False] * len(me_ob.faces))
		
		texture = []
		texturename = basename + "_tex_" + str(a)
		if (len(faceUVArray) > 0):
			uvtex = me_ob.uv_textures.new() #add one uv texture
			uvtex.name = "Imported UV"
			for i, face in enumerate(me_ob.faces):
				blender_tface= uvtex.data[i] #face
				blender_tface.uv1 = faceUVArray[i][0] #uv = (0,0)
				blender_tface.uv2 = faceUVArray[i][1] #uv = (0,0)
				blender_tface.uv3 = faceUVArray[i][2] #uv = (0,0)
			texture.append(uvtex)
		
		materialname = "mat"
		materials = []

		matdata = bpy.data.materials.new(materialname)
		matdata.diffuse_color=(float(0.04),float(0.08),float(0.44))#blue color
		
		texdata = None
		texIndex = len(bpy.data.textures) - 1
		if (texIndex >= 0):
			texdata = bpy.data.textures[len(bpy.data.textures)-1]
			if (texdata != None):
				texdata.name = "texturelist1"
				matdata.active_texture = texdata
		materials.append(matdata)
		for material in materials:
			#add material to the mesh list of materials
			me_ob.materials.append(material)
			
		me_ob.update()
		
		obmesh = bpy.data.objects.new(basename,me_ob)
		bpy.context.scene.objects.link(obmesh)
		if props.rotate_z_180:
			mat_z180 = mathutils.Matrix.Rotation(math.pi, 4, 'Z')
			me_ob.transform(mat_z180)
		bpy.context.scene.update()
	
def getInputFilename(filename, props):
	checktype = filename.split('\\')[-1].split('.')[1]
	print ("------------",filename)
	if checktype.upper() != 'MSH':
		print ("  Selected file = ",filename)
		raise (IOError, "The selected input file is not a *.msh file")
	mshImport(filename, props)

class IMPORT_OT_dragonage_mesh(bpy.types.Operator):
	'''Import from Dragon Age Mesh file (.msh)'''
	bl_idname = "import_scene.dragonage_msh"
	bl_description = 'Import from Dragon Age mesh file (.msh)'
	bl_label = "Import Dragon Age Mesh"
	bl_space_type = "PROPERTIES"
	bl_region_type = "WINDOW"
	
	rotate_z_180 = BoolProperty(name="Rotate Z 180",
							description="Rotate 180 degrees around Z so model faces front.",
							default=True)


	# List of operator properties, the attributes will be assigned
	# to the class instance from the operator settings before calling.
	filepath = StringProperty(name="File Path", description="Filepath used for importing the MSH file", maxlen= 1024, default= "", subtype='FILE_PATH')

	def execute(self, context):
		props = self.properties
		getInputFilename(self.filepath, props)
		return {'FINISHED'}

	def invoke(self, context, event):
		wm = context.window_manager
		wm.fileselect_add(self)
		return {'RUNNING_MODAL'}

def menu_func(self, context):
	self.layout.operator(IMPORT_OT_dragonage_mesh.bl_idname, text="Dragon Age 2 Mesh (.msh)")


def register():
	bpy.utils.register_module(__name__)

	bpy.types.INFO_MT_file_import.append(menu_func)


def unregister():
	bpy.utils.unregister_module(__name__)
	bpy.types.INFO_MT_file_import.remove(menu_func)


if __name__ == "__main__":
	register()

Re: Dragon Age 2 (PC)

Posted: Wed Apr 06, 2011 12:39 am
by lpss
figuresculptor wrote:
lpss wrote:I still can't get the hair/beard meshes with UV maps on Blender... :[
Does anyone know a way to do it? I'm using the Blender 2.49 script as I already had Blender 2.49
lpss:

The same problem exists with the 2.5.6 script - I've actually combed through the beard and hair, and it just looks like all the UVs are set to 0,0 or 1,0. I've looked through the vertex data for other potential UV data, and found nothing. I'm not sure what's going on with the hair or beards, but it's not anything you're doing - it is the script.
Thanks, figuresculptor! I hope you guys find the UV maps soon. :keke:

Re: Dragon Age 2 (PC)

Posted: Wed Apr 06, 2011 12:45 am
by figuresculptor
lpss wrote:Thanks, figuresculptor! I hope you guys find the UV maps soon. :keke:
We have… for everything else. I honestly think they're doing something weird at runtime with the hair and beards, so I'm not sure we're ever going to find them.

Re: Dragon Age 2 (PC)

Posted: Thu Apr 07, 2011 5:17 am
by Szkaradek123
Update for Blender249 importer:
- add uv-mapping for hair and beards.

Re: Dragon Age 2 (PC)

Posted: Thu Apr 07, 2011 8:31 pm
by lpss
You rock, dude!

Re: Dragon Age 2 (PC)

Posted: Sat May 07, 2011 8:01 pm
by bullet333
I got the script to work in 3ds max, but I'm having a lot of trouble finding the face and hair textures. Can someone please help me out?

Oh and I'm also trying to get the Blender script to work as well, but I'm a noob and don't know how to create that .py file you guys are talking about. I've tried using those .blend files, but it just doesn't give me the option to import .msh files.

Re: Dragon Age 2 (PC)

Posted: Fri May 13, 2011 2:22 pm
by superchickensoup
Hi, is it possible for anyone to e-mail me a obj of flemeth from da2. I just need the mesh and textures. Im building a high poly version and need the mesh for referance.
I managed to extract the msh files but could not find flemeth's model.
You can see my work Here
http://www.airflow3d.com
Any help would be appc.

E-mail
robangol @ g00glem@il.com
superchickensoup @ g00glem@il.com

Huge thanks.

Re: Dragon Age 2 (PC)

Posted: Sun May 22, 2011 1:48 pm
by anzolino
Hi guys,
thanks a lot for your great work. It works really fine.

But (there is always a but... ;o)) now I've got the export problem. I didn't find a solution to export the mesh (i.e. as fbx) and to convert the exported file. The model doesn't appear in the game (DA2). So my question to the experts: exists a solution for direct model exporting to a DA2 msh file?

So long
anzolino

Re: Dragon Age 2 (PC)

Posted: Sun May 22, 2011 2:09 pm
by figuresculptor
anzolino wrote:I didn't find a solution to export the mesh (i.e. as fbx) and to convert the exported file. The model doesn't appear in the game (DA2). So my question to the experts: exists a solution for direct model exporting to a DA2 msh file?
The DA2 tools should allow you to convert from an OBJ, DAE, or FBX file to a Mesh. There's also the old IOTools for Blender that contains a .msh exporter, but I don't believe it's been updated for DA2.

I believe that PyGFF also has tools for converting and packaging files. I've only used it to import objects, but it may be able to get objects back in the game. http://social.bioware.com/project/1936/

Re: Dragon Age 2 (PC)

Posted: Sun May 22, 2011 2:55 pm
by anzolino
Yes, the IO Tools does'nt work.
I've tried the DA2 Tools to convert the FBX to MSH and also to convert to XML for compiling with the DAO ResourceBuild processors. I'm also using the PyGFF for attribute changes etc. I will test if PyGFF can convert too.
Maybe I miss something else.

Re: Dragon Age 2 (PC)

Posted: Mon May 23, 2011 8:31 pm
by anzolino
I've heard from others that the DA2Tools also doesn't work. I didn't found any convert options in pyGFF. So it seems there don't exists a convert solution :[

Re: Dragon Age 2 (PC)

Posted: Wed Jun 08, 2011 2:19 pm
by OriginOfWaves
thanks so much for this importer guys

Re: Dragon Age 2 (PC)

Posted: Thu Jun 16, 2011 11:32 pm
by trumpdog
There is one import/export script for lightwave 3d here http://social.bioware.com/project/2246/
I dont know anything about it or the capabilities of the plug in. All i know is that everything done to the model has to be done in Lightwave, for example....you cant do anything in blender and export it to lightwave format or it loses its weighting and some other stuff upon import to lightwave. IMHO lightwave kinda sucks.....Havent had a successful export yet since i dont know how to use it.