mirror of
https://github.com/MapMakersAndProgrammers/io_scene_a3d.git
synced 2025-10-26 01:49:13 -07:00
Initial blender importing
This commit is contained in:
@@ -203,7 +203,7 @@ class A3D:
|
||||
# Read and assign transform ids
|
||||
for transformI in range(transformCount):
|
||||
transformID, = unpackStream("<I", stream)
|
||||
self.transforms[transformID] = transforms[transformI]
|
||||
self.transforms[transformI] = transforms[transformI] #XXX: The IDs seem to be incorrect and instead map to index?
|
||||
|
||||
# Padding
|
||||
padding = calculatePadding(length)
|
||||
|
||||
@@ -135,7 +135,8 @@ class A3DSubmesh:
|
||||
self.indexCount = 0
|
||||
|
||||
def read2(self, stream):
|
||||
self.indexCount, = unpackStream("<I", stream)*3
|
||||
self.indexCount, = unpackStream("<I", stream) # This is just the face count so multiply it by 3
|
||||
self.indexCount *= 3
|
||||
self.indices = list(unpackStream(f"<{self.indexCount}H", stream))
|
||||
self.smoothingGroups = list(unpackStream(f"<{self.indexCount//3}I", stream))
|
||||
self.materialID, = unpackStream("<H", stream)
|
||||
@@ -195,7 +196,7 @@ class A3DObject:
|
||||
|
||||
# Read material IDs
|
||||
for _ in range(self.materialCount):
|
||||
materialID, = unpackStream("<I", stream)
|
||||
materialID, = unpackStream("<i", stream)
|
||||
self.materialIDs.append(materialID)
|
||||
|
||||
print(f"[A3DObject name: {self.name} meshID: {self.meshID} transformID: {self.transformID} materialIDs: {len(self.materialIDs)}]")
|
||||
@@ -0,0 +1,183 @@
|
||||
import bmesh
|
||||
import bpy
|
||||
from bpy.types import Operator
|
||||
from bpy.props import StringProperty, BoolProperty
|
||||
from bpy_extras.io_utils import ImportHelper
|
||||
from bpy_extras.node_shader_utils import PrincipledBSDFWrapper
|
||||
|
||||
from .A3D import A3D
|
||||
from .A3DObjects import (
|
||||
A3D_VERTEXTYPE_COORDINATE,
|
||||
A3D_VERTEXTYPE_UV1,
|
||||
A3D_VERTEXTYPE_NORMAL1,
|
||||
A3D_VERTEXTYPE_UV2,
|
||||
A3D_VERTEXTYPE_COLOR,
|
||||
A3D_VERTEXTYPE_NORMAL2
|
||||
)
|
||||
|
||||
'''
|
||||
Operators
|
||||
'''
|
||||
class ImportA3D(Operator, ImportHelper):
|
||||
bl_idname = "import_scene.alternativa"
|
||||
bl_label = "Import A3D"
|
||||
bl_description = "Import an A3D model"
|
||||
|
||||
filter_glob: StringProperty(default="*.a3d", options={'HIDDEN'})
|
||||
|
||||
def invoke(self, context, event):
|
||||
return ImportHelper.invoke(self, context, event)
|
||||
|
||||
def execute(self, context):
|
||||
filepath = self.filepath
|
||||
|
||||
# Read the file
|
||||
print(f"Reading A3D data from {filepath}")
|
||||
modelData = A3D()
|
||||
with open(filepath, "rb") as file:
|
||||
modelData.read(file)
|
||||
|
||||
# Import data into blender
|
||||
print("Importing mesh data into blender")
|
||||
# Create materials
|
||||
materials = []
|
||||
for material in modelData.materials:
|
||||
ma = bpy.data.materials.new(material.name)
|
||||
maWrapper = PrincipledBSDFWrapper(ma, is_readonly=False, use_nodes=True)
|
||||
maWrapper.base_color = material.color
|
||||
maWrapper.roughness = 1.0
|
||||
|
||||
materials.append(ma)
|
||||
# Build meshes
|
||||
meshes = []
|
||||
for mesh in modelData.meshes:
|
||||
me = bpy.data.meshes.new(mesh.name)
|
||||
|
||||
# Gather all vertex data
|
||||
coordinates = []
|
||||
uv1 = []
|
||||
normal1 = []
|
||||
uv2 = []
|
||||
colors = []
|
||||
normal2 = []
|
||||
for vertexBuffer in mesh.vertexBuffers:
|
||||
if vertexBuffer.bufferType == A3D_VERTEXTYPE_COORDINATE:
|
||||
coordinates += vertexBuffer.data
|
||||
elif vertexBuffer.bufferType == A3D_VERTEXTYPE_UV1:
|
||||
uv1 += vertexBuffer.data
|
||||
elif vertexBuffer.bufferType == A3D_VERTEXTYPE_NORMAL1:
|
||||
normal1 += vertexBuffer.data
|
||||
elif vertexBuffer.bufferType == A3D_VERTEXTYPE_UV2:
|
||||
uv2 += vertexBuffer.data
|
||||
elif vertexBuffer.bufferType == A3D_VERTEXTYPE_COLOR:
|
||||
colors += vertexBuffer.data
|
||||
elif vertexBuffer.bufferType == A3D_VERTEXTYPE_NORMAL2:
|
||||
normal2 += vertexBuffer.data
|
||||
|
||||
# Add blender vertices
|
||||
blenderVertexIndices = []
|
||||
blenderVertices = []
|
||||
blenderUV1s = []
|
||||
blenderUV2s = []
|
||||
for submesh in mesh.submeshes:
|
||||
polygonCount = len(submesh.indices) // 3
|
||||
me.vertices.add(polygonCount*3)
|
||||
me.loops.add(polygonCount*3)
|
||||
me.polygons.add(polygonCount)
|
||||
|
||||
for indexI in range(submesh.indexCount):
|
||||
index = submesh.indices[indexI]
|
||||
blenderVertexIndices.append(indexI)
|
||||
blenderVertices += list(coordinates[index])
|
||||
blenderUV1s.append(uv1[index])
|
||||
#blenderUV2s += uv2[index]
|
||||
me.vertices.foreach_set("co", blenderVertices)
|
||||
me.polygons.foreach_set("loop_start", range(0, len(blenderVertices)//3, 3))
|
||||
me.loops.foreach_set("vertex_index", blenderVertexIndices)
|
||||
|
||||
# UVs
|
||||
if len(uv1) != 0:
|
||||
uvData = me.uv_layers.new(name="UV1").data
|
||||
for polygonI, po in enumerate(me.polygons):
|
||||
indexI = polygonI * 3
|
||||
uvData[po.loop_start].uv = blenderUV1s[blenderVertexIndices[indexI]]
|
||||
uvData[po.loop_start+1].uv = blenderUV1s[blenderVertexIndices[indexI+1]]
|
||||
uvData[po.loop_start+2].uv = blenderUV1s[blenderVertexIndices[indexI+2]]
|
||||
|
||||
# Apply materials (version 2)
|
||||
faceIndexBase = 0
|
||||
for submeshI, submesh in enumerate(mesh.submeshes):
|
||||
if submesh.materialID == None:
|
||||
continue
|
||||
me.materials.append(materials[submesh.materialID])
|
||||
for faceI in range(submesh.indexCount//3):
|
||||
me.polygons[faceI+faceIndexBase].material_index = submeshI
|
||||
faceIndexBase += submesh.indexCount//3
|
||||
|
||||
# Finalise
|
||||
me.validate()
|
||||
me.update()
|
||||
meshes.append(me)
|
||||
# Create objects
|
||||
for objec in modelData.objects:
|
||||
me = meshes[objec.meshID]
|
||||
mesh = modelData.meshes[objec.meshID]
|
||||
transform = modelData.transforms[objec.transformID]
|
||||
|
||||
# Select a name for the blender object
|
||||
name = ""
|
||||
if objec.name != "":
|
||||
name = objec.name
|
||||
elif mesh.name != "":
|
||||
name = mesh.name
|
||||
else:
|
||||
name = transform.name
|
||||
|
||||
# Create the object
|
||||
ob = bpy.data.objects.new(name, me)
|
||||
bpy.context.collection.objects.link(ob)
|
||||
|
||||
# Set transform
|
||||
ob.location = transform.position
|
||||
ob.scale = transform.scale
|
||||
ob.rotation_mode = "QUATERNION"
|
||||
x, y, z, w = transform.rotation
|
||||
ob.rotation_quaternion = (w, x, y, z)
|
||||
|
||||
# Apply materials (version 3)
|
||||
for materialID in objec.materialIDs:
|
||||
print(materialID)
|
||||
if materialID == -1:
|
||||
continue
|
||||
me.materials.append(materials[materialID])
|
||||
# Set the default material to the first one we added
|
||||
for polygon in me.polygons:
|
||||
polygon.material_index = 0
|
||||
|
||||
return {"FINISHED"}
|
||||
|
||||
'''
|
||||
Menu
|
||||
'''
|
||||
def menu_func_import_a3d(self, context):
|
||||
self.layout.operator(ImportA3D.bl_idname, text="Alternativa3D HTML5 (.a3d)")
|
||||
|
||||
'''
|
||||
Registration
|
||||
'''
|
||||
classes = [
|
||||
ImportA3D
|
||||
]
|
||||
|
||||
def register():
|
||||
for c in classes:
|
||||
bpy.utils.register_class(c)
|
||||
bpy.types.TOPBAR_MT_file_import.append(menu_func_import_a3d)
|
||||
|
||||
def unregister():
|
||||
for c in classes:
|
||||
bpy.utils.unregister_class(c)
|
||||
bpy.types.TOPBAR_MT_file_import.remove(menu_func_import_a3d)
|
||||
|
||||
if __name__ == "__main__":
|
||||
register()
|
||||
@@ -1,6 +0,0 @@
|
||||
from sys import argv
|
||||
from .A3D import A3D
|
||||
|
||||
with open(argv[1], "rb") as f:
|
||||
model = A3D()
|
||||
model.read(f)
|
||||
Reference in New Issue
Block a user