• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.
Sign in to follow this  
Followers 0
the incredible smoker

Planning on using Blender

17 posts in this topic

My opinion : Blender is better, but it takes time to learn it. 3dstudio max is easier to learn, more intuitive. It is a classical approach, and you wont be lost.

 

In Blender I save a lot of time. One of the strong features amongts others, is that you can lay down UVs with ease and speed.

1

Share this post


Link to post
Share on other sites

Pressing G_Key (grab) twice in edit mode enables edge slide.

Well, I just learnt something new. Thanks! :D

1

Share this post


Link to post
Share on other sites

Hi, thanks for the reply`s.

Looks like i can use Blender without problems when reading Scouting Ninja`s post.

The UV coordinates has unwrap ?, that is very nice, if i have to, i will fill in the UV coordinates manually since i only do low-poly stuff.

The boolean is also not perfect in 3dMax, still have to remove sudden vertices sometime, it is a very nice inspiring usable feature for the rest, max aint perfect also, especially if you look to the price.

There are always other methods to make the same without boolean, and will be more perfect, so i can live with that.

I,m surely i going to use Blender, if i have some question i will post them in this forum.

thanks

1

Share this post


Link to post
Share on other sites

Posted (edited)

Hi, i know Hodgman, i like to make a very simple game for once, nothing more.

Microsoft makes all that stuff in dll, so you cannot see the actual codes and maths.

By example they have this nice function also : CheckIntersect.

 

I was planning on using all the DirectX stuff, i dont know how to make all functions myself,

i better wanto avoid all, only i dont know how ?

Ok a 3d fileformat aint that hard to make.

I,m also gonna use the fixed pipeline, i realy have no clue else what to do, i,m a total beginner with the goal of making some games.

I only wanto invest 1 year for all music/artwork/programming.

 

The big problem is that i cannot optimize the functions i use : adding integer math / adding lookuptables.

Edited by the incredible smoker
0

Share this post


Link to post
Share on other sites

Posted (edited)

Which program is better is a matter of opinion. I prefer Blender because it doesn't cost as much as a used car and I do tutorials where I want people to be able to follow along without having to go buy thousands of dollars worth of software.
 
I used Max for awhile. I started with Max before I knew how to do much, mostly following tutorials. I wouldn't mind using it again as long as I don't have to buy it.
 
But I really love Blender. There might be other software out there that does things better. There's a lot of software I've never tried. I had a lot of trouble with animation in Blender, but that may be simply because I haven't learned to use it well yet. However, when I worked in Poser years ago it seemed like animation was an order of magnitude easier.
 
So far, animation is really the only issue I've ever had with Blender. I'm not sure how much better Max is at it as it's been many years since I've done any animation in Max and I think that was just a tutorial or two. I think Poser was easier for humanoid animation than either of them, if I recall correctly. Even my Poser experience was several years ago.
 
I'm enrolled in a 3D art program where I'm learning 3D modeling and we're using Blender for the class. My DeviantArt site shows some of the finals I turned in for the class including a bucket, Mons Meg, and a Cold Blast Lamp. I did the modeling in Blender, then I exported them to Substance for painting/texturing, then I imported them back into Blender to render them in Cycles. The backgrounds are HDRI environment maps. Basically, they are 360 degree spherical photographs. Blender Cycles uses the photo for lighting, which is a big part of what makes everything looks so realistic.
http://virtuallyprogramming.deviantart.com/
 
If you are coding DirectX, you may want to check out my simple DX 11 engine on my website. The entire Visual Studio project is there for download including all art assets and such. For example, the Python code for the Blender exporter is in the download. I made a Blender model exporter written in Python (forgive my Python code as I literally taught myself Python just for this project - the exporter code works, but has room for improvement) and the source code is there to load the model file and create a model object from it. It should work well for rigid animation, although it doesn't support skinned animation. But it's modifiable so you could make it do whatever you like. There is a video of my OpenGL engine on my website. You can watch that and get an idea of what the DX engine does without having to actually download the DX project. The OGL engine is basically the same except I never got around to adding the code for models and all the models in the OGL code are hard coded. My modeling skills weren't all that great back when I programmed this stuff; they've gotten a lot better in the past year as I've been in this art program.
 
I think a lot of people use ASSIMP to load models and I think it supports a lot of different formats. I assume it supports skinned animation as well.
 
I started with XNA and then went straight to DX11. So, I skipped DX9, but I guess it natively supports .X files? They took the whole model class out and such in DX11, so it no longer natively supports much of anything although I think it will natively support .DDS images.

Edited by BBeck
0

Share this post


Link to post
Share on other sites
Blender is something you will hate with a passion, until you finally, after many hours of pain, get used to its perverse user interface and keyboard shortcuts.

At that point, Blender suddenly becomes the most awesome modelling software you have ever used (I'm not really interested in raytracing, so the fact that the Cycles renderer is about as poor as it can be performance-wise is not an issue for me, and I couldn't say anything about Blender's built-in game engine either).

Tasks that seem to be trivial but are excruciatingly difficult with most modelling software are surprisingly easy in Blender, if you know how to use it. But... plan to invest a few weeks of learning.
0

Share this post


Link to post
Share on other sites

I started with XNA and then went straight to DX11. So, I skipped DX9, but I guess it natively supports .X files? They took the whole model class out and such in DX11, so it no longer natively supports much of anything.

 

Oh, does D3DXMesh still exists ?, do you have to figure out now yourself how it works ?, thanks for the examples then.

I still use DX9, i wanto upgrade to a better version maybe if its better, i still use XP, visual C++ 2005, can i install a better DirectX with that ?

I dont wanto download a free compiler since i have professional package and can legally sell with this eventually.

0

Share this post


Link to post
Share on other sites

Oh, does D3DXMesh still exists ?

Nope. The D3DX library was not maintained after D3D9. It's used by the example code for D3D9 only, it's not a "real" part of DirectX.

1

Share this post


Link to post
Share on other sites

In addition to what Hodgman said, I believe they moved a lot of the functionality out to the DirectX Took Kit. Looks to me like they took a lot of that stuff out between DX10 and DX11 including Sprite and Model support. I think they did DXTK as a way to give it back to those who wanted it. I believe a lot of pro-game developers were basically writing their own anyway and they wanted to offload it.

 

I haven't tried DXTK myself. When I was doing DX11, I was bound and determined to figure out how to do it all myself. So, I built my own model class, exporter, and importer. Then I serialized the class to save the binary data out to disk. I would have gone on to make it support skinned animation. I got as far as doing a test run using XNA to play back Blender humanoid animation data as stick figures, but then decided to start doing OpenGL instead and had to start all over learning OGL. Then I got side tracked again with learning 3D modeling. Learning Vulkan is on my agenda but really before any of that I have to get my new computer built as the parts have been sitting here collecting dust since Christmas.

 

I never used D3DXMesh directly. I think what I was doing in XNA years ago was calling it to get the job done behind the scenes.

 

There's also ASSIMP for models although I don't know exactly how much it does for you since I haven't tried it. I've thought about trying to work ASSIMP into my OGL engine rather than rewriting my DX model class to support OGL. I can see some advantages to both and so I'm still not sure which direction I'll go with that if I ever get the time.

 

I actually have a bit of deprecated code in my DX11 engine. Some of it is probably because I wrote it for Windows 7 and MS no longer really supports that wanting everyone to use Win10. Apparently, there's no "good" way to get keyboard input in DX11 and hasn't been in DX for a long time. I'm using DX8 code to communicate with the Keyboard rather than going through the event loop. I think some of the error handling was deprecated code as well. I tried to avoid anything deprecated, but there seemed no good way to do some things in DX11 for Win7 without using deprecated code.

 

So, I'm guessing you could actually include D3DXMesh in DX11 or DX12 code.

 

Really, all a model is is a vertex buffer and an index buffer. The hard part is done in the modeling software to build all those vertices and assign them data. I made mine to import sub-meshes so that the model could be in different parts. That's mostly to support rigid animation, so that the parts can be animated separately. But I put it all in a single vertex buffer.

 

If you support skinned animation, it gets quite a bit more complex. You have to have all the skinning data such as vertex groups and weighting information to know how much each vertex is assigned to each bone in the armature. And you have to have the armature data itself (bones), which is a bit different from the sub-meshes having their own matrices in rigid animation. Then of course, there's all the animation data for the armature and calculating frames between the key frames.

I'm not sure if D3DXMesh supported animation. I'm betting it did because I seem to remember doing a tutorial once where I got a model to animate back in the DX9 days and back then I had no clue what I was doing. In fact, I failed to learn DX9 after a few years of effort. XNA came along and that's when I actually started figuring everything out and in XNA the model class did not natively support skinned animation. Then I went into DX11 without ever really learning DX9.

0

Share this post


Link to post
Share on other sites

Agreed with what most people are saying here with the two main points.

  • Blender is cost effective and produces similar results (has a great community and lots of plugins).
  • Using Blender solely for that format is perhaps not the best use since it is not commonly used now.
0

Share this post


Link to post
Share on other sites

Thanks for the reply`s

For the toolkit i see no download for XP & Win7, maybe i stay with old trusty DX9,

 

only it would be very handy to make stuff myself, i might understand things better for optimizing.

That means i have to make a blender export plugin, i bet there are enough examples for that in C.

 

I use vertexbuffer for the LevelMesh, only indexbuffer i dont know exact how it works, it seems i need it for the models.

And skinned animation is something i would like, only i dont wanto get involved in these seperate shader files for animations,

i want everything done in 1 source code file, not learn a new shader language on top, i dont know if that is possible ?

0

Share this post


Link to post
Share on other sites

I think you have to use Python to write a Blender exporter. If you find a way to do it in C, let me know, because I pretty much hate Python. Then again, I only learned enough Python to write a Blender exporter. So, I imagine my code has plenty of room for improvement. But here is my Blender Python model data exporter:

 

import bpy


def ProcessChildren(f, ParentMesh, VerticesInModel, FacesInModel):  #Get all data for sub-meshes.
    VerticesSoFar = VerticesInModel
    FacesSoFar = FacesInModel
    NumberOfChildren = len(ParentMesh.children)
    if NumberOfChildren > 0:
        for ChildMesh in ParentMesh.children:
            HasUVCoordinates = ChildMesh.data.uv_layers.active
            HasVertexColors = ChildMesh.data.vertex_colors.active
            CountOfVertices = 0
            f.write("Name:%s\n" % ChildMesh.name)
            f.write("Parent:%s\n" % ChildMesh.parent.name)
            VerticesSoFar = VerticesSoFar + len(ChildMesh.data.vertices)
            ChildMesh.data.update(calc_tessface=True)
            FacesSoFar = FacesSoFar + len(ChildMesh.data.tessfaces)
            #Materials
            SubMeshMaterialNo = 0
            for Material in ChildMesh.material_slots:
                f.write("M:%d" % SubMeshMaterialNo)
                f.write("-%s" % Material.name)
                f.write(" T:%s" % Material.material.active_texture.image.name)
                f.write(" C:%s\n" % str(tuple(Material.material.diffuse_color)))
            #WorldMatrix
            WorldMatrixRowNumber = 0
            for WorldMatrixRow in ChildMesh.matrix_world.row:
                f.write("WMR%d" % WorldMatrixRowNumber)
                f.write(":%s\n" % str(tuple(WorldMatrixRow)))
                WorldMatrixRowNumber = WorldMatrixRowNumber + 1
            #Faces.
            FaceCount = 0
            for Face in ChildMesh.data.polygons:
                f.write("F:%d" % FaceCount)
                f.write(" M:%s" % str(Face.material_index))
                f.write(" N:({:f}".format(Face.normal[0]))
                f.write(",{:f}".format(Face.normal[1]))
                f.write(",{:f})".format(Face.normal[2]))
                f.write(" S:%s\n" % str(Face.use_smooth)[0])
                FaceCount = FaceCount + 1
                for Vert, Loop in zip(Face.vertices, Face.loop_indices):
                    f.write("P:%s" % str(tuple(ChildMesh.data.vertices[Vert].co)))
                    if HasUVCoordinates is not None:
                        f.write(", U:%s" % str(tuple(ChildMesh.data.uv_layers.active.data[Loop].uv)))
                    else:
                        f.write(", U:(0.0,0.0)")
                    f.write(", N:%s" % str(tuple(ChildMesh.data.vertices[Vert].normal)))
                    if HasVertexColors is not None:
                        f.write(", C:%s" % str(tuple(ChildMesh.data.vertex_colors.active.data[Vert].color)))
                    else:
                        f.write(", C:(0.0,0.0,0.0,0.0)")
                    f.write("\n")
            #Call child's children.
            VerticesSoFar, FacesSoFar = ProcessChildren(f, ChildMesh, VerticesSoFar, FacesSoFar)
    return VerticesSoFar, FacesSoFar

def write_some_data(context, filepath):
    HasUVCoordinates = bpy.context.active_object.data.uv_layers.active
    HasVertexColors = bpy.context.active_object.data.vertex_colors.active
    print("Exporting data...")
    bpy.context.active_object.data.update(calc_tessface=True)         #calc_tessface=True must be set before working with faces.
    
    f = open(filepath, 'w', encoding='utf-8')
    if bpy.context.active_object != None and bpy.context.active_object.parent == None and bpy.context.active_object.type == 'MESH':
        CountOfVertices = 0
        NumberOfMaterialsUsed = 0
        FacesInModel = 0
        VerticesInModel = len(bpy.context.active_object.data.vertices)
        FacesInModel = len(bpy.context.active_object.data.tessfaces)
        f.write("Punc!It Text\n")
        f.write("Rigid Animation\n")
        f.write("Name:%s\n" % bpy.context.active_object.name)
        f.write("Parent:None\n")
        #Materials
        MaterialNo = 0
        for Material in bpy.context.active_object.material_slots:
            f.write("M:%d" % MaterialNo)
            f.write("-%s" % Material.name)
            f.write(" T:%s" % Material.material.active_texture.image.name)
            f.write(" C:%s\n" % str(tuple(Material.material.diffuse_color)))
        #WorldMatrix
        WorldMatrixRowNumber = 0
        for WorldMatrixRow in bpy.context.active_object.matrix_world.row:
            f.write("WMR%d" % WorldMatrixRowNumber)
            f.write(":%s\n" % str(tuple(WorldMatrixRow)))
            WorldMatrixRowNumber = WorldMatrixRowNumber + 1
        #Faces.
        FaceCount = 0
        for Face in bpy.context.active_object.data.polygons:
            f.write("F:%d" % FaceCount)
            f.write(" M:%s" % str(Face.material_index))
            f.write(" N:({:f}".format(Face.normal[0]))
            f.write(",{:f}".format(Face.normal[1]))
            f.write(",{:f})".format(Face.normal[2]))
            f.write(" S:%s\n" % str(Face.use_smooth)[0])
            FaceCount = FaceCount + 1
            for Vert, Loop in zip(Face.vertices, Face.loop_indices):
                f.write("P:%s" % str(tuple(bpy.context.active_object.data.vertices[Vert].co)))
                if HasUVCoordinates is not None:
                    f.write(", U:%s" % str(tuple(bpy.context.active_object.data.uv_layers.active.data[Loop].uv)))
                else:
                    f.write(", U:(0.0,0.0)")
                f.write(", N:%s" % str(tuple(bpy.context.active_object.data.vertices[Vert].normal)))
                if HasVertexColors is not None:
                    f.write(", C:%s" % str(tuple(bpy.context.active_object.data.vertex_colors.active.data[Vert].color)))
                else:
                    f.write(", C:(0.0,0.0,0.0,0.0)")
                f.write("\n")
        #Children.
        VerticesInModel, FacesInModel = ProcessChildren(f, bpy.context.active_object, VerticesInModel, FacesInModel)
        #Footer
        f.write("Total Unique Vertices:%d\n" % VerticesInModel)
        f.write("Total Faces:%d\n" % FacesInModel)
        f.write("Total Materials:%d" % NumberOfMaterialsUsed)
    else:
        f.write("You must select the root mesh before exporting the model!")
    f.close()
    
    return {'FINISHED'}


# ExportHelper is a helper class, defines filename and
# invoke() function which calls the file selector.
from bpy_extras.io_utils import ExportHelper
from bpy.props import StringProperty, BoolProperty, EnumProperty
from bpy.types import Operator


class ExportSomeData(Operator, ExportHelper):
    """This appears in the tooltip of the operator and in the generated docs"""
    bl_idname = "export_test.some_data"  # important since its how bpy.ops.import_test.some_data is constructed
    bl_label = "Export Button"

    # ExportHelper mixin class uses this
    filename_ext = ".txt"

    filter_glob = StringProperty(
            default="*.txt",
            options={'HIDDEN'},
            )

    def execute(self, context):
        return write_some_data(context, self.filepath)


# Only needed if you want to add into a dynamic menu
def menu_func_export(self, context):
    self.layout.operator(ExportSomeData.bl_idname, text="Custom Exporter Test")


def register():
    bpy.utils.register_class(ExportSomeData)
    bpy.types.INFO_MT_file_export.append(menu_func_export)


def unregister():
    bpy.utils.unregister_class(ExportSomeData)
    bpy.types.INFO_MT_file_export.remove(menu_func_export)


if __name__ == "__main__":
    register()

    # test call
    bpy.ops.export_test.some_data('INVOKE_DEFAULT')

 

This is a toy car model I made in Blender and exported. This is what the output looks like:

Punc!It Text
Rigid Animation
Name:CarBody
Parent:None
M:0-CarMaterial T:SimplifiedCarBody.png C:(1.0, 1.0, 1.0)
WMR0:(1.0, 0.0, 0.0, 0.0)
WMR1:(0.0, 1.0, 0.0, 0.0)
WMR2:(0.0, 0.0, 1.0, 0.0)
WMR3:(0.0, 0.0, 0.0, 1.0)
F:0 M:0 N:(-0.000000,-1.000000,0.000000) S:F
P:(0.6159690022468567, -1.0, 1.3930187225341797), U:(0.38228708505630493, 0.8303871154785156), N:(0.5597094893455505, -0.46266061067581177, 0.6874599456787109), C:(1.0, 1.0, 0.0)
P:(-0.6159691214561462, -0.9999999403953552, 1.3930187225341797), U:(0.6177127957344055, 0.8303872346878052), N:(-0.5597094893455505, -0.46266061067581177, 0.6874599456787109), C:(0.9686274528503418, 1.0, 0.003921568859368563)
P:(-0.6159691214561462, -0.9999999403953552, 0.6069812774658203), U:(0.617712676525116, 0.9806004762649536), N:(-0.5773491859436035, -0.5773491859436035, -0.5773491859436035), C:(1.0, 1.0, 0.0)
P:(0.6159690022468567, -1.0, 0.6069812774658203), U:(0.3822869658470154, 0.9806003570556641), N:(0.5773491859436035, -0.5773491859436035, -0.5773491859436035), C:(0.9333333373069763, 1.0, 0.04313725605607033)
F:1 M:0 N:(-1.000000,0.000000,0.000000) S:F
P:(-0.6159690618515015, 0.01772703416645527, 0.9793898463249207), U:(0.8122022747993469, 0.9094325304031372), N:(-0.7674794793128967, 0.08630634844303131, 0.635181725025177), C:(0.929411768913269, 1.0, 0.003921568859368563)
P:(-0.6159690022468567, 0.7281867861747742, 1.0621156692504883), U:(0.9479727745056152, 0.8936232924461365), N:(-0.6028626561164856, 0.35294654965400696, 0.7155064344406128), C:(0.929411768913269, 1.0, 0.003921568859368563)
P:(-0.6159690022468567, 1.0, 0.6069812774658203), U:(0.9999170303344727, 0.9806004762649536), N:(-0.5541856288909912, 0.7238990664482117, -0.4108401834964752), C:(0.929411768913269, 1.0, 0.0)
P:(-0.6159690618515015, 0.1418156772851944, 0.6069812774658203), U:(0.8359159827232361, 0.9806005954742432), N:(-0.7070833444595337, 0.0, -0.7070833444595337), C:(0.9333333373069763, 1.0, 0.05098039284348488)
F:2 M:0 N:(0.000000,0.858546,0.512737) S:F
P:(-0.6159690022468567, 0.7281867861747742, 1.0621156692504883), U:(0.5792591571807861, 0.008944153785705566), N:(-0.6028626561164856, 0.35294654965400696, 0.7155064344406128), C:(0.929411768913269, 1.0, 0.003921568859368563)
P:(0.6159691214561462, 0.7281866669654846, 1.0621156692504883), U:(0.5792591571807861, 0.2862038016319275), N:(0.6028626561164856, 0.35294654965400696, 0.7155064344406128), C:(0.929411768913269, 1.0, 0.0)
P:(0.6159691214561462, 0.9999999403953552, 0.6069812774658203), U:(0.45994994044303894, 0.28620368242263794), N:(0.5541856288909912, 0.7238990664482117, -0.4108401834964752), C:(1.0, 1.0, 0.0)
P:(-0.6159690022468567, 1.0, 0.6069812774658203), U:(0.45994997024536133, 0.008944228291511536), N:(-0.5541856288909912, 0.7238990664482117, -0.4108401834964752), C:(0.929411768913269, 1.0, 0.0)
F:3 M:0 N:(1.000000,-0.000000,-0.000000) S:F
P:(0.6159690618515015, 0.017726941034197807, 0.9793898463249207), U:(0.18779747188091278, 0.9094322323799133), N:(0.7674794793128967, 0.08630634844303131, 0.635181725025177), C:(0.929411768913269, 1.0, 0.0)
P:(0.6159690022468567, -1.0, 1.3930187225341797), U:(0.38228708505630493, 0.8303871154785156), N:(0.5597094893455505, -0.46266061067581177, 0.6874599456787109), C:(1.0, 1.0, 0.0)
P:(0.6159690022468567, -1.0, 0.6069812774658203), U:(0.3822869658470154, 0.9806003570556641), N:(0.5773491859436035, -0.5773491859436035, -0.5773491859436035), C:(0.9333333373069763, 1.0, 0.04313725605607033)
P:(0.6159690618515015, 0.14181558787822723, 0.6069812774658203), U:(0.16408395767211914, 0.9806002378463745), N:(0.7070833444595337, 0.0, -0.7070833444595337), C:(1.0, 1.0, 0.0)
F:4 M:0 N:(0.000000,-0.000000,-1.000000) S:F
P:(0.6159690618515015, 0.14181558787822723, 0.6069812774658203), U:(0.2668073773384094, 0.28620344400405884), N:(0.7070833444595337, 0.0, -0.7070833444595337), C:(1.0, 1.0, 0.0)
P:(-0.6159690618515015, 0.1418156772851944, 0.6069812774658203), U:(0.2668076157569885, 0.008944153785705566), N:(-0.7070833444595337, 0.0, -0.7070833444595337), C:(0.9333333373069763, 1.0, 0.05098039284348488)
P:(-0.6159690022468567, 1.0, 0.6069812774658203), U:(0.45994997024536133, 0.008944228291511536), N:(-0.5541856288909912, 0.7238990664482117, -0.4108401834964752), C:(0.929411768913269, 1.0, 0.0)
P:(0.6159691214561462, 0.9999999403953552, 0.6069812774658203), U:(0.45994994044303894, 0.28620368242263794), N:(0.5541856288909912, 0.7238990664482117, -0.4108401834964752), C:(1.0, 1.0, 0.0)
F:5 M:0 N:(0.000000,0.376516,0.926410) S:F
P:(0.6159690618515015, 0.017726941034197807, 0.9793898463249207), U:(0.7402355074882507, 0.28620395064353943), N:(0.7674794793128967, 0.08630634844303131, 0.635181725025177), C:(0.929411768913269, 1.0, 0.0)
P:(-0.6159690618515015, 0.01772703416645527, 0.9793898463249207), U:(0.740235447883606, 0.008944094181060791), N:(-0.7674794793128967, 0.08630634844303131, 0.635181725025177), C:(0.929411768913269, 1.0, 0.003921568859368563)
P:(-0.6159691214561462, -0.9999999403953552, 1.3930187225341797), U:(0.9874796867370605, 0.008944094181060791), N:(-0.5597094893455505, -0.46266061067581177, 0.6874599456787109), C:(0.9686274528503418, 1.0, 0.003921568859368563)
P:(0.6159690022468567, -1.0, 1.3930187225341797), U:(0.9874798059463501, 0.28620395064353943), N:(0.5597094893455505, -0.46266061067581177, 0.6874599456787109), C:(1.0, 1.0, 0.0)
F:6 M:0 N:(-1.000000,0.000000,0.000000) S:F
P:(-0.6159691214561462, -0.9999999403953552, 1.3930187225341797), U:(0.6177127957344055, 0.8303872346878052), N:(-0.5597094893455505, -0.46266061067581177, 0.6874599456787109), C:(0.9686274528503418, 1.0, 0.003921568859368563)
P:(-0.6159690618515015, 0.01772703416645527, 0.9793898463249207), U:(0.8122022747993469, 0.9094325304031372), N:(-0.7674794793128967, 0.08630634844303131, 0.635181725025177), C:(0.929411768913269, 1.0, 0.003921568859368563)
P:(-0.6159690618515015, 0.1418156772851944, 0.6069812774658203), U:(0.8359159827232361, 0.9806005954742432), N:(-0.7070833444595337, 0.0, -0.7070833444595337), C:(0.9333333373069763, 1.0, 0.05098039284348488)
P:(-0.6159691214561462, -0.9999999403953552, 0.6069812774658203), U:(0.617712676525116, 0.9806004762649536), N:(-0.5773491859436035, -0.5773491859436035, -0.5773491859436035), C:(1.0, 1.0, 0.0)
F:7 M:0 N:(1.000000,-0.000000,-0.000000) S:F
P:(0.6159691214561462, 0.7281866669654846, 1.0621156692504883), U:(0.052026983350515366, 0.8936232924461365), N:(0.6028626561164856, 0.35294654965400696, 0.7155064344406128), C:(0.929411768913269, 1.0, 0.0)
P:(0.6159690618515015, 0.017726941034197807, 0.9793898463249207), U:(0.18779747188091278, 0.9094322323799133), N:(0.7674794793128967, 0.08630634844303131, 0.635181725025177), C:(0.929411768913269, 1.0, 0.0)
P:(0.6159690618515015, 0.14181558787822723, 0.6069812774658203), U:(0.16408395767211914, 0.9806002378463745), N:(0.7070833444595337, 0.0, -0.7070833444595337), C:(1.0, 1.0, 0.0)
P:(0.6159691214561462, 0.9999999403953552, 0.6069812774658203), U:(8.296234591398388e-05, 0.9806005954742432), N:(0.5541856288909912, 0.7238990664482117, -0.4108401834964752), C:(1.0, 1.0, 0.0)
F:8 M:0 N:(0.000000,-0.000000,-1.000000) S:F
P:(0.6159690022468567, -1.0, 0.6069812774658203), U:(0.009831011295318604, 0.2862032651901245), N:(0.5773491859436035, -0.5773491859436035, -0.5773491859436035), C:(0.9333333373069763, 1.0, 0.04313725605607033)
P:(-0.6159691214561462, -0.9999999403953552, 0.6069812774658203), U:(0.00983119010925293, 0.008943945169448853), N:(-0.5773491859436035, -0.5773491859436035, -0.5773491859436035), C:(1.0, 1.0, 0.0)
P:(-0.6159690618515015, 0.1418156772851944, 0.6069812774658203), U:(0.2668076157569885, 0.008944153785705566), N:(-0.7070833444595337, 0.0, -0.7070833444595337), C:(0.9333333373069763, 1.0, 0.05098039284348488)
P:(0.6159690618515015, 0.14181558787822723, 0.6069812774658203), U:(0.2668073773384094, 0.28620344400405884), N:(0.7070833444595337, 0.0, -0.7070833444595337), C:(1.0, 1.0, 0.0)
F:9 M:0 N:(-0.000000,-0.115658,0.993289) S:F
P:(0.6159691214561462, 0.7281866669654846, 1.0621156692504883), U:(0.5792591571807861, 0.2862038016319275), N:(0.6028626561164856, 0.35294654965400696, 0.7155064344406128), C:(0.929411768913269, 1.0, 0.0)
P:(-0.6159690022468567, 0.7281867861747742, 1.0621156692504883), U:(0.5792591571807861, 0.008944153785705566), N:(-0.6028626561164856, 0.35294654965400696, 0.7155064344406128), C:(0.929411768913269, 1.0, 0.003921568859368563)
P:(-0.6159690618515015, 0.01772703416645527, 0.9793898463249207), U:(0.740235447883606, 0.008944094181060791), N:(-0.7674794793128967, 0.08630634844303131, 0.635181725025177), C:(0.929411768913269, 1.0, 0.003921568859368563)
P:(0.6159690618515015, 0.017726941034197807, 0.9793898463249207), U:(0.7402355074882507, 0.28620395064353943), N:(0.7674794793128967, 0.08630634844303131, 0.635181725025177), C:(0.929411768913269, 1.0, 0.0)
Name:WheelBkPort
Parent:CarBody
M:0-BackPortMaterial T:SimplifiedCarFrontPort.png C:(0.800000011920929, 0.800000011920929, 0.800000011920929)
WMR0:(1.0, 0.0, 0.0, -0.9599999785423279)
WMR1:(0.0, 1.0, 0.0, -1.0)
WMR2:(0.0, 0.0, 1.0, 0.30000001192092896)
WMR3:(0.0, 0.0, 0.0, 1.0)
F:0 M:0 N:(-0.000000,-1.000000,0.000000) S:F
P:(0.29999998211860657, -0.30000004172325134, 0.30000001192092896), U:(1.0000817775726318, 0.4998322129249573), N:(0.5773491859436035, -0.5773491859436035, 0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
P:(-0.30000004172325134, -0.29999998211860657, 0.30000001192092896), U:(0.750124990940094, 0.4998321533203125), N:(-0.5773491859436035, -0.5773491859436035, 0.5773491859436035), C:(0.12941177189350128, 0.0235294122248888, 1.0)
P:(-0.30000004172325134, -0.29999998211860657, -0.30000001192092896), U:(0.7501248121261597, 0.2498754858970642), N:(-0.5773491859436035, -0.5773491859436035, -0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
P:(0.29999998211860657, -0.30000004172325134, -0.30000001192092896), U:(1.0000817775726318, 0.24987530708312988), N:(0.5773491859436035, -0.5773491859436035, -0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
F:1 M:0 N:(-1.000000,0.000000,0.000000) S:F
P:(-0.30000004172325134, -0.29999998211860657, 0.30000001192092896), U:(0.750124990940094, 0.4998321533203125), N:(-0.5773491859436035, -0.5773491859436035, 0.5773491859436035), C:(0.12941177189350128, 0.0235294122248888, 1.0)
P:(-0.29999998211860657, 0.30000004172325134, 0.30000001192092896), U:(0.5001685619354248, 0.4998323321342468), N:(-0.5773491859436035, 0.5773491859436035, 0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
P:(-0.29999998211860657, 0.30000004172325134, -0.30000001192092896), U:(0.5001682043075562, 0.24987581372261047), N:(-0.5773491859436035, 0.5773491859436035, -0.5773491859436035), C:(0.11372549086809158, 0.003921568859368563, 1.0)
P:(-0.30000004172325134, -0.29999998211860657, -0.30000001192092896), U:(0.7501248121261597, 0.2498754858970642), N:(-0.5773491859436035, -0.5773491859436035, -0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
F:2 M:0 N:(0.000000,1.000000,0.000000) S:F
P:(-0.29999998211860657, 0.30000004172325134, 0.30000001192092896), U:(0.5001685619354248, 0.4998323321342468), N:(-0.5773491859436035, 0.5773491859436035, 0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
P:(0.30000004172325134, 0.29999998211860657, 0.30000001192092896), U:(0.2502121329307556, 0.49983274936676025), N:(0.5773491859436035, 0.5773491859436035, 0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
P:(0.30000004172325134, 0.29999998211860657, -0.30000001192092896), U:(0.2502116858959198, 0.24987617135047913), N:(0.5773491859436035, 0.5773491859436035, -0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
P:(-0.29999998211860657, 0.30000004172325134, -0.30000001192092896), U:(0.5001682043075562, 0.24987581372261047), N:(-0.5773491859436035, 0.5773491859436035, -0.5773491859436035), C:(0.11372549086809158, 0.003921568859368563, 1.0)
F:3 M:0 N:(1.000000,-0.000000,0.000000) S:F
P:(0.30000004172325134, 0.29999998211860657, 0.30000001192092896), U:(0.2502121329307556, 0.49983274936676025), N:(0.5773491859436035, 0.5773491859436035, 0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
P:(0.29999998211860657, -0.30000004172325134, 0.30000001192092896), U:(0.0002555549144744873, 0.49983328580856323), N:(0.5773491859436035, -0.5773491859436035, 0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
P:(0.29999998211860657, -0.30000004172325134, -0.30000001192092896), U:(0.0002550482749938965, 0.24987667798995972), N:(0.5773491859436035, -0.5773491859436035, -0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
P:(0.30000004172325134, 0.29999998211860657, -0.30000001192092896), U:(0.2502116858959198, 0.24987617135047913), N:(0.5773491859436035, 0.5773491859436035, -0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
F:4 M:0 N:(0.000000,-0.000000,-1.000000) S:F
P:(0.29999998211860657, -0.30000004172325134, -0.30000001192092896), U:(1.0000817775726318, 0.24987530708312988), N:(0.5773491859436035, -0.5773491859436035, -0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
P:(-0.30000004172325134, -0.29999998211860657, -0.30000001192092896), U:(0.7501248121261597, 0.2498754858970642), N:(-0.5773491859436035, -0.5773491859436035, -0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
P:(-0.29999998211860657, 0.30000004172325134, -0.30000001192092896), U:(0.7501246929168701, -8.171796798706055e-05), N:(-0.5773491859436035, 0.5773491859436035, -0.5773491859436035), C:(0.11372549086809158, 0.003921568859368563, 1.0)
P:(0.30000004172325134, 0.29999998211860657, -0.30000001192092896), U:(1.0000818967819214, -8.183717727661133e-05), N:(0.5773491859436035, 0.5773491859436035, -0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
F:5 M:0 N:(0.000000,-0.000000,1.000000) S:F
P:(0.30000004172325134, 0.29999998211860657, 0.30000001192092896), U:(1.0000817775726318, 0.7497890591621399), N:(0.5773491859436035, 0.5773491859436035, 0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
P:(-0.29999998211860657, 0.30000004172325134, 0.30000001192092896), U:(0.750124990940094, 0.7497889399528503), N:(-0.5773491859436035, 0.5773491859436035, 0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
P:(-0.30000004172325134, -0.29999998211860657, 0.30000001192092896), U:(0.750124990940094, 0.4998321533203125), N:(-0.5773491859436035, -0.5773491859436035, 0.5773491859436035), C:(0.12941177189350128, 0.0235294122248888, 1.0)
P:(0.29999998211860657, -0.30000004172325134, 0.30000001192092896), U:(1.0000817775726318, 0.4998322129249573), N:(0.5773491859436035, -0.5773491859436035, 0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
Name:WheelBkStarboard
Parent:CarBody
M:0-BackStarboardMaterial T:SimplifiedCarFrontPort.png C:(0.800000011920929, 0.800000011920929, 0.800000011920929)
WMR0:(1.0, 0.0, 0.0, 0.949999988079071)
WMR1:(0.0, 1.0, 0.0, -1.0)
WMR2:(0.0, 0.0, 1.0, 0.30000001192092896)
WMR3:(0.0, 0.0, 0.0, 1.0)
F:0 M:0 N:(-0.000000,-1.000000,0.000000) S:F
P:(0.29999998211860657, -0.30000004172325134, 0.30000001192092896), U:(1.0009549856185913, 0.49895909428596497), N:(0.5773491859436035, -0.5773491859436035, 0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
P:(-0.30000004172325134, -0.29999998211860657, 0.30000001192092896), U:(0.7509981393814087, 0.4989590346813202), N:(-0.5773491859436035, -0.5773491859436035, 0.5773491859436035), C:(0.12941177189350128, 0.0235294122248888, 1.0)
P:(-0.30000004172325134, -0.29999998211860657, -0.30000001192092896), U:(0.7509979009628296, 0.2490023672580719), N:(-0.5773491859436035, -0.5773491859436035, -0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
P:(0.29999998211860657, -0.30000004172325134, -0.30000001192092896), U:(1.0009549856185913, 0.24900218844413757), N:(0.5773491859436035, -0.5773491859436035, -0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
F:1 M:0 N:(-1.000000,0.000000,0.000000) S:F
P:(-0.30000004172325134, -0.29999998211860657, 0.30000001192092896), U:(0.7509981393814087, 0.4989590346813202), N:(-0.5773491859436035, -0.5773491859436035, 0.5773491859436035), C:(0.12941177189350128, 0.0235294122248888, 1.0)
P:(-0.29999998211860657, 0.30000004172325134, 0.30000001192092896), U:(0.5010417103767395, 0.4989592134952545), N:(-0.5773491859436035, 0.5773491859436035, 0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
P:(-0.29999998211860657, 0.30000004172325134, -0.30000001192092896), U:(0.5010412931442261, 0.24900269508361816), N:(-0.5773491859436035, 0.5773491859436035, -0.5773491859436035), C:(0.11372549086809158, 0.003921568859368563, 1.0)
P:(-0.30000004172325134, -0.29999998211860657, -0.30000001192092896), U:(0.7509979009628296, 0.2490023672580719), N:(-0.5773491859436035, -0.5773491859436035, -0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
F:2 M:0 N:(0.000000,1.000000,0.000000) S:F
P:(-0.29999998211860657, 0.30000004172325134, 0.30000001192092896), U:(0.5010417103767395, 0.4989592134952545), N:(-0.5773491859436035, 0.5773491859436035, 0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
P:(0.30000004172325134, 0.29999998211860657, 0.30000001192092896), U:(0.2510852813720703, 0.49895963072776794), N:(0.5773491859436035, 0.5773491859436035, 0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
P:(0.30000004172325134, 0.29999998211860657, -0.30000001192092896), U:(0.2510848045349121, 0.24900305271148682), N:(0.5773491859436035, 0.5773491859436035, -0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
P:(-0.29999998211860657, 0.30000004172325134, -0.30000001192092896), U:(0.5010412931442261, 0.24900269508361816), N:(-0.5773491859436035, 0.5773491859436035, -0.5773491859436035), C:(0.11372549086809158, 0.003921568859368563, 1.0)
F:3 M:0 N:(1.000000,-0.000000,0.000000) S:F
P:(0.30000004172325134, 0.29999998211860657, 0.30000001192092896), U:(0.2510852813720703, 0.49895963072776794), N:(0.5773491859436035, 0.5773491859436035, 0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
P:(0.29999998211860657, -0.30000004172325134, 0.30000001192092896), U:(0.0011286735534667969, 0.4989601671695709), N:(0.5773491859436035, -0.5773491859436035, 0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
P:(0.29999998211860657, -0.30000004172325134, -0.30000001192092896), U:(0.001128166913986206, 0.2490035593509674), N:(0.5773491859436035, -0.5773491859436035, -0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
P:(0.30000004172325134, 0.29999998211860657, -0.30000001192092896), U:(0.2510848045349121, 0.24900305271148682), N:(0.5773491859436035, 0.5773491859436035, -0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
F:4 M:0 N:(0.000000,-0.000000,-1.000000) S:F
P:(0.29999998211860657, -0.30000004172325134, -0.30000001192092896), U:(1.0009549856185913, 0.24900218844413757), N:(0.5773491859436035, -0.5773491859436035, -0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
P:(-0.30000004172325134, -0.29999998211860657, -0.30000001192092896), U:(0.7509979009628296, 0.2490023672580719), N:(-0.5773491859436035, -0.5773491859436035, -0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
P:(-0.29999998211860657, 0.30000004172325134, -0.30000001192092896), U:(0.75099778175354, -0.0009548366069793701), N:(-0.5773491859436035, 0.5773491859436035, -0.5773491859436035), C:(0.11372549086809158, 0.003921568859368563, 1.0)
P:(0.30000004172325134, 0.29999998211860657, -0.30000001192092896), U:(1.0009549856185913, -0.0009549558162689209), N:(0.5773491859436035, 0.5773491859436035, -0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
F:5 M:0 N:(0.000000,-0.000000,1.000000) S:F
P:(0.30000004172325134, 0.29999998211860657, 0.30000001192092896), U:(1.0009549856185913, 0.7489159107208252), N:(0.5773491859436035, 0.5773491859436035, 0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
P:(-0.29999998211860657, 0.30000004172325134, 0.30000001192092896), U:(0.7509981393814087, 0.7489157915115356), N:(-0.5773491859436035, 0.5773491859436035, 0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
P:(-0.30000004172325134, -0.29999998211860657, 0.30000001192092896), U:(0.7509981393814087, 0.4989590346813202), N:(-0.5773491859436035, -0.5773491859436035, 0.5773491859436035), C:(0.12941177189350128, 0.0235294122248888, 1.0)
P:(0.29999998211860657, -0.30000004172325134, 0.30000001192092896), U:(1.0009549856185913, 0.49895909428596497), N:(0.5773491859436035, -0.5773491859436035, 0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
Name:WheelFtPort
Parent:CarBody
M:0-FrontPortMaterial T:SimplifiedCarFrontPort.png C:(0.800000011920929, 0.800000011920929, 0.800000011920929)
WMR0:(1.0, 0.0, 0.0, -0.9599999785423279)
WMR1:(0.0, 1.0, 0.0, 0.9999998211860657)
WMR2:(0.0, 0.0, 1.0, 0.30000001192092896)
WMR3:(0.0, 0.0, 0.0, 1.0)
F:0 M:0 N:(-0.000000,-1.000000,0.000000) S:F
P:(0.29999998211860657, -0.30000004172325134, 0.30000001192092896), U:(0.25004422664642334, 0.25004151463508606), N:(0.5773491859436035, -0.5773491859436035, 0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
P:(-0.30000004172325134, -0.29999998211860657, 0.30000001192092896), U:(0.5000007748603821, 0.2500423192977905), N:(-0.5773491859436035, -0.5773491859436035, 0.5773491859436035), C:(0.12941177189350128, 0.0235294122248888, 1.0)
P:(-0.30000004172325134, -0.29999998211860657, -0.30000001192092896), U:(0.5000001788139343, 0.49999886751174927), N:(-0.5773491859436035, -0.5773491859436035, -0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
P:(0.29999998211860657, -0.30000004172325134, -0.30000001192092896), U:(0.2500433921813965, 0.49999815225601196), N:(0.5773491859436035, -0.5773491859436035, -0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
F:1 M:0 N:(-1.000000,0.000000,0.000000) S:F
P:(-0.30000004172325134, -0.29999998211860657, 0.30000001192092896), U:(0.5000007748603821, 0.2500423192977905), N:(-0.5773491859436035, -0.5773491859436035, 0.5773491859436035), C:(0.12941177189350128, 0.0235294122248888, 1.0)
P:(-0.29999998211860657, 0.30000004172325134, 0.30000001192092896), U:(0.7499570846557617, 0.2500428855419159), N:(-0.5773491859436035, 0.5773491859436035, 0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
P:(-0.29999998211860657, 0.30000004172325134, -0.30000001192092896), U:(0.7499568462371826, 0.4999992251396179), N:(-0.5773491859436035, 0.5773491859436035, -0.5773491859436035), C:(0.11372549086809158, 0.003921568859368563, 1.0)
P:(-0.30000004172325134, -0.29999998211860657, -0.30000001192092896), U:(0.5000001788139343, 0.49999886751174927), N:(-0.5773491859436035, -0.5773491859436035, -0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
F:2 M:0 N:(0.000000,1.000000,0.000000) S:F
P:(-0.29999998211860657, 0.30000004172325134, 0.30000001192092896), U:(0.7499570846557617, 0.2500428855419159), N:(-0.5773491859436035, 0.5773491859436035, 0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
P:(0.30000004172325134, 0.29999998211860657, 0.30000001192092896), U:(0.9999133348464966, 0.2500429153442383), N:(0.5773491859436035, 0.5773491859436035, 0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
P:(0.30000004172325134, 0.29999998211860657, -0.30000001192092896), U:(0.999913215637207, 0.49999916553497314), N:(0.5773491859436035, 0.5773491859436035, -0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
P:(-0.29999998211860657, 0.30000004172325134, -0.30000001192092896), U:(0.7499568462371826, 0.4999992251396179), N:(-0.5773491859436035, 0.5773491859436035, -0.5773491859436035), C:(0.11372549086809158, 0.003921568859368563, 1.0)
F:3 M:0 N:(1.000000,-0.000000,0.000000) S:F
P:(0.30000004172325134, 0.29999998211860657, 0.30000001192092896), U:(8.738040924072266e-05, 0.2500404715538025), N:(0.5773491859436035, 0.5773491859436035, 0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
P:(0.29999998211860657, -0.30000004172325134, 0.30000001192092896), U:(0.25004422664642334, 0.25004151463508606), N:(0.5773491859436035, -0.5773491859436035, 0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
P:(0.29999998211860657, -0.30000004172325134, -0.30000001192092896), U:(0.2500433921813965, 0.49999815225601196), N:(0.5773491859436035, -0.5773491859436035, -0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
P:(0.30000004172325134, 0.29999998211860657, -0.30000001192092896), U:(8.654594421386719e-05, 0.49999719858169556), N:(0.5773491859436035, 0.5773491859436035, -0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
F:4 M:0 N:(0.000000,-0.000000,-1.000000) S:F
P:(0.29999998211860657, -0.30000004172325134, -0.30000001192092896), U:(0.9999133944511414, 0.749955415725708), N:(0.5773491859436035, -0.5773491859436035, -0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
P:(-0.30000004172325134, -0.29999998211860657, -0.30000001192092896), U:(0.7499570846557617, 0.7499555945396423), N:(-0.5773491859436035, -0.5773491859436035, -0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
P:(-0.29999998211860657, 0.30000004172325134, -0.30000001192092896), U:(0.7499568462371826, 0.4999992251396179), N:(-0.5773491859436035, 0.5773491859436035, -0.5773491859436035), C:(0.11372549086809158, 0.003921568859368563, 1.0)
P:(0.30000004172325134, 0.29999998211860657, -0.30000001192092896), U:(0.999913215637207, 0.49999916553497314), N:(0.5773491859436035, 0.5773491859436035, -0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
F:5 M:0 N:(0.000000,-0.000000,1.000000) S:F
P:(0.30000004172325134, 0.29999998211860657, 0.30000001192092896), U:(0.9999133348464966, 0.2500429153442383), N:(0.5773491859436035, 0.5773491859436035, 0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
P:(-0.29999998211860657, 0.30000004172325134, 0.30000001192092896), U:(0.7499570846557617, 0.2500428855419159), N:(-0.5773491859436035, 0.5773491859436035, 0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
P:(-0.30000004172325134, -0.29999998211860657, 0.30000001192092896), U:(0.7499572038650513, 8.666515350341797e-05), N:(-0.5773491859436035, -0.5773491859436035, 0.5773491859436035), C:(0.12941177189350128, 0.0235294122248888, 1.0)
P:(0.29999998211860657, -0.30000004172325134, 0.30000001192092896), U:(0.9999133944511414, 8.678436279296875e-05), N:(0.5773491859436035, -0.5773491859436035, 0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
Name:FtPortPropeller
Parent:WheelFtPort
M:0-FrontPortPropelerMaterial T:SimplifiedCarFrontPortProp.png C:(0.800000011920929, 0.800000011920929, 0.800000011920929)
WMR0:(1.0, 0.0, 0.0, -1.25)
WMR1:(0.0, 1.0, 0.0, 1.0)
WMR2:(0.0, 0.0, 1.0, 0.3333300054073334)
WMR3:(0.0, 0.0, 0.0, 1.0)
F:0 M:0 N:(-1.000000,0.000000,0.000000) S:F
P:(-0.02500000037252903, -0.20000000298023224, 0.05000000074505806), U:(0.501366138458252, 0.5319569706916809), N:(-0.5773491859436035, -0.5773491859436035, 0.5773491859436035), C:(0.0,0.0,0.0,0.0)
P:(-0.02500000037252903, 0.20000000298023224, 0.05000000074505806), U:(0.05822812020778656, 0.5319639444351196), N:(-0.5773491859436035, 0.5773491859436035, 0.5773491859436035), C:(0.0,0.0,0.0,0.0)
P:(-0.02500000037252903, 0.20000000298023224, -0.05000000074505806), U:(0.05822690576314926, 0.4211801588535309), N:(-0.5773491859436035, 0.5773491859436035, -0.5773491859436035), C:(0.0,0.0,0.0,0.0)
P:(-0.02500000037252903, -0.20000000298023224, -0.05000000074505806), U:(0.5013640522956848, 0.42117220163345337), N:(-0.5773491859436035, -0.5773491859436035, -0.5773491859436035), C:(0.0,0.0,0.0,0.0)
F:1 M:0 N:(0.000000,1.000000,-0.000000) S:F
P:(-0.02500000037252903, 0.20000000298023224, 0.05000000074505806), U:(0.05822812020778656, 0.5319639444351196), N:(-0.5773491859436035, 0.5773491859436035, 0.5773491859436035), C:(0.0,0.0,0.0,0.0)
P:(0.02500000037252903, 0.20000000298023224, 0.05000000074505806), U:(0.0028362085577100515, 0.5319638848304749), N:(0.5773491859436035, 0.5773491859436035, 0.5773491859436035), C:(0.0,0.0,0.0,0.0)
P:(0.02500000037252903, 0.20000000298023224, -0.05000000074505806), U:(0.0028361277654767036, 0.4211793541908264), N:(0.5773491859436035, 0.5773491859436035, -0.5773491859436035), C:(0.0,0.0,0.0,0.0)
P:(-0.02500000037252903, 0.20000000298023224, -0.05000000074505806), U:(0.05822690576314926, 0.4211801588535309), N:(-0.5773491859436035, 0.5773491859436035, -0.5773491859436035), C:(0.0,0.0,0.0,0.0)
F:2 M:0 N:(1.000000,0.000000,-0.000000) S:F
P:(0.02500000037252903, 0.20000000298023224, 0.05000000074505806), U:(0.9999024271965027, 0.5319446325302124), N:(0.5773491859436035, 0.5773491859436035, 0.5773491859436035), C:(0.0,0.0,0.0,0.0)
P:(0.02500000037252903, -0.20000000298023224, 0.05000000074505806), U:(0.5567590594291687, 0.531956136226654), N:(0.5773491859436035, -0.5773491859436035, 0.5773491859436035), C:(0.0,0.0,0.0,0.0)
P:(0.02500000037252903, -0.20000000298023224, -0.05000000074505806), U:(0.5567563772201538, 0.4211706221103668), N:(0.5773491859436035, -0.5773491859436035, -0.5773491859436035), C:(0.0,0.0,0.0,0.0)
P:(0.02500000037252903, 0.20000000298023224, -0.05000000074505806), U:(0.999899685382843, 0.4211588203907013), N:(0.5773491859436035, 0.5773491859436035, -0.5773491859436035), C:(0.0,0.0,0.0,0.0)
F:3 M:0 N:(0.000000,-1.000000,0.000000) S:F
P:(0.02500000037252903, -0.20000000298023224, 0.05000000074505806), U:(0.5567590594291687, 0.531956136226654), N:(0.5773491859436035, -0.5773491859436035, 0.5773491859436035), C:(0.0,0.0,0.0,0.0)
P:(-0.02500000037252903, -0.20000000298023224, 0.05000000074505806), U:(0.501366138458252, 0.5319569706916809), N:(-0.5773491859436035, -0.5773491859436035, 0.5773491859436035), C:(0.0,0.0,0.0,0.0)
P:(-0.02500000037252903, -0.20000000298023224, -0.05000000074505806), U:(0.5013640522956848, 0.42117220163345337), N:(-0.5773491859436035, -0.5773491859436035, -0.5773491859436035), C:(0.0,0.0,0.0,0.0)
P:(0.02500000037252903, -0.20000000298023224, -0.05000000074505806), U:(0.5567563772201538, 0.4211706221103668), N:(0.5773491859436035, -0.5773491859436035, -0.5773491859436035), C:(0.0,0.0,0.0,0.0)
F:4 M:0 N:(-0.000000,0.000000,-1.000000) S:F
P:(-0.02500000037252903, -0.20000000298023224, -0.05000000074505806), U:(0.0554872564971447, 9.955011773854494e-05), N:(-0.5773491859436035, -0.5773491859436035, -0.5773491859436035), C:(0.0,0.0,0.0,0.0)
P:(-0.02500000037252903, 0.20000000298023224, -0.05000000074505806), U:(0.05822690576314926, 0.4211801588535309), N:(-0.5773491859436035, 0.5773491859436035, -0.5773491859436035), C:(0.0,0.0,0.0,0.0)
P:(0.02500000037252903, 0.20000000298023224, -0.05000000074505806), U:(0.0028361277654767036, 0.4211793541908264), N:(0.5773491859436035, 0.5773491859436035, -0.5773491859436035), C:(0.0,0.0,0.0,0.0)
P:(0.02500000037252903, -0.20000000298023224, -0.05000000074505806), U:(9.761026012711227e-05, 9.761026012711227e-05), N:(0.5773491859436035, -0.5773491859436035, -0.5773491859436035), C:(0.0,0.0,0.0,0.0)
F:5 M:0 N:(-0.000000,0.000000,1.000000) S:F
P:(0.02500000037252903, -0.20000000298023224, 0.05000000074505806), U:(0.005591780412942171, 0.953059732913971), N:(0.5773491859436035, -0.5773491859436035, 0.5773491859436035), C:(0.0,0.0,0.0,0.0)
P:(0.02500000037252903, 0.20000000298023224, 0.05000000074505806), U:(0.0028362085577100515, 0.5319638848304749), N:(0.5773491859436035, 0.5773491859436035, 0.5773491859436035), C:(0.0,0.0,0.0,0.0)
P:(-0.02500000037252903, 0.20000000298023224, 0.05000000074505806), U:(0.05822812020778656, 0.5319639444351196), N:(-0.5773491859436035, 0.5773491859436035, 0.5773491859436035), C:(0.0,0.0,0.0,0.0)
P:(-0.02500000037252903, -0.20000000298023224, 0.05000000074505806), U:(0.060983531177043915, 0.9530596733093262), N:(-0.5773491859436035, -0.5773491859436035, 0.5773491859436035), C:(0.0,0.0,0.0,0.0)
Name:WheelFtStarboard
Parent:CarBody
M:0-FrontStarboardMaterial T:SimplifiedCarFrontPort.png C:(0.800000011920929, 0.800000011920929, 0.800000011920929)
WMR0:(1.0, 0.0, 0.0, 0.949999988079071)
WMR1:(0.0, 1.0, 0.0, 1.0)
WMR2:(0.0, 0.0, 1.0, 0.30000001192092896)
WMR3:(0.0, 0.0, 0.0, 1.0)
F:0 M:0 N:(-0.000000,-1.000000,0.000000) S:F
P:(0.29999998211860657, -0.30000004172325134, 0.30000001192092896), U:(0.7499573230743408, 0.25004249811172485), N:(0.5773491859436035, -0.5773491859436035, 0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
P:(-0.30000004172325134, -0.29999998211860657, 0.30000001192092896), U:(0.9999132752418518, 0.25004273653030396), N:(-0.5773491859436035, -0.5773491859436035, 0.5773491859436035), C:(0.12941177189350128, 0.0235294122248888, 1.0)
P:(-0.30000004172325134, -0.29999998211860657, -0.30000001192092896), U:(0.999913215637207, 0.49999862909317017), N:(-0.5773491859436035, -0.5773491859436035, -0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
P:(0.29999998211860657, -0.30000004172325134, -0.30000001192092896), U:(0.7499569654464722, 0.4999988079071045), N:(0.5773491859436035, -0.5773491859436035, -0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
F:1 M:0 N:(-1.000000,0.000000,0.000000) S:F
P:(-0.30000004172325134, -0.29999998211860657, 0.30000001192092896), U:(8.830868318909779e-05, 0.2500384449958801), N:(-0.5773491859436035, -0.5773491859436035, 0.5773491859436035), C:(0.12941177189350128, 0.0235294122248888, 1.0)
P:(-0.29999998211860657, 0.30000004172325134, 0.30000001192092896), U:(0.2500448524951935, 0.2500401735305786), N:(-0.5773491859436035, 0.5773491859436035, 0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
P:(-0.29999998211860657, 0.30000004172325134, -0.30000001192092896), U:(0.2500433325767517, 0.49999675154685974), N:(-0.5773491859436035, 0.5773491859436035, -0.5773491859436035), C:(0.11372549086809158, 0.003921568859368563, 1.0)
P:(-0.30000004172325134, -0.29999998211860657, -0.30000001192092896), U:(8.658744627609849e-05, 0.4999949634075165), N:(-0.5773491859436035, -0.5773491859436035, -0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
F:2 M:0 N:(0.000000,1.000000,0.000000) S:F
P:(-0.29999998211860657, 0.30000004172325134, 0.30000001192092896), U:(0.2500448524951935, 0.2500401735305786), N:(-0.5773491859436035, 0.5773491859436035, 0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
P:(0.30000004172325134, 0.29999998211860657, 0.30000001192092896), U:(0.5000011920928955, 0.250041663646698), N:(0.5773491859436035, 0.5773491859436035, 0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
P:(0.30000004172325134, 0.29999998211860657, -0.30000001192092896), U:(0.5000001192092896, 0.4999980628490448), N:(0.5773491859436035, 0.5773491859436035, -0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
P:(-0.29999998211860657, 0.30000004172325134, -0.30000001192092896), U:(0.2500433325767517, 0.49999675154685974), N:(-0.5773491859436035, 0.5773491859436035, -0.5773491859436035), C:(0.11372549086809158, 0.003921568859368563, 1.0)
F:3 M:0 N:(1.000000,-0.000000,0.000000) S:F
P:(0.30000004172325134, 0.29999998211860657, 0.30000001192092896), U:(0.5000011920928955, 0.250041663646698), N:(0.5773491859436035, 0.5773491859436035, 0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
P:(0.29999998211860657, -0.30000004172325134, 0.30000001192092896), U:(0.7499573230743408, 0.25004249811172485), N:(0.5773491859436035, -0.5773491859436035, 0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
P:(0.29999998211860657, -0.30000004172325134, -0.30000001192092896), U:(0.7499569654464722, 0.4999988079071045), N:(0.5773491859436035, -0.5773491859436035, -0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
P:(0.30000004172325134, 0.29999998211860657, -0.30000001192092896), U:(0.5000001192092896, 0.4999980628490448), N:(0.5773491859436035, 0.5773491859436035, -0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
F:4 M:0 N:(0.000000,-0.000000,-1.000000) S:F
P:(0.29999998211860657, -0.30000004172325134, -0.30000001192092896), U:(0.7499569654464722, 0.4999988079071045), N:(0.5773491859436035, -0.5773491859436035, -0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
P:(-0.30000004172325134, -0.29999998211860657, -0.30000001192092896), U:(0.999913215637207, 0.49999862909317017), N:(-0.5773491859436035, -0.5773491859436035, -0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
P:(-0.29999998211860657, 0.30000004172325134, -0.30000001192092896), U:(0.9999135136604309, 0.7499545216560364), N:(-0.5773491859436035, 0.5773491859436035, -0.5773491859436035), C:(0.11372549086809158, 0.003921568859368563, 1.0)
P:(0.30000004172325134, 0.29999998211860657, -0.30000001192092896), U:(0.7499575614929199, 0.7499548196792603), N:(0.5773491859436035, 0.5773491859436035, -0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
F:5 M:0 N:(0.000000,-0.000000,1.000000) S:F
P:(0.30000004172325134, 0.29999998211860657, 0.30000001192092896), U:(0.7499576210975647, 8.658744627609849e-05), N:(0.5773491859436035, 0.5773491859436035, 0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
P:(-0.29999998211860657, 0.30000004172325134, 0.30000001192092896), U:(0.9999135136604309, 8.686506771482527e-05), N:(-0.5773491859436035, 0.5773491859436035, 0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
P:(-0.30000004172325134, -0.29999998211860657, 0.30000001192092896), U:(0.9999132752418518, 0.25004273653030396), N:(-0.5773491859436035, -0.5773491859436035, 0.5773491859436035), C:(0.12941177189350128, 0.0235294122248888, 1.0)
P:(0.29999998211860657, -0.30000004172325134, 0.30000001192092896), U:(0.7499573230743408, 0.25004249811172485), N:(0.5773491859436035, -0.5773491859436035, 0.5773491859436035), C:(0.10980392247438431, 0.0, 1.0)
Name:FtStarboardPropeller
Parent:WheelFtStarboard
M:0-FrontStarboardPropMaterial T:SimplifiedCarFrontPortProp.png C:(0.800000011920929, 0.800000011920929, 0.800000011920929)
WMR0:(1.0, 0.0, 0.0, 1.25)
WMR1:(0.0, 1.0, 0.0, 1.0)
WMR2:(0.0, 0.0, 1.0, 0.3333300054073334)
WMR3:(0.0, 0.0, 0.0, 1.0)
F:0 M:0 N:(-1.000000,0.000000,0.000000) S:F
P:(-0.02500000037252903, -0.20000000298023224, 0.05000000074505806), U:(0.9997372627258301, 0.5350660681724548), N:(-0.5773491859436035, -0.5773491859436035, 0.5773491859436035), C:(0.0,0.0,0.0,0.0)
P:(-0.02500000037252903, 0.20000000298023224, 0.05000000074505806), U:(0.5566012263298035, 0.5350320935249329), N:(-0.5773491859436035, 0.5773491859436035, 0.5773491859436035), C:(0.0,0.0,0.0,0.0)
P:(-0.02500000037252903, 0.20000000298023224, -0.05000000074505806), U:(0.5566093921661377, 0.42424821853637695), N:(-0.5773491859436035, 0.5773491859436035, -0.5773491859436035), C:(0.0,0.0,0.0,0.0)
P:(-0.02500000037252903, -0.20000000298023224, -0.05000000074505806), U:(0.999745786190033, 0.4242819547653198), N:(-0.5773491859436035, -0.5773491859436035, -0.5773491859436035), C:(0.0,0.0,0.0,0.0)
F:1 M:0 N:(0.000000,1.000000,-0.000000) S:F
P:(-0.02500000037252903, 0.20000000298023224, 0.05000000074505806), U:(0.5566012263298035, 0.5350320935249329), N:(-0.5773491859436035, 0.5773491859436035, 0.5773491859436035), C:(0.0,0.0,0.0,0.0)
P:(0.02500000037252903, 0.20000000298023224, 0.05000000074505806), U:(0.501209557056427, 0.5350278615951538), N:(0.5773491859436035, 0.5773491859436035, 0.5773491859436035), C:(0.0,0.0,0.0,0.0)
P:(0.02500000037252903, 0.20000000298023224, -0.05000000074505806), U:(0.5012171864509583, 0.4242442846298218), N:(0.5773491859436035, 0.5773491859436035, -0.5773491859436035), C:(0.0,0.0,0.0,0.0)
P:(-0.02500000037252903, 0.20000000298023224, -0.05000000074505806), U:(0.5566093921661377, 0.42424821853637695), N:(-0.5773491859436035, 0.5773491859436035, -0.5773491859436035), C:(0.0,0.0,0.0,0.0)
F:2 M:0 N:(1.000000,0.000000,-0.000000) S:F
P:(0.02500000037252903, 0.20000000298023224, 0.05000000074505806), U:(0.501209557056427, 0.5350278615951538), N:(0.5773491859436035, 0.5773491859436035, 0.5773491859436035), C:(0.0,0.0,0.0,0.0)
P:(0.02500000037252903, -0.20000000298023224, 0.05000000074505806), U:(0.05807733163237572, 0.5349979400634766), N:(0.5773491859436035, -0.5773491859436035, 0.5773491859436035), C:(0.0,0.0,0.0,0.0)
P:(0.02500000037252903, -0.20000000298023224, -0.05000000074505806), U:(0.05808385834097862, 0.42421552538871765), N:(0.5773491859436035, -0.5773491859436035, -0.5773491859436035), C:(0.0,0.0,0.0,0.0)
P:(0.02500000037252903, 0.20000000298023224, -0.05000000074505806), U:(0.5012171864509583, 0.4242442846298218), N:(0.5773491859436035, 0.5773491859436035, -0.5773491859436035), C:(0.0,0.0,0.0,0.0)
F:3 M:0 N:(0.000000,-1.000000,0.000000) S:F
P:(0.02500000037252903, -0.20000000298023224, 0.05000000074505806), U:(0.05807733163237572, 0.5349979400634766), N:(0.5773491859436035, -0.5773491859436035, 0.5773491859436035), C:(0.0,0.0,0.0,0.0)
P:(-0.02500000037252903, -0.20000000298023224, 0.05000000074505806), U:(0.0026867054402828217, 0.5349938869476318), N:(-0.5773491859436035, -0.5773491859436035, 0.5773491859436035), C:(0.0,0.0,0.0,0.0)
P:(-0.02500000037252903, -0.20000000298023224, -0.05000000074505806), U:(0.0026956163346767426, 0.4242139160633087), N:(-0.5773491859436035, -0.5773491859436035, -0.5773491859436035), C:(0.0,0.0,0.0,0.0)
P:(0.02500000037252903, -0.20000000298023224, -0.05000000074505806), U:(0.05808385834097862, 0.42421552538871765), N:(0.5773491859436035, -0.5773491859436035, -0.5773491859436035), C:(0.0,0.0,0.0,0.0)
F:4 M:0 N:(-0.000000,0.000000,-1.000000) S:F
P:(-0.02500000037252903, -0.20000000298023224, -0.05000000074505806), U:(0.0026956163346767426, 0.4242139160633087), N:(-0.5773491859436035, -0.5773491859436035, -0.5773491859436035), C:(0.0,0.0,0.0,0.0)
P:(-0.02500000037252903, 0.20000000298023224, -0.05000000074505806), U:(-5.901232361793518e-05, 0.0031646303832530975), N:(-0.5773491859436035, 0.5773491859436035, -0.5773491859436035), C:(0.0,0.0,0.0,0.0)
P:(0.02500000037252903, 0.20000000298023224, -0.05000000074505806), U:(0.055326636880636215, 0.0031646303832530975), N:(0.5773491859436035, 0.5773491859436035, -0.5773491859436035), C:(0.0,0.0,0.0,0.0)
P:(0.02500000037252903, -0.20000000298023224, -0.05000000074505806), U:(0.05808385834097862, 0.42421552538871765), N:(0.5773491859436035, -0.5773491859436035, -0.5773491859436035), C:(0.0,0.0,0.0,0.0)
F:5 M:0 N:(-0.000000,0.000000,1.000000) S:F
P:(0.02500000037252903, -0.20000000298023224, 0.05000000074505806), U:(0.05807733163237572, 0.5349979400634766), N:(0.5773491859436035, -0.5773491859436035, 0.5773491859436035), C:(0.0,0.0,0.0,0.0)
P:(0.02500000037252903, 0.20000000298023224, 0.05000000074505806), U:(0.06080096587538719, 0.956089973449707), N:(0.5773491859436035, 0.5773491859436035, 0.5773491859436035), C:(0.0,0.0,0.0,0.0)
P:(-0.02500000037252903, 0.20000000298023224, 0.05000000074505806), U:(0.005409713834524155, 0.9560858607292175), N:(-0.5773491859436035, 0.5773491859436035, 0.5773491859436035), C:(0.0,0.0,0.0,0.0)
P:(-0.02500000037252903, -0.20000000298023224, 0.05000000074505806), U:(0.0026867054402828217, 0.5349938869476318), N:(-0.5773491859436035, -0.5773491859436035, 0.5773491859436035), C:(0.0,0.0,0.0,0.0)
Total Unique Vertices:60
Total Faces:46
Total Materials:0

 

There is no advantage to exporting to a binary format unless that binary format can be loaded straight into your data types, which at the very least would require a much greater knowledge of Python. What you really want to do is load your model class with this data and then serialize it so that the binary model file perfectly matches your model class data and thus is most efficient for loading into the model class to load a model. So, whatever you export, it's probably going to get converted; so it might as well be human readable.

 

This format is similar in some ways to the OBJ format which might be a good one to learn as well.

 

I called this file format the PUNC file format for Position, UV, Normal, Color as that's the data in the vertices. The first line allows you to verify that it is a PUNC file. The second line identifies the type of PUNC file as I was planning on a separate format for skinned animation from the rigid animation format. Then it goes into a loop of model parts/meshes. The first line in the loop is the sub-mesh name which in this case is the body of the car. If the sub-mesh has a parent because it was parented in Blender the second line in the loop will identify which sub-mesh is it's parent. (I believe there are two ways to parent something in Blender and one works for this and the other doesn't, but I can't remember off the top of my head what that is.)  The CarBody has no parent, which makes it the root mesh and it will be the parent of all the others (which are wheels).

 

The next line identifies the material used for the sub-mesh. I think this allows multiple materials per sub-mesh assigning each a number starting from 0. Then the T identifies any texture image file used for that material and C identifies any color used for the entire material.

 

After that it has the WMR lines. This is a world/object matrix for the sub-mesh. I think WMR stood for "World Matrix Row". It's just a 4 by 4 world matrix. These matrices are the relative positions and offsets of each sub-mesh from each other as assigned in Blender. In this case, this positions the wheels relative to the car body. And the body is an identity matrix basically placing it at the world origin.

 

Then it goes into another sub-loop describing "faces". This is going to use a triangle list rather than a triangle strip or triangle fan. So, it's basically a list of triangles. But Blender basically does things in faces rather than in triangles. So, the first face has four vertices. You have to figure out how to break this up into triangles. I assume all Blender faces have co-planar triangles, which means it should not matter how you assign the edges to triangulate the face. I usually triangulate the model in Blender before exporting. I've only tested this format a little and so there may still be some bugs. I think the most complicated model I tested with was Blender's Suzanne monkey.

 

But for each face it gives the material number which references the texture and color at the beginning. Then it defines a face normal. And I think the S value was for flat shading or smooth shading allowing some faces to be smooth and others faceted in the same sub-mesh. As I get better at modeling, I am appreciating that more. Then it's a vertex list of all the vertices in that face, their positions, UV coordinates, vertex normals, and colors. Note that you may not always use all of these values. UV coordinates and vertex colors are often mutually exclusive. You tend to use one or the other, but not both. You can use both, which is why it's like this. But usually you either use a texture or vertex colors and not both at the same time.

 

So, then it just repeats that loop going through every face of the sub-mesh and expecting you to break the faces up into triangles. The list ends when you hit the name of the next sub-mesh. I don't think the sub-meshes are in parent-child order and so you may have to read them in and then figure out which is the parent and which is the child.

 

The file ends when it lists the "Total Unique Vertices". Looks like that total number of materials is broken. I don't think I actually used those last 3 lines when reading the data back in. But that's basically all there is to it. It allows you to build a vertex buffer. And there's enough info there to build an index buffer if you want. My code loads the entire model and all its sub-meshes into a single vertex buffer and then uses offsets in the buffer for each sub-mesh.


In my C++ code, I used two classes for the model. I have a Model Compiler class that reads this file and I have a RigidModel class that it reads the data into. The model class looks like this:

[b]RigidModel.h[/b]

#pragma once
#include <d3d11.h>
#include <DirectXMath.h>
#include <DxErr.h>
#include <vector>        //NOT actual vectors. These are dynamic arrays.
#include "TextureClass.h"
#include "ShaderClass.h"

struct PUNCVERTEX{ DirectX::XMFLOAT3 Position; DirectX::XMFLOAT2 UV; DirectX::XMFLOAT3 Normal; DirectX::XMFLOAT4 Color; };    //Describes the structure of our vertices.


//__declspec(align(16)) class MeshPart
class MeshPart
{
public:
    MeshPart();
    ~MeshPart();
    void Shutdown();
    void AddChild(MeshPart* Child);
    void Draw(ID3D11DeviceContext* GraphicsDeviceContext, ID3D11Buffer* VertexBuffer, ID3D11Buffer* IndexBuffer,
        DirectX::CXMMATRIX View, DirectX::CXMMATRIX Projection, ShaderClass Shader, XMFLOAT3 DiffuseLightDirection,
        XMFLOAT4 AmbientLightColor, XMFLOAT4 DiffuseLightColor, DirectX::CXMMATRIX FamilyWorld);
    std::string Name;
    DirectX::XMFLOAT4X4 World;
    unsigned int FirstVertexInBuffer;
    unsigned int FirstIndexInBuffer;
    unsigned int VerticesInThisMeshPart;
    unsigned int IndicesInThismeshPart;
    TextureClass* Texture;
    std::vector<MeshPart*> Children;
};


class RigidModel
{
public:
    RigidModel();
    ~RigidModel();
    bool RigidModel::BuildModelFromBuffer(PUNCVERTEX* VertexArray, int VerticesInModel,
        int* IndexArray, int IndicesInModel,
        ID3D11Device* GraphicsDevice, ID3D11DeviceContext* GraphicsDeviceContext);
    void Draw(ID3D11DeviceContext* GraphicsDeviceContext, CXMMATRIX View, CXMMATRIX Projection, ShaderClass Shader,
        XMFLOAT3 DiffuseLightDirection, XMFLOAT4 AmbientLightColor, XMFLOAT4 DiffuseLightColor);
    void Shutdown();
    std::string Name;
    MeshPart Root;
private:
    int VerticesInMesh;                            //Number of vertices used in the mesh.
    int IndicesInMesh;                            //Number of indices used in the index buffer.
    ID3D11Buffer* VertexBuffer;                 //The pointer to the vertex buffer
    ID3D11Buffer* IndexBuffer;                    //The pointer to the index buffer.
};

 

[b]RigidModel.cpp]/b]

#include "RigidModel.h"


RigidModel::RigidModel()
{
}


RigidModel::~RigidModel()
{
    Shutdown();
}


bool RigidModel::BuildModelFromBuffer(PUNCVERTEX* VertexArray, int VerticesInModel,
    int* IndexArray, int IndicesInModel,
    ID3D11Device* GraphicsDevice, ID3D11DeviceContext* GraphicsDeviceContext)
{
    D3D11_BUFFER_DESC VertexBufferDescription;                //The settings for the vertex buffer.
    D3D11_SUBRESOURCE_DATA VertexBufferSubResourceData;        //How a sub-resource is to be
    D3D11_BUFFER_DESC IndexBufferDescription;                //The settings for the index buffer.
    D3D11_SUBRESOURCE_DATA IndexBufferSubResourceData;        //How a sub-resource is to be
    bool ModelCreatedSuccessfully = false;


    if (VertexBuffer == nullptr)    //Don't try and create a vertex buffer for the object if it's already created.
    {
        VerticesInMesh = VerticesInModel;                                            //We might want this info later so remember it.
        ZeroMemory(&VertexBufferDescription, sizeof(VertexBufferDescription));        //Initialize memory to zeros.
        VertexBufferDescription.Usage = D3D11_USAGE_DYNAMIC;                        //Read-write access type for CPU and GPU
        VertexBufferDescription.ByteWidth = sizeof(PUNCVERTEX) * VerticesInMesh;    //Total size of the vertex buffer.
        VertexBufferDescription.BindFlags = D3D11_BIND_VERTEX_BUFFER;                //Buffer is a vertex buffer.
        VertexBufferDescription.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;            //Allow CPU to write in buffer.

        VertexBufferSubResourceData.pSysMem = VertexArray;
        VertexBufferSubResourceData.SysMemPitch = NULL;
        VertexBufferSubResourceData.SysMemSlicePitch = NULL;


        if (SUCCEEDED(GraphicsDevice->CreateBuffer(&VertexBufferDescription, &VertexBufferSubResourceData, &VertexBuffer)))    //Create the vertex buffer or stop if it fails.
        {
            IndicesInMesh = IndicesInModel;
            ZeroMemory(&IndexBufferDescription, sizeof(IndexBufferDescription));
            IndexBufferDescription.Usage = D3D11_USAGE_DEFAULT;
            IndexBufferDescription.ByteWidth = sizeof(int) * IndicesInMesh;            //Total size of the index buffer.
            IndexBufferDescription.BindFlags = D3D11_BIND_INDEX_BUFFER;            //Buffer is an index buffer.
            IndexBufferDescription.CPUAccessFlags = NULL;    
            IndexBufferDescription.MiscFlags = NULL;


            IndexBufferSubResourceData.pSysMem = IndexArray;
            IndexBufferSubResourceData.SysMemPitch = NULL;
            IndexBufferSubResourceData.SysMemSlicePitch = NULL;
            if (SUCCEEDED(GraphicsDevice->CreateBuffer(&IndexBufferDescription, &IndexBufferSubResourceData, &IndexBuffer)))    //Create the vertex buffer or stop if it fails.
            {
                ModelCreatedSuccessfully = true;
            }
        }
    }

    return ModelCreatedSuccessfully;
}


void RigidModel::Shutdown()
{
    if (VertexBuffer != nullptr)
    {
        VertexBuffer->Release();
        VertexBuffer = nullptr;
    }

    Root.Shutdown();
}

void RigidModel::Draw(ID3D11DeviceContext* GraphicsDeviceContext, DirectX::CXMMATRIX View, DirectX::CXMMATRIX Projection, ShaderClass Shader,
    XMFLOAT3 DiffuseLightDirection, XMFLOAT4 AmbientLightColor, XMFLOAT4 DiffuseLightColor)
{
    Root.Draw(GraphicsDeviceContext, VertexBuffer, IndexBuffer, View, Projection, Shader, DiffuseLightDirection, AmbientLightColor, DiffuseLightColor, DirectX::XMMatrixIdentity());
}

MeshPart::MeshPart()
{
    XMStoreFloat4x4(&World, DirectX::XMMatrixIdentity());
    Name.clear();
    Texture = nullptr;
    FirstVertexInBuffer = 0;
    VerticesInThisMeshPart = 0;
    IndicesInThismeshPart = 0;
}

MeshPart::~MeshPart()
{
    Shutdown();
}


void MeshPart::Shutdown()
{
    //Shutdown all children.
    for (auto Child : Children)
    {
        Child->Shutdown();
        //_aligned_free(Child);
        delete Child;
        Child = nullptr;
    }
    Children.clear();
    //Then Shutdown self.
    if (Texture != nullptr)
    {
        delete Texture;
        Texture = nullptr;
    }
}


void MeshPart::AddChild(MeshPart* Child)
{
    Children.push_back(Child);
}


void MeshPart::Draw(ID3D11DeviceContext* GraphicsDeviceContext, ID3D11Buffer* VertexBuffer, ID3D11Buffer* IndexBuffer,
    DirectX::CXMMATRIX View, DirectX::CXMMATRIX Projection, ShaderClass Shader,    XMFLOAT3 DiffuseLightDirection,
    XMFLOAT4 AmbientLightColor, XMFLOAT4 DiffuseLightColor, DirectX::CXMMATRIX FamilyWorld)
{
    UINT Stride = sizeof(PUNCVERTEX);    //Stride is the size of 1 vertex in memory.
    UINT Offset = 0;
    UINT IndexOffset = 0;
    DirectX::XMMATRIX RelationalWorld;

    RelationalWorld = XMLoadFloat4x4(&World) * FamilyWorld;    //This makes the submesh's world matrix relative to its parent which is relevant to its parent and so on.
    if (Texture == nullptr)
    {
        Shader.Settings(GraphicsDeviceContext, RelationalWorld, View, Projection, DiffuseLightDirection, AmbientLightColor, DiffuseLightColor, nullptr, 0.0f);
    }
    else
    {
        Shader.Settings(GraphicsDeviceContext, RelationalWorld, View, Projection, DiffuseLightDirection, AmbientLightColor, DiffuseLightColor, Texture->ResourceView(), 2.0f);
    }
    //Offset = FirstVertexInBuffer * sizeof(PUNCVERTEX);        //Offset is in bytes. FirstVertexInBuffer is in vertices.
    //IndexOffset = FirstIndexInBuffer * sizeof(int);
    GraphicsDeviceContext->IASetVertexBuffers(0, 1, &VertexBuffer, &Stride, &Offset);    //Select which vertex buffer to display.
    GraphicsDeviceContext->IASetIndexBuffer(IndexBuffer, DXGI_FORMAT_R32_UINT, IndexOffset);
    GraphicsDeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);    //Select which primtive type we are using.
    GraphicsDeviceContext->DrawIndexed(IndicesInThismeshPart, FirstIndexInBuffer, FirstVertexInBuffer);        //Not using DrawIndexed. Draw the Bottom.


    if (Children.size() > 0)
    {
        for (auto Child : Children)
        {
            Child->Draw(GraphicsDeviceContext, VertexBuffer, IndexBuffer, View, Projection, Shader, DiffuseLightDirection, AmbientLightColor, DiffuseLightColor, RelationalWorld);
        }
    }
}

 

And this class loads the data into the RigidModel class from the Python export:

[b]ModelCompiler.h[/b]

#pragma once
#include <fstream>
#include <sstream>
#include "RigidModel.h"
#include "StringConversions.h"


class Face
{
public:
    int CountVertices();
    int CountTriangles();
    Face();
    Face(std::string Header);
    void AddVertex(std::string CodedVertexString);
    PUNCVERTEX GetVertex(int VertexNumber);
private:
    unsigned int Number;
    unsigned int MaterialNumber;
    DirectX::XMFLOAT3 FaceNormal;
    bool SmoothShaded;
    std::vector<PUNCVERTEX> VerticesInFace;
};


class Material
{
public:
    Material();
    //Material(int No, std::string TextureFile, DirectX::XMFLOAT4 RGBColor);
    int Number;
    std::string Name;
    std::string Texture;
    DirectX::XMFLOAT4 Color;
};


class MeshPiece
{
public:
    std::string Name;
    std::string Parent;
    DirectX::XMFLOAT4X4 World;
    std::vector<Material> Materials;
    std::vector<PUNCVERTEX> Vertices;
    std::vector<Face> Faces;
    std::vector<PUNCVERTEX> MeshPiece::GetVertices();
private:
    void GetVerticesFromFaces();
};


class ModelCompiler
{
public:
    ModelCompiler();
    ~ModelCompiler();
    bool Build(RigidModel &Model, std::string FileName, ID3D11Device* GraphicsDevice, ID3D11DeviceContext* GraphicsDeviceContext);
    bool CreateModel(RigidModel &Model, std::vector<MeshPiece> SubMeshList, std::string TexturesFolder, ID3D11Device* GraphicsDevice,
        ID3D11DeviceContext* GraphicsDeviceContext);
    bool SaveToDisk(RigidModel &ModelToSave, PUNCVERTEX* VertexArray, int VerticesInModel, int* IndexArray, int IndicesInModel);
private:
    std::vector<MeshPiece> SubMeshes;
    Material CreateMaterial(std::string UnparsedText);
    void GetChildren(MeshPart* Parent, std::vector<PUNCVERTEX> &VertexBufferBuildList,
        std::vector<int> &IndexBufferBuildList, int &NumberOfVerticesAdded, int &NumberOfIndicesAdded,
        std::vector<MeshPiece>, std::string TexturesFolder, ID3D11Device* GraphicsDevice);
    void GetModelBuffers(PUNCVERTEX* &VertexBufferPtr, int &TotalNumberOfVertices,
        int* &IndexBufferPtr, int &TotalNumberOfIndices, std::vector<PUNCVERTEX> &VertexList);
    void GetPartBuffers(std::vector<PUNCVERTEX> &PartVertices, std::vector<PUNCVERTEX> &VertexBufferBuildList,
        std::vector<int> &IndexBufferBuildList, int &NumberOfVerticesAdded, int &NumberOfIndicesAdded);
    bool VerticesAreEqual(PUNCVERTEX A, PUNCVERTEX B);
    void SaveChildrenToDisk(int NumberOfChildren, MeshPart &Part, std::ofstream &ModelFile);
};

 

[b]ModelCompiler.cpp[/b]

#include "ModelCompiler.h"


ModelCompiler::ModelCompiler()
{
}


ModelCompiler::~ModelCompiler()
{
    //Free all the memory we allocated for the submeshes.
    for (auto Part : SubMeshes)
    {
        delete &Part;
    }
}


bool ModelCompiler::Build(RigidModel &Model, std::string FileName, ID3D11Device* GraphicsDevice, ID3D11DeviceContext* GraphicsDeviceContext)
{
    bool ModelCreatedSuccessfully = false;
    bool LoadedCorrectly = false;
    StringConversions StringConverter;
    std::ifstream InputFile(FileName);
    std::string LineOfText;
    unsigned int LineNumber = 0;
    MeshPiece* SubMesh = nullptr;
    std::string MatrixRow1 = "";
    std::string MatrixRow2 = "";
    std::string MatrixRow3 = "";
    


    std::getline(InputFile, LineOfText);
    if (LineOfText == "Punc!It Text")
    {
        //LineNumber++;
        std::getline(InputFile, LineOfText);
        if (LineOfText == "Rigid Animation")
        {
            //LineNumber++;
            std::getline(InputFile, LineOfText);
            while (!InputFile.eof())
            {
                if (LineOfText.substr(0, 5) == "Name:")
                {
                    if (SubMesh != nullptr) SubMeshes.push_back(*SubMesh);        //Every time you read a name it is a new submesh in the model so store the one just built.
                    SubMesh = new MeshPiece();                                //Start to build a new submesh.
                    SubMesh->Name = LineOfText.substr(5, LineOfText.length() - 5);    //Get the name of the submesh.
                    std::getline(InputFile, LineOfText);
                }
                else if (LineOfText.substr(0, 2) == "P:")
                {
                    //Line should already be processed as part of face, so just ignore it and go on.
                    std::getline(InputFile, LineOfText);
                }
                else if (LineOfText.substr(0, 2) == "F:")
                {
                    Face NewFace(LineOfText);
                    std::getline(InputFile, LineOfText);
                    while (LineOfText.substr(0, 2) == "P:")
                    {
                        NewFace.AddVertex(LineOfText);
                        std::getline(InputFile, LineOfText);
                    }
                    SubMesh->Faces.push_back(NewFace);
                }
                else if (LineOfText.substr(0, 2) == "M:")
                {
                    Material NewMaterial;
                    NewMaterial = CreateMaterial(LineOfText);
                    SubMesh->Materials.push_back(NewMaterial);
                    std::getline(InputFile, LineOfText);
                }
                else if (LineOfText.substr(0, 5) == "WMR0:")
                {
                    MatrixRow1 = LineOfText;
                    std::getline(InputFile, LineOfText);
                }
                else if (LineOfText.substr(0, 5) == "WMR1:")
                {
                    MatrixRow2 = LineOfText;
                    std::getline(InputFile, LineOfText);
                }
                else if (LineOfText.substr(0, 5) == "WMR2:")
                {
                    MatrixRow3 = LineOfText;
                    std::getline(InputFile, LineOfText);
                }
                else if (LineOfText.substr(0, 5) == "WMR3:")
                {
                    DirectX::XMStoreFloat4x4(&SubMesh->World, StringConverter.StringsToMatrix(MatrixRow1, MatrixRow2, MatrixRow3, LineOfText));
                    MatrixRow1.clear(); MatrixRow2.clear(); MatrixRow3.clear();
                    std::getline(InputFile, LineOfText);
                }
                else if (LineOfText.substr(0, 7) == "Parent:")
                {
                    SubMesh->Parent = LineOfText.substr(7, LineOfText.size() - 7);
                    std::getline(InputFile, LineOfText);
                }
                else if (LineOfText.substr(0, 22) == "Total Unique Vertices:")
                {
                    if (SubMesh != nullptr) SubMeshes.push_back(*SubMesh);    //EoF so a new Name: line will not be reached but we still need to save the submesh.
                    std::getline(InputFile, LineOfText);
                }
                else std::getline(InputFile, LineOfText);
            }
            InputFile.close();
            int LastSlash = FileName.find_last_of("/");
            int FileExtensionStart = FileName.find(".txt");
            Model.Name = FileName.substr(LastSlash + 1, FileExtensionStart - LastSlash -1);

            ModelCreatedSuccessfully = CreateModel(Model, SubMeshes, "./Models/", GraphicsDevice, GraphicsDeviceContext);
        }
    }
    return ModelCreatedSuccessfully;
}


Material ModelCompiler::CreateMaterial(std::string UnparsedText)
{
    Material NewMaterial;
    StringConversions StringConverter;
    std::vector<std::string> Delimiters;
    std::vector<std::string> ParsedStrings;
    std::string ColorValues;

    Delimiters.push_back("M:");
    Delimiters.push_back("-");
    Delimiters.push_back("T:");
    Delimiters.push_back("C:(");
    Delimiters.push_back(")");
    StringConverter.Parse(UnparsedText, Delimiters, ParsedStrings, true);
    Delimiters.clear();

    NewMaterial.Number = std::stoi(ParsedStrings[0]);
    NewMaterial.Name = ParsedStrings[1];
    NewMaterial.Texture = ParsedStrings[2];
    ColorValues = ParsedStrings[3];
    Delimiters.push_back(",");
    ParsedStrings.clear();
    StringConverter.Parse(ColorValues, Delimiters, ParsedStrings, false);
    NewMaterial.Color.x = std::stof(ParsedStrings[0]);    //Red
    NewMaterial.Color.y = std::stof(ParsedStrings[1]);    //Green
    NewMaterial.Color.z = std::stof(ParsedStrings[2]);    //Blue
    NewMaterial.Color.w = 1.0f;    //Set alpha to 100%. Blender does not export an alpha value.
    return NewMaterial;
}


bool ModelCompiler::CreateModel(RigidModel &Model, std::vector<MeshPiece> SubMeshList, std::string TexturesFolder, ID3D11Device* GraphicsDevice,
    ID3D11DeviceContext* GraphicsDeviceContext)
{
    bool ModelCreatedSuccessfully = false;
    std::vector<MeshPart> PartsTree;
    PUNCVERTEX* VertexBufferPtr = nullptr;
    int* IndexBufferPtr = nullptr;
    int NumberOfIndices = 0;
    int TotalNumberOfVertices = 0;
    int TotalNumberOfIndices = 0;
    std::vector<PUNCVERTEX> BuildList;
    std::vector<PUNCVERTEX> VertexList;
    std::vector<int> IndexList;
    int Root = -1;

    MeshPart* RootMeshPart = &Model.Root;
    std::vector<MeshPiece>::iterator MeshListIterator;
    TextureClass* NewTexture;
    bool ExitLoop = false;


    MeshListIterator = SubMeshList.begin();
    while (!ExitLoop)
    {
        
        if (MeshListIterator->Parent == "None")
        {
            Root = (int) (MeshListIterator - SubMeshList.begin());    //Store the index withing the vector to the root mesh of the model.
            ExitLoop = true;
        }
        if (MeshListIterator == SubMeshList.end()) ExitLoop = true;
            else MeshListIterator++;
    }
    
    RootMeshPart->Name = SubMeshList[Root].Name;
    RootMeshPart->World = SubMeshList[Root].World;
    if (SubMeshList[Root].Materials.size() > 0)    //No materials means there are no textures.
    {
        NewTexture = new TextureClass();
        NewTexture->Load(TexturesFolder + SubMeshList[Root].Materials[0].Texture, GraphicsDevice);    //Only handles 1 material. Probably need to change this.
        RootMeshPart->Texture = NewTexture;
    }
    RootMeshPart->FirstVertexInBuffer = 0;
    BuildList = SubMeshList[Root].GetVertices();
    
    GetPartBuffers(BuildList, VertexList, IndexList, TotalNumberOfVertices, TotalNumberOfIndices);
    
    RootMeshPart->VerticesInThisMeshPart = (int) TotalNumberOfVertices;
    RootMeshPart->IndicesInThismeshPart = (int)TotalNumberOfIndices;
    
    GetChildren(RootMeshPart, VertexList, IndexList, TotalNumberOfVertices, TotalNumberOfIndices, SubMeshList, TexturesFolder, GraphicsDevice);

    DirectX::XMMATRIX RotatedWorld;
    RotatedWorld = DirectX::XMLoadFloat4x4(&RootMeshPart->World);
    RotatedWorld *= DirectX::XMMatrixRotationX(-DirectX::XM_PIDIV2);    //Conversion to correct Blender world coordinate system difference to DX coordinate system.
    DirectX::XMStoreFloat4x4(&RootMeshPart->World, RotatedWorld);
    
    VertexBufferPtr = new PUNCVERTEX[TotalNumberOfVertices];
    IndexBufferPtr = new int[TotalNumberOfIndices];

    ZeroMemory(VertexBufferPtr, sizeof(PUNCVERTEX) * TotalNumberOfVertices);
    for (int VertexNumber = 0; VertexNumber < TotalNumberOfVertices; VertexNumber++)
    {
        VertexBufferPtr[VertexNumber] = VertexList[VertexNumber];
    }

    ZeroMemory(IndexBufferPtr, sizeof(int) * TotalNumberOfIndices);
    for (int IndexNumber = 0; IndexNumber < TotalNumberOfIndices; IndexNumber++)
    {
        IndexBufferPtr[IndexNumber] = IndexList[IndexNumber];
    }

    ModelCreatedSuccessfully = Model.BuildModelFromBuffer(VertexBufferPtr, TotalNumberOfVertices,
        IndexBufferPtr, TotalNumberOfIndices, GraphicsDevice, GraphicsDeviceContext);

    //Save Model to File.
    if (ModelCreatedSuccessfully)
        ModelCreatedSuccessfully = SaveToDisk(Model, VertexBufferPtr, TotalNumberOfVertices, IndexBufferPtr, TotalNumberOfIndices);

    delete[] VertexBufferPtr;    //Vertex buffer has been copied to an ID3D11Buffer and this array we allocated is no longer needed after that.
    VertexBufferPtr = nullptr;
    delete[] IndexBufferPtr;
    IndexBufferPtr = nullptr;

    return ModelCreatedSuccessfully;
}


bool ModelCompiler::SaveToDisk(RigidModel &ModelToSave, PUNCVERTEX* VertexArray, int VerticesInModel,
    int* IndexArray, int IndicesInModel)
{
    bool SavedProperly = false;
    //std::string ModelFileName = ModelToSave.Name;
    std::ofstream ModelFile;
    const char* FileID{"Rigid Model File"};

    ModelFile.open("CompiledModel.RMF", std::ios_base::binary);
    ModelFile.write(FileID, 16);
    ModelFile.write((char*)&VerticesInModel, sizeof(VerticesInModel));
    ModelFile.write((char*)VertexArray, sizeof(PUNCVERTEX)*VerticesInModel);
    ModelFile.write((char*)&IndicesInModel, sizeof(IndicesInModel));
    ModelFile.write((char*)IndexArray, sizeof(int)*IndicesInModel);
    ModelFile.write(ModelToSave.Name.c_str(), ModelToSave.Name.size()+1);    //Write the string with the null terminator.
    //Write Root.
    ModelFile.write(ModelToSave.Root.Name.c_str(), ModelToSave.Root.Name.size() + 1);    //Write root node name with the string null terminator.
    ModelFile.write((char*)&ModelToSave.Root.FirstVertexInBuffer, sizeof(unsigned int));
    ModelFile.write((char*)&ModelToSave.Root.VerticesInThisMeshPart, sizeof(unsigned int));
    ModelFile.write((char*)&ModelToSave.Root.FirstIndexInBuffer, sizeof(unsigned int));
    ModelFile.write((char*)&ModelToSave.Root.IndicesInThismeshPart, sizeof(unsigned int));
    ModelFile.write((char*)&ModelToSave.Root.World._11, sizeof(float));    //World Matrix.
    ModelFile.write((char*)&ModelToSave.Root.World._12, sizeof(float));
    ModelFile.write((char*)&ModelToSave.Root.World._13, sizeof(float));
    ModelFile.write((char*)&ModelToSave.Root.World._14, sizeof(float));
    ModelFile.write((char*)&ModelToSave.Root.World._21, sizeof(float));
    ModelFile.write((char*)&ModelToSave.Root.World._22, sizeof(float));
    ModelFile.write((char*)&ModelToSave.Root.World._23, sizeof(float));
    ModelFile.write((char*)&ModelToSave.Root.World._24, sizeof(float));
    ModelFile.write((char*)&ModelToSave.Root.World._31, sizeof(float));
    ModelFile.write((char*)&ModelToSave.Root.World._32, sizeof(float));
    ModelFile.write((char*)&ModelToSave.Root.World._33, sizeof(float));
    ModelFile.write((char*)&ModelToSave.Root.World._34, sizeof(float));
    ModelFile.write((char*)&ModelToSave.Root.World._41, sizeof(float));
    ModelFile.write((char*)&ModelToSave.Root.World._42, sizeof(float));
    ModelFile.write((char*)&ModelToSave.Root.World._43, sizeof(float));
    ModelFile.write((char*)&ModelToSave.Root.World._44, sizeof(float));
    ModelFile.write(ModelToSave.Root.Texture->GetFileName().c_str(), ModelToSave.Root.Texture->GetFileName().size() + 1);
    int NumberOfChildren = ModelToSave.Root.Children.size();
    ModelFile.write((char*)&NumberOfChildren, sizeof(unsigned int));
    
    SaveChildrenToDisk(NumberOfChildren, ModelToSave.Root, ModelFile);

    ModelFile.close();    
    SavedProperly = true;

    return SavedProperly;
}


void ModelCompiler::SaveChildrenToDisk(int NumberOfChildren, MeshPart &Part, std::ofstream &ModelFile)
{
    if (NumberOfChildren > 0)
    {
        for (auto Child : Part.Children)
        {
            ModelFile.write(Child->Name.c_str(), Child->Name.size() + 1);    //Write the string with the null terminator.
            ModelFile.write((char*)&Child->FirstVertexInBuffer, sizeof(unsigned int));
            ModelFile.write((char*)&Child->VerticesInThisMeshPart, sizeof(unsigned int));
            ModelFile.write((char*)&Child->FirstIndexInBuffer, sizeof(unsigned int));
            ModelFile.write((char*)&Child->IndicesInThismeshPart, sizeof(unsigned int));
            ModelFile.write((char*)&Child->World._11, sizeof(float));    //World Matrix.
            ModelFile.write((char*)&Child->World._12, sizeof(float));
            ModelFile.write((char*)&Child->World._13, sizeof(float));
            ModelFile.write((char*)&Child->World._14, sizeof(float));
            ModelFile.write((char*)&Child->World._21, sizeof(float));
            ModelFile.write((char*)&Child->World._22, sizeof(float));
            ModelFile.write((char*)&Child->World._23, sizeof(float));
            ModelFile.write((char*)&Child->World._24, sizeof(float));
            ModelFile.write((char*)&Child->World._31, sizeof(float));
            ModelFile.write((char*)&Child->World._32, sizeof(float));
            ModelFile.write((char*)&Child->World._33, sizeof(float));
            ModelFile.write((char*)&Child->World._34, sizeof(float));
            ModelFile.write((char*)&Child->World._41, sizeof(float));
            ModelFile.write((char*)&Child->World._42, sizeof(float));
            ModelFile.write((char*)&Child->World._43, sizeof(float));
            ModelFile.write((char*)&Child->World._44, sizeof(float));
            ModelFile.write(Child->Texture->GetFileName().c_str(), Child->Texture->GetFileName().size() + 1);
            int NumberOfGrandChildren = Child->Children.size();
            ModelFile.write((char*)&NumberOfGrandChildren, sizeof(unsigned int));

            SaveChildrenToDisk(NumberOfGrandChildren, *Child, ModelFile);

        }
    }
}
 

bool ModelCompiler::VerticesAreEqual(PUNCVERTEX A, PUNCVERTEX B)
{
    return A.Position.x == B.Position.x
        && A.Position.y == B.Position.y
        && A.Position.z == B.Position.z
        && A.UV.x == B.UV.x
        && A.UV.y == B.UV.y
        && A.Normal.x == B.Normal.x
        && A.Normal.y == B.Normal.y
        && A.Normal.z == B.Normal.z
        && A.Color.x == B.Color.x
        && A.Color.y == B.Color.y
        && A.Color.z == B.Color.z
        && A.Color.w == B.Color.w;
}


void ModelCompiler::GetChildren(MeshPart* Parent, std::vector<PUNCVERTEX> &VertexBufferBuildList,
    std::vector<int> &IndexBufferBuildList, int &NumberOfVerticesAdded, int &NumberOfIndicesAdded,
    std::vector<MeshPiece> Meshs, std::string TexturesFolder, ID3D11Device* GraphicsDevice)
{
    std::vector<PUNCVERTEX> VerticesOfSubMesh;

    for (auto Mesh : Meshs)
    {
        if (Mesh.Parent == Parent->Name)
        {
            MeshPart* FoundChild = new MeshPart();
            FoundChild->Name = Mesh.Name;
            DirectX::XMMATRIX ParentsWorld = DirectX::XMLoadFloat4x4(&Parent->World);
            ParentsWorld = DirectX::XMMatrixInverse(nullptr, ParentsWorld);
            DirectX::XMMATRIX LocalWorld = DirectX::XMLoadFloat4x4(&Mesh.World);
            ParentsWorld = LocalWorld * ParentsWorld;
            DirectX::XMStoreFloat4x4(&FoundChild->World, ParentsWorld); //Multiplying by an inverse is basically subtracting one matrix from the other. Make children relative to parents.
    
            if (Mesh.Materials.size() > 0)
            {
                TextureClass* NewTexture = new TextureClass();
                NewTexture->Load(TexturesFolder + Mesh.Materials[0].Texture, GraphicsDevice);    //Only handles 1 material. Probably need to change this.
                FoundChild->Texture = NewTexture;
            }
            else FoundChild->Texture = nullptr;
            FoundChild->FirstVertexInBuffer = NumberOfVerticesAdded;
            FoundChild->FirstIndexInBuffer = NumberOfIndicesAdded;
            VerticesOfSubMesh = Mesh.GetVertices();

            GetPartBuffers(VerticesOfSubMesh, VertexBufferBuildList, IndexBufferBuildList, NumberOfVerticesAdded, NumberOfIndicesAdded);

            FoundChild->VerticesInThisMeshPart = NumberOfVerticesAdded - FoundChild->FirstVertexInBuffer;
            FoundChild->IndicesInThismeshPart = NumberOfIndicesAdded - FoundChild->FirstIndexInBuffer;

            GetChildren(FoundChild, VertexBufferBuildList, IndexBufferBuildList, NumberOfVerticesAdded,
                NumberOfIndicesAdded, Meshs, TexturesFolder, GraphicsDevice);

            Parent->AddChild(FoundChild);
            FoundChild = nullptr;
        }
    }
}


void ModelCompiler::GetPartBuffers(std::vector<PUNCVERTEX> &PartVertices, std::vector<PUNCVERTEX> &VertexBufferBuildList, std::vector<int> &IndexBufferBuildList,
    int &NumberOfVerticesAdded, int &NumberOfIndicesAdded)
{
    bool VertexFoundInList = false;
    int VertexFoundInPosition = -1;
    int NewPartIndex = 0;
    int IndicesPreviouslyAdded = NumberOfIndicesAdded;
    std::vector<PUNCVERTEX> TempBuildList;

    for (auto UnprocessedVertex : PartVertices)
    {
        //Find Vertex in VerticesOfSubMesh.
        int ListPosition = -1;

        //for (auto FinalVertex : VertexBufferBuildList)
        for (auto FinalVertex : TempBuildList)
        {
            ListPosition++;
            if (VerticesAreEqual(FinalVertex, UnprocessedVertex))
            {
                VertexFoundInList = true;
                VertexFoundInPosition = ListPosition;
            }
        }
        if (!VertexFoundInList)    //Not in the new list, add it.
        {
            VertexBufferBuildList.push_back(UnprocessedVertex);
            TempBuildList.push_back(UnprocessedVertex);
            IndexBufferBuildList.push_back(NewPartIndex);
            NumberOfVerticesAdded++;
            NumberOfIndicesAdded++;
            NewPartIndex++;
        }
        else    //In the new list already, just add its position to the index list.
        {
            IndexBufferBuildList.push_back(VertexFoundInPosition);
            NumberOfIndicesAdded++;
            VertexFoundInList = false;
        }
        VertexFoundInPosition = -1;
    }
}



std::vector<PUNCVERTEX> MeshPiece::GetVertices()
{
    Vertices.clear();
    GetVerticesFromFaces();
    return Vertices;
}


void MeshPiece::GetVerticesFromFaces()
{
    int NumberOfTrianglesInFace = 0;

    for (auto Polygon : Faces)
    {
        NumberOfTrianglesInFace = Polygon.CountTriangles();

        switch (NumberOfTrianglesInFace)
        {
            case 1:
                Vertices.push_back(Polygon.GetVertex(2));
                Vertices.push_back(Polygon.GetVertex(1));
                Vertices.push_back(Polygon.GetVertex(0));
                break;
            case 2:
                Vertices.push_back(Polygon.GetVertex(2));
                Vertices.push_back(Polygon.GetVertex(1));
                Vertices.push_back(Polygon.GetVertex(0));

                Vertices.push_back(Polygon.GetVertex(0));
                Vertices.push_back(Polygon.GetVertex(3));
                Vertices.push_back(Polygon.GetVertex(2));
                break;
            case 3:
                Vertices.push_back(Polygon.GetVertex(2));
                Vertices.push_back(Polygon.GetVertex(1));
                Vertices.push_back(Polygon.GetVertex(0));

                Vertices.push_back(Polygon.GetVertex(0));
                Vertices.push_back(Polygon.GetVertex(3));
                Vertices.push_back(Polygon.GetVertex(2));

                Vertices.push_back(Polygon.GetVertex(0));
                Vertices.push_back(Polygon.GetVertex(4));
                Vertices.push_back(Polygon.GetVertex(3));
                break;
            case 4:
                Vertices.push_back(Polygon.GetVertex(2));
                Vertices.push_back(Polygon.GetVertex(1));
                Vertices.push_back(Polygon.GetVertex(0));

                Vertices.push_back(Polygon.GetVertex(0));
                Vertices.push_back(Polygon.GetVertex(3));
                Vertices.push_back(Polygon.GetVertex(2));

                Vertices.push_back(Polygon.GetVertex(0));
                Vertices.push_back(Polygon.GetVertex(4));
                Vertices.push_back(Polygon.GetVertex(3));

                Vertices.push_back(Polygon.GetVertex(0));
                Vertices.push_back(Polygon.GetVertex(5));
                Vertices.push_back(Polygon.GetVertex(4));
                break;
            default:
                //Unhandled exception with too many triangles to count
                break;
        }
    }
}


Face::Face()
{
    Number = 0;
    MaterialNumber = 0;
    FaceNormal = DirectX::XMFLOAT3(0.f, 0.f, 0.f);
    SmoothShaded = false;
    VerticesInFace.clear();
}

Face::Face(std::string Header)
{
    StringConversions StringConverter;
    std::vector<std::string> Delimiters;
    std::vector<std::string> ParsedStrings;

    Delimiters.push_back("F:");
    Delimiters.push_back("M:");
    Delimiters.push_back("N:(");
    Delimiters.push_back(") S:");
    Delimiters.push_back(",");
    StringConverter.Parse(Header, Delimiters, ParsedStrings, true);
    Number = std::stoul(ParsedStrings[0]);
    MaterialNumber = std::stoul(ParsedStrings[1]);
    FaceNormal.x = std::stof(ParsedStrings[2]);
    FaceNormal.y = std::stof(ParsedStrings[3]);
    FaceNormal.z = std::stof(ParsedStrings[4]);
    if (ParsedStrings[5] == "T") SmoothShaded = true;
        else SmoothShaded = false;
}


void Face::AddVertex(std::string CodedVertexString)
{
    StringConversions StringConverter;
    std::vector<std::string> Delimiters;
    std::vector<std::string> ParsedStrings;
    PUNCVERTEX NewVertex;
    DirectX::XMFLOAT2 TempUV;
    DirectX::XMFLOAT3 Vec3To4;


    ZeroMemory(&NewVertex, sizeof(NewVertex));
    Delimiters.push_back("P:(");
    Delimiters.push_back("), U:(");
    Delimiters.push_back("), N:(");
    Delimiters.push_back("), C:(");

    StringConverter.Parse(CodedVertexString, Delimiters, ParsedStrings, true);
    NewVertex.Position = StringConverter.StringToVector3(ParsedStrings[0]);
    TempUV = StringConverter.StringToVector2(ParsedStrings[1]);        //Store UV coordinates to temp value because Blender has the V(which is y) value inversed.
    NewVertex.UV.x = TempUV.x;
    NewVertex.UV.y = 1.0f - TempUV.y;
    NewVertex.Normal = StringConverter.StringToVector3(ParsedStrings[2]);
    Vec3To4 = StringConverter.StringToVector3(ParsedStrings[3]);
    NewVertex.Color = DirectX::XMFLOAT4(Vec3To4.x, Vec3To4.y, Vec3To4.z, 1.0f);    //Could be a bug because not stipping ) at the end of line.

    VerticesInFace.push_back(NewVertex);
}


int Face::CountVertices()
{
    return (int) VerticesInFace.size();
}


int Face::CountTriangles()
{
    int FaceVertices = (int) VerticesInFace.size();
    int TrianglesInFace = 0;

    if (FaceVertices > 2)
    {
        if (FaceVertices < 7)   //There could be more but we'll limit it for now.
        {
            if (FaceVertices == 3) TrianglesInFace = 1;
            if (FaceVertices == 4) TrianglesInFace = 2;
            if (FaceVertices == 5) TrianglesInFace = 3;
            if (FaceVertices == 6) TrianglesInFace = 4;
        }
    }

    return TrianglesInFace;
}


PUNCVERTEX Face::GetVertex(int VertexNumber)
{
    return VerticesInFace[VertexNumber];
}

Material::Material(void){}

 

The entire project is on my website for download including the Python script and the textures for the model. The Python above is the abreviated version. The Python file in the project file has a bunch of other Python scripts that may prove useful in understanding the Blender data and how it is organized. I found getting info on the Blender data to be next to impossible. I actually "discovered" the Blender data layout through trial and error by just fishing around until I figured it out over a couple of months. Fortunately, Blender is really good about helping you on these fishing expeditions. Still, a lot of what's in the full Python file is stuff that I fished around and found and will likely be useful in figuring the layout of the data.

http://virtuallyprogramming.com/DirectX11/Tutorials/Tutorials.html

0

Share this post


Link to post
Share on other sites

Posted (edited)

If I understood you right, you said you don't know how an index buffer works. It's pretty straight forward. The index buffer is just a list of which vertices to process in what order. This allows your vertices in your vertex buffer to be used out of order and multiple times. For example, a quad (rectangle) made up of two triangles, might have an edge where two of the vertices are identical in both triangles. They are shared vertices. So, instead of specifying 6 vertices for the two triangles you only have to specify 4 and two of them get re-used in both triangles.

 

In that case, your vertex buffer might looks something like: 0,1,2,2,1,4

 

The graphics card knows that every 3 vertices makes a triangle. So, the first triangle is 0,1,2 and the second is 2,1,4 where vertices 2 and 1 are used in both triangles. Then your vertex buffer only has 4 vertices instead of six making your vertex buffer a whole lot smaller and saving memory on the graphics card. For a 4 byte integer (I believe it is) you saved a vertex which in the PUNC case is something like 11 four byte floats I believe. It can save a huge amount of memory.

 

But all it really is is a list of which vertices to process in what order. Every 3 values is a triangle. At least, I believe that's the way it works with a Triangle List(It's been probably a year since I've written any graphics code). In a triangle strip, I believe every vertex is a new triangle and it uses the last two vertices defined to form the three sides of the triangle. In that case, all the triangles are connected by definition. So, it only takes one vertex (plus the previous two) to define a triangle. I would love to use triangle strips in my model (because they are substantially more efficient), but I doubt it's even possible. I gave up on that a long time ago and just use a triangle list.

 

Oh. Also be aware of your "winding". Back face culling will remove the backside of the triangle, if it is turned on. It determines which side is the backside by whether the vertices are defined clockwise or counter-clockwise. So, the order you define them in is important. You want back face culling on because it saves the graphics card from having to draw back faces that will never be seen by the camera such as the inside of an object. With an index buffer, you define your order using the index buffer. But index buffers are optional. Without an index buffer your order would be determined in the vertex buffer. Turn back face culling off for debugging, but otherwise you want it on.

Edited by BBeck
0

Share this post


Link to post
Share on other sites

Now that I think about it, some may find it useful to see my entire Python script collection. Like I said, the only way I could figure out Blender scripting was to just fish around and try things out. There was little to no instructions I could find on how Blender data is organized. These scripts are things I saved while fishing around that pulled certain types of data from Blender. I think there's some stuff in there for skinned animation as I see some references to armatures.

 

I wrote a program that extracted the animation data from Blender using the basic humanoid armature that is in Blender. I created the animations in Blender using the basic humanoid armature and then my script exported those animations to a text file. I then loaded the file into an XNA program where I played them back as stick figures. It worked. The stick figures moved just like the armatures in the Blender animations.

 

Looks like the code for that is on my website here:

http://virtuallyprogramming.com/XNATutorials/ThreeDTutorials/SecondTutorial/SecondTutorial.html

But it is an XNA project, not a DX project. Still, that should not matter if you are just interested in the Blender exporter. The Blender exporter should be the same regardless of whether it is XNA or DX. Wait, I was able to find what appears to be the Blender exporter to export the animations. I'll make that a separate post.

 

#Python scripts and code to output the model data and also experimenting.
#The final script in this file is the one used to produce the models for this NewFormat code.
bpy.data.objects['CarBody'].data.vertices[0].co
bpy.data.objects['CarBody'].data.vertices[0].normal
bpy.data.objects['CarBody'].data.vertices[0].index
bpy.data.objects['CarBody'].matrix_world


Must have "Textured Solid" selected in the "Shading" menu of the N-menu (Properties) to see colors.

bpy.context.active_object.name
bpy.context.active_object.type
bpy.context.active_object.type == 'MESH' #Verify selected object is a mesh rather than camera, etc.
bpy.context.active_object.active_material.name #Active Material is what's selected and not what the mesh uses.
len(bpy.data.materials) #Number of Materials Used.
bpy.data.materials[1].diffuse_color  #Color of material 1.
bpy.data.materials[0].name   #Name of Material Zero.
bpy.data.materials[0].use_textures[0]  #True or False.
bpy.data.materials[0].texture_slots['MyTexture'].texture.image.name
bpy.context.active_object.active_material.diffuse_color
bpy.context.active_object.data.vertices[0].co
bpy.context.active_object.data.vertex_colors.active.data[0].color
bpy.context.active_object.data.tessfaces[0].use_smooth    #smooth or flat shading.
bpy.data.objects['WheelFtPort'].data.materials[0].texture_slots[0].texture.image.name
bpy.context.active_object.active_material.texture_slots[0].texture.image


for clr in bpy.context.active_object.data.vertex_colors.active.data: print(clr.color)

bpy.context.active_object.children[3].data.tessfaces[0].material_index

#Material Index points back to the Material Slot # of the mesh?

##################################################################
ob = bpy.context.active_object


for face in ob.data.polygons:
                for vert, loop in zip(face.vertices, face.loop_indices):
                    for item in ob.data.vertices[vert].normal:  # normal
                        print("Normal: %d" % item)
                    for item in ob.data.vertices[vert].co:  # vertex
                        print("Vertex: %d" % item)
                    for item in (ob.data.uv_layers.active.data[loop].uv if ob.data.uv_layers.active is not None else (0.0, 0.0)):  # uv
                        print("UV: %d" % item)


##################################################################
# List Faces
for Face in bpy.context.active_object.data.polygons:
    for Vert, Loop in zip(Face.vertices, Face.loop_indices):
        print(Vert)
    print("\n")


# List Face UVs
for Face in bpy.context.active_object.data.polygons:
    for Vert, Loop in zip(Face.vertices, Face.loop_indices):
        print(str(tuple(bpy.context.active_object.data.uv_layers.active.data[Loop].uv)))
    print("\n")


# List Face PUNC
# Appears to be accurate, but greatly multiples the number of vertices.
for Face in bpy.context.active_object.data.polygons:
    for Vert, Loop in zip(Face.vertices, Face.loop_indices):
        print("P:%s" % str(tuple(bpy.context.active_object.data.vertices[Vert].co)))
        print("U:%s" % str(tuple(bpy.context.active_object.data.uv_layers.active.data[Loop].uv)))
        print("N:%s" % str(tuple(bpy.context.active_object.data.vertices[Vert].normal)))
        print("C:%s" % str(tuple(bpy.context.active_object.data.vertex_colors.active.data[Vert].color)))
    print("\n")


#print("X:%s" % str(tuple(bpy.context.active_object.data.uv_layers.active.data[Vert].uv))) #wrong


# List Face PUNC
# Appears to be accurate, but greatly multiples the number of vertices.
MatNo = 0
for Material in bpy.context.active_object.material_slots:
    print("M:", MatNo, " Name:", Material.name, " Texture:", Material.material.active_texture.name, " Image:", Material.material.active_texture.image.name)
    MatNo = MatNo + 1

for Face in bpy.context.active_object.data.polygons:
    print("Face Normal:", round(Face.normal[0],7), ",", round(Face.normal[1],7), ",", round(Face.normal[2],7))
    print("Face Normal:{:f}".format(Face.normal[0]), ",", "{:f}".format(Face.normal[1]), ",", "{:f}".format(Face.normal[2]))
    print("Face Normal:{0}".format(tuple(Face.normal)))
    print("Material:%d" % Face.material_index)
    for Vert, Loop in zip(Face.vertices, Face.loop_indices):
        Pos = str(tuple(bpy.context.active_object.data.vertices[Vert].co))
        UV = str(tuple(bpy.context.active_object.data.uv_layers.active.data[Loop].uv))
        Norm =str(tuple(bpy.context.active_object.data.vertices[Vert].normal))
        Col =str(tuple(bpy.context.active_object.data.vertex_colors.active.data[Vert].color))
        print("P:", Pos, " U:", UV, " N:", Norm, " C:", Col)
    print("\n")


#############################################################

#Count triangles
bpub
len(bpy.context.active_object.data.tessfaces)

#############################################################

#List vertices of each quad

for Face in bpy.context.active_object.data.polygons:
    for Vert, Loop in zip(Face.vertices, Face.loop_indices):
        print("Vertex:", Vert)
    print("Material:", Face.material_index)
#############################################################

#Another way to list the vertices of each quad
bpy.context.active_object.data.update(calc_tessface=True)
print(len(bpy.context.active_object.data.tessfaces))

for Triangles in bpy.context.active_object.data.tessfaces:
    print("Material: %d Vertices:" % Triangles.material_index, end='')
    for Verts in Triangles.vertices:
        print(" %d" % Verts, end='')
    print()

for Triangles in bpy.context.active_object.data.tessfaces:
    print("M:%d F:" % Triangles.material_index, end='')
    print(str(tuple(Triangles.vertices)))

#############################################################
bpy.context.active_object.name
bpy.context.active_object.data.vertices[0].co
bpy.context.active_object.data.vertices[0].index
bpy.context.active_object.data.vertices[0].normal
bpy.context.active_object.data.vertex_colors.active.data[0].color
bpy.context.active_object.data.uv_layers.active.data[0].uv



print(bpy.context.active_object.data.vertex_colors.active) #None if empty.
print(bpy.context.active_object.data.uv_layers.active) #None if empty.

bpy.context.active_object.children[0].data.vertex_colors.active.data[0].color #Color of the first child.

#detect if coordinates are present.
HasUVCoordinates = bpy.context.active_object.data.uv_layers.active
if HasUVCoordinates is None:
    print("True")




####################################################################
import bpy

def ProcessChildren(ParentMesh, ParentLabel, VerticesInModel, FacesInModel):  #Get all data for sub-meshes.
    VerticesSoFar = VerticesInModel
    FacesSoFar = FacesInModel
    NumberOfChildren = len(ParentMesh.children)
    if NumberOfChildren > 0:
        ChildLabel = ParentLabel + "==>"
        for ChildMesh in ParentMesh.children:
            print(ChildLabel, ChildMesh.name)
            VerticesSoFar = VerticesSoFar + len(ChildMesh.data.vertices)
            ChildMesh.data.update(calc_tessface=True)
            FacesSoFar = FacesSoFar + len(ChildMesh.data.tessfaces)
            VerticesSoFar, FacesSoFar = ProcessChildren(ChildMesh, ChildLabel, VerticesSoFar, FacesSoFar)
    return VerticesSoFar, FacesSoFar

if bpy.context.active_object.type == 'MESH':
    print(bpy.context.active_object.name)
    bpy.context.active_object.data.update(calc_tessface=True)
    VerticesInModel = len(bpy.context.active_object.data.vertices)
    FacesInModel = len(bpy.context.active_object.data.tessfaces)
    VerticesInModel, FacesInModel = ProcessChildren(bpy.context.active_object, "", VerticesInModel, FacesInModel)
    print("Total Vertices:%d" % VerticesInModel)
    print("Total Faces:%d" % FacesInModel)



####################################################################
#There is an assumption that there can only be one material/texture per mesh.
#Make sure the parent object is selected in ObjectMode and not EditMode.
import bpy

def ProcessChildren(ParentMesh, VerticesInModel, FacesInModel):  #Get all data for sub-meshes.
    VerticesSoFar = VerticesInModel
    FacesSoFar = FacesInModel
    NumberOfChildren = len(ParentMesh.children)
    if NumberOfChildren > 0:
        for ChildMesh in ParentMesh.children:
            HasUVCoordinates = ChildMesh.data.uv_layers.active
            HasVertexColors = ChildMesh.data.vertex_colors.active
            CountOfVertices = 0
            print("Name:%s" % ChildMesh.name)
            print("Parent:%s" % ChildMesh.parent.name)
            VerticesSoFar = VerticesSoFar + len(ChildMesh.data.vertices)
            ChildMesh.data.update(calc_tessface=True)
            FacesSoFar = FacesSoFar + len(ChildMesh.data.tessfaces)
            #Vertices.
            for Vertex in ChildMesh.data.vertices:
                print("P:%s" % str(tuple(Vertex.co)))
                if HasUVCoordinates is not None:
                    print(", U:%s" % str(ChildMesh.data.uv_layers.active.data[CountOfVertices].uv))
                else:
                    print(", U:(0.0,0.0)")
                print(", N:%s" % str(tuple(Vertex.normal)))
                if HasVertexColors is not None:
                    print(", C:%s" % str(tuple(ChildMesh.data.vertex_colors.active.data[CountOfVertices].color)))
                else:
                    print(", C:(0.0,0.0,0.0,0.0)")
                print("\n")
                CountOfVertices = CountOfVertices + 1
            #Faces.
            for Face in ChildMesh.data.tessfaces:
                print("F:%s" % str(tuple(Face.vertices)))
                print(" M:%s" % str(Face.material_index))
                print(" S:%s\n" % str(Face.use_smooth))
            #Call child's children.
            VerticesSoFar, FacesSoFar = ProcessChildren(ChildMesh, VerticesSoFar, FacesSoFar)
    return VerticesSoFar, FacesSoFar

if bpy.context.active_object != None and bpy.context.active_object.parent == None and bpy.context.active_object.type == 'MESH':
    print("Punc!It Text\n")
    HasUVCoordinates = bpy.context.active_object.data.uv_layers.active
    HasVertexColors = bpy.context.active_object.data.vertex_colors.active
    NumberOfMaterialsUsed = 0
    CountOfVertices = 0
    #Name.
    print("Name:%s" % bpy.context.active_object.name)
    print("Parent:Root")
    bpy.context.active_object.data.update(calc_tessface=True)
    VerticesInModel = len(bpy.context.active_object.data.vertices)
    FacesInModel = len(bpy.context.active_object.data.tessfaces)
    #Vertices.
    for Vertex in bpy.context.active_object.data.vertices:
        print("P:%s" % str(tuple(Vertex.co)))
        if HasUVCoordinates is not None:
            print(", U:%s" % str(bpy.context.active_object.data.uv_layers.active.data[CountOfVertices].uv))
        else:
            print(", U:(0.0,0.0)")
        print(", N:%s" % str(tuple(Vertex.normal)))
        if HasVertexColors is not None:
            print(", C:%s" % str(tuple(bpy.context.active_object.data.vertex_colors.active.data[CountOfVertices].color)))
        else:
            print(", C:(0.0,0.0,0.0,0.0)")
        print("\n")
        CountOfVertices = CountOfVertices + 1
    #Faces.
    for Face in bpy.context.active_object.data.tessfaces:
        print("F:%s" % str(tuple(Face.vertices)))
        print(" M:%s" % str(Face.material_index))
        print(" S:%s\n" % str(Face.use_smooth))
    #Children.
    VerticesInModel, FacesInModel = ProcessChildren(bpy.context.active_object, VerticesInModel, FacesInModel)
    #Materials.
    NumberOfMaterialsUsed = len(bpy.data.materials)
    if NumberOfMaterialsUsed > 0:
        MaterialNumber = 0
        for Material in bpy.data.materials:
            print("M:%d" % MaterialNumber)
            print(" T:%s" % bpy.data.materials[0].texture_slots['MyTexture'].texture.image.name)
            print(" C:%s\n" % str(tuple(bpy.context.active_object.data.vertex_colors.active.data[CountOfVertices].color)))
            MaterialNumber = MaterialNumber + 1
    else:
        print("M:None\n");
    print("Total Vertices:%d" % VerticesInModel)
    print("Total Faces:%d" % FacesInModel)
    print("Total Materials:%d" % NumberOfMaterialsUsed)
else:
    print("You must select the root object before running this script!")

####################################################################
import bpy

def ProcessChildren(f, ParentMesh, VerticesInModel, FacesInModel):  #Get all data for sub-meshes.
    VerticesSoFar = VerticesInModel
    FacesSoFar = FacesInModel
    NumberOfChildren = len(ParentMesh.children)
    if NumberOfChildren > 0:
        for ChildMesh in ParentMesh.children:
            HasUVCoordinates = ChildMesh.data.uv_layers.active
            HasVertexColors = ChildMesh.data.vertex_colors.active
            CountOfVertices = 0
            f.write("Name:%s\n" % ChildMesh.name)
            f.write("Parent:%s\n" % ChildMesh.parent.name)
            VerticesSoFar = VerticesSoFar + len(ChildMesh.data.vertices)
            ChildMesh.data.update(calc_tessface=True)
            FacesSoFar = FacesSoFar + len(ChildMesh.data.tessfaces)
            #Materials
            SubMeshMaterialNo = 0
            for Material in ChildMesh.material_slots:
                f.write("M:%d" % SubMeshMaterialNo)
                f.write(" T:%s" % Material.material.texture_slots[0].texture.image.name)
                f.write(" C:%s\n" % str(tuple(Material.material.diffuse_color)))
            #WorldMatrix
            WorldMatrixRowNumber = 0
            for WorldMatrixRow in ChildMesh.matrix_world.row:
                f.write("WMR%d" % WorldMatrixRowNumber)
                f.write(":%s\n" % str(tuple(WorldMatrixRow)))
                WorldMatrixRowNumber = WorldMatrixRowNumber + 1
            #Vertices.
            for Vertex in ChildMesh.data.vertices:
                f.write("P:%s" % str(tuple(Vertex.co)))
                if HasUVCoordinates is not None:
                    f.write(", U:%s" % str(tuple(ChildMesh.data.uv_layers.active.data[CountOfVertices].uv)))
                else:
                    f.write(", U:(0.0,0.0)")
                f.write(", N:%s" % str(tuple(Vertex.normal)))
                if HasVertexColors is not None:
                    f.write(", C:%s" % str(tuple(ChildMesh.data.vertex_colors.active.data[CountOfVertices].color)))
                else:
                    f.write(", C:(0.0,0.0,0.0,0.0)")
                f.write("\n")
                CountOfVertices = CountOfVertices + 1
            #Faces.
            for Face in ChildMesh.data.tessfaces:
                f.write("F:%s" % str(tuple(Face.vertices)))
                f.write(" M:%s" % str(Face.material_index))
                f.write(" S:%s\n" % str(Face.use_smooth)[0])
            #Call child's children.
            VerticesSoFar, FacesSoFar = ProcessChildren(f, ChildMesh, VerticesSoFar, FacesSoFar)
    return VerticesSoFar, FacesSoFar

def write_some_data(context, filepath):
    HasUVCoordinates = bpy.context.active_object.data.uv_layers.active
    HasVertexColors = bpy.context.active_object.data.vertex_colors.active
    print("Exporting data...")
    bpy.context.active_object.data.update(calc_tessface=True)         #calc_tessface=True must be set before working with faces.
    
    f = open(filepath, 'w', encoding='utf-8')
    if bpy.context.active_object != None and bpy.context.active_object.parent == None and bpy.context.active_object.type == 'MESH':
        CountOfVertices = 0
        NumberOfMaterialsUsed = 0
        FacesInModel = 0
        VerticesInModel = len(bpy.context.active_object.data.vertices)
        FacesInModel = len(bpy.context.active_object.data.tessfaces)
        f.write("Punc!It Text\n")
        f.write("Rigid Animation\n")
        f.write("Name:%s\n" % bpy.context.active_object.name)
        f.write("Parent:None\n")
        #Materials
        SubMeshMaterialNo = 0
        for Material in bpy.context.active_object.material_slots:
            f.write("M:%d" % SubMeshMaterialNo)
            f.write(" T:%s" % Material.material.texture_slots[0].texture.image.name)
            f.write(" C:%s\n" % str(tuple(Material.material.diffuse_color)))
        #WorldMatrix
        WorldMatrixRowNumber = 0
        for WorldMatrixRow in bpy.context.active_object.matrix_world.row:
            f.write("WMR%d" % WorldMatrixRowNumber)
            f.write(":%s\n" % str(tuple(WorldMatrixRow)))
            WorldMatrixRowNumber = WorldMatrixRowNumber + 1
        #Vertices.
        for Vertex in bpy.context.active_object.data.vertices:
            f.write("P:%s" % str(tuple(Vertex.co)))
            if HasUVCoordinates is not None:
                f.write(", U:%s" % str(tuple(bpy.context.active_object.data.uv_layers.active.data[CountOfVertices].uv)))
            else:
                f.write(", U:(0.0,0.0)")
            f.write(", N:%s" % str(tuple(Vertex.normal)))
            if HasVertexColors is not None:
                f.write(", C:%s" % str(tuple(bpy.context.active_object.data.vertex_colors.active.data[CountOfVertices].color)))
            else:
                f.write(", C:(0.0,0.0,0.0,0.0)")
            f.write("\n")
            CountOfVertices = CountOfVertices + 1
        #Faces.
        for Face in bpy.context.active_object.data.tessfaces:
            f.write("F:%s" % str(tuple(Face.vertices)))
            f.write(" M:%s" % str(Face.material_index))
            f.write(" S:%s\n" % str(Face.use_smooth)[0])  #T if smooth shading & F if flat shading.
        #Children.
        VerticesInModel, FacesInModel = ProcessChildren(f, bpy.context.active_object, VerticesInModel, FacesInModel)
        #Materials.
        #NumberOfMaterialsUsed = len(bpy.data.materials)
        #if NumberOfMaterialsUsed > 0:
        #    MaterialNumber = 0
        #    for Material in bpy.data.materials:
        #        f.write("M:%d" % MaterialNumber)
        #        f.write(" T:%s" % bpy.data.materials[MaterialNumber].texture_slots[0].texture.image.name)
        #        f.write(" C:%s\n" % str(tuple(bpy.data.materials[MaterialNumber].diffuse_color)))
        #        MaterialNumber = MaterialNumber + 1
        #else:
        #    f.write("M:None\n")
        #File Footer.
        f.write("Total Vertices:%d\n" % VerticesInModel)
        f.write("Total Faces:%d\n" % FacesInModel)
        f.write("Total Materials:%d" % NumberOfMaterialsUsed)
    else:
        f.write("You must select the root mesh before exporting the model!")
    f.close()
    
    return {'FINISHED'}


# ExportHelper is a helper class, defines filename and
# invoke() function which calls the file selector.
from bpy_extras.io_utils import ExportHelper
from bpy.props import StringProperty, BoolProperty, EnumProperty
from bpy.types import Operator


class ExportSomeData(Operator, ExportHelper):
    """This appears in the tooltip of the operator and in the generated docs"""
    bl_idname = "export_test.some_data"  # important since its how bpy.ops.import_test.some_data is constructed
    bl_label = "Export Button"

    # ExportHelper mixin class uses this
    filename_ext = ".txt"

    filter_glob = StringProperty(
            default="*.txt",
            options={'HIDDEN'},
            )

    def execute(self, context):
        return write_some_data(context, self.filepath)


# Only needed if you want to add into a dynamic menu
def menu_func_export(self, context):
    self.layout.operator(ExportSomeData.bl_idname, text="Custom Exporter Test")


def register():
    bpy.utils.register_class(ExportSomeData)
    bpy.types.INFO_MT_file_export.append(menu_func_export)


def unregister():
    bpy.utils.unregister_class(ExportSomeData)
    bpy.types.INFO_MT_file_export.remove(menu_func_export)


if __name__ == "__main__":
    register()

    # test call
    bpy.ops.export_test.some_data('INVOKE_DEFAULT')
=================================================================================

import bpy


def ProcessChildren(f, ParentMesh, VerticesInModel, FacesInModel):  #Get all data for sub-meshes.
    VerticesSoFar = VerticesInModel
    FacesSoFar = FacesInModel
    NumberOfChildren = len(ParentMesh.children)
    if NumberOfChildren > 0:
        for ChildMesh in ParentMesh.children:
            HasUVCoordinates = ChildMesh.data.uv_layers.active
            HasVertexColors = ChildMesh.data.vertex_colors.active
            CountOfVertices = 0
            f.write("Name:%s\n" % ChildMesh.name)
            f.write("Parent:%s\n" % ChildMesh.parent.name)
            VerticesSoFar = VerticesSoFar + len(ChildMesh.data.vertices)
            ChildMesh.data.update(calc_tessface=True)
            FacesSoFar = FacesSoFar + len(ChildMesh.data.tessfaces)
            #Materials
            SubMeshMaterialNo = 0
            for Material in ChildMesh.material_slots:
                f.write("M:%d" % SubMeshMaterialNo)
                f.write("-%s" % Material.name)
                f.write(" T:%s" % Material.material.active_texture.image.name)
                f.write(" C:%s\n" % str(tuple(Material.material.diffuse_color)))
            #WorldMatrix
            WorldMatrixRowNumber = 0
            for WorldMatrixRow in ChildMesh.matrix_world.row:
                f.write("WMR%d" % WorldMatrixRowNumber)
                f.write(":%s\n" % str(tuple(WorldMatrixRow)))
                WorldMatrixRowNumber = WorldMatrixRowNumber + 1
            #Faces.
            FaceCount = 0
            for Face in ChildMesh.data.polygons:
                f.write("F:%d" % FaceCount)
                f.write(" M:%s" % str(Face.material_index))
                f.write(" N:({:f}".format(Face.normal[0]))
                f.write(",{:f}".format(Face.normal[1]))
                f.write(",{:f})".format(Face.normal[2]))
                f.write(" S:%s\n" % str(Face.use_smooth)[0])
                FaceCount = FaceCount + 1
                for Vert, Loop in zip(Face.vertices, Face.loop_indices):
                    f.write("P:%s" % str(tuple(ChildMesh.data.vertices[Vert].co)))
                    if HasUVCoordinates is not None:
                        f.write(", U:%s" % str(tuple(ChildMesh.data.uv_layers.active.data[Loop].uv)))
                    else:
                        f.write(", U:(0.0,0.0)")
                    f.write(", N:%s" % str(tuple(ChildMesh.data.vertices[Vert].normal)))
                    if HasVertexColors is not None:
                        f.write(", C:%s" % str(tuple(ChildMesh.data.vertex_colors.active.data[Vert].color)))
                    else:
                        f.write(", C:(0.0,0.0,0.0,0.0)")
                    f.write("\n")
            #Call child's children.
            VerticesSoFar, FacesSoFar = ProcessChildren(f, ChildMesh, VerticesSoFar, FacesSoFar)
    return VerticesSoFar, FacesSoFar

def write_some_data(context, filepath):
    HasUVCoordinates = bpy.context.active_object.data.uv_layers.active
    HasVertexColors = bpy.context.active_object.data.vertex_colors.active
    print("Exporting data...")
    bpy.context.active_object.data.update(calc_tessface=True)         #calc_tessface=True must be set before working with faces.
    
    f = open(filepath, 'w', encoding='utf-8')
    if bpy.context.active_object != None and bpy.context.active_object.parent == None and bpy.context.active_object.type == 'MESH':
        CountOfVertices = 0
        NumberOfMaterialsUsed = 0
        FacesInModel = 0
        VerticesInModel = len(bpy.context.active_object.data.vertices)
        FacesInModel = len(bpy.context.active_object.data.tessfaces)
        f.write("Punc!It Text\n")
        f.write("Rigid Animation\n")
        f.write("Name:%s\n" % bpy.context.active_object.name)
        f.write("Parent:None\n")
        #Materials
        MaterialNo = 0
        for Material in bpy.context.active_object.material_slots:
            f.write("M:%d" % MaterialNo)
            f.write("-%s" % Material.name)
            f.write(" T:%s" % Material.material.active_texture.image.name)
            f.write(" C:%s\n" % str(tuple(Material.material.diffuse_color)))
        #WorldMatrix
        WorldMatrixRowNumber = 0
        for WorldMatrixRow in bpy.context.active_object.matrix_world.row:
            f.write("WMR%d" % WorldMatrixRowNumber)
            f.write(":%s\n" % str(tuple(WorldMatrixRow)))
            WorldMatrixRowNumber = WorldMatrixRowNumber + 1
        #Faces.
        FaceCount = 0
        for Face in bpy.context.active_object.data.polygons:
            f.write("F:%d" % FaceCount)
            f.write(" M:%s" % str(Face.material_index))
            f.write(" N:({:f}".format(Face.normal[0]))
            f.write(",{:f}".format(Face.normal[1]))
            f.write(",{:f})".format(Face.normal[2]))
            f.write(" S:%s\n" % str(Face.use_smooth)[0])
            FaceCount = FaceCount + 1
            for Vert, Loop in zip(Face.vertices, Face.loop_indices):
                f.write("P:%s" % str(tuple(bpy.context.active_object.data.vertices[Vert].co)))
                if HasUVCoordinates is not None:
                    f.write(", U:%s" % str(tuple(bpy.context.active_object.data.uv_layers.active.data[Loop].uv)))
                else:
                    f.write(", U:(0.0,0.0)")
                f.write(", N:%s" % str(tuple(bpy.context.active_object.data.vertices[Vert].normal)))
                if HasVertexColors is not None:
                    f.write(", C:%s" % str(tuple(bpy.context.active_object.data.vertex_colors.active.data[Vert].color)))
                else:
                    f.write(", C:(0.0,0.0,0.0,0.0)")
                f.write("\n")
        #Children.
        VerticesInModel, FacesInModel = ProcessChildren(f, bpy.context.active_object, VerticesInModel, FacesInModel)
        #Footer
        f.write("Total Unique Vertices:%d\n" % VerticesInModel)
        f.write("Total Faces:%d\n" % FacesInModel)
        f.write("Total Materials:%d" % NumberOfMaterialsUsed)
    else:
        f.write("You must select the root mesh before exporting the model!")
    f.close()
    
    return {'FINISHED'}


# ExportHelper is a helper class, defines filename and
# invoke() function which calls the file selector.
from bpy_extras.io_utils import ExportHelper
from bpy.props import StringProperty, BoolProperty, EnumProperty
from bpy.types import Operator


class ExportSomeData(Operator, ExportHelper):
    """This appears in the tooltip of the operator and in the generated docs"""
    bl_idname = "export_test.some_data"  # important since its how bpy.ops.import_test.some_data is constructed
    bl_label = "Export Button"

    # ExportHelper mixin class uses this
    filename_ext = ".txt"

    filter_glob = StringProperty(
            default="*.txt",
            options={'HIDDEN'},
            )

    def execute(self, context):
        return write_some_data(context, self.filepath)


# Only needed if you want to add into a dynamic menu
def menu_func_export(self, context):
    self.layout.operator(ExportSomeData.bl_idname, text="Custom Exporter Test")


def register():
    bpy.utils.register_class(ExportSomeData)
    bpy.types.INFO_MT_file_export.append(menu_func_export)


def unregister():
    bpy.utils.unregister_class(ExportSomeData)
    bpy.types.INFO_MT_file_export.remove(menu_func_export)


if __name__ == "__main__":
    register()

    # test call
    bpy.ops.export_test.some_data('INVOKE_DEFAULT')
==========================================================================================

bpy.context.active_object.modifiers[0].type
bpy.context.active_object.modifiers[0].object.data.bones[0].name
bpy.context.active_object.modifiers[0].object.data.bones['upper_arm.R'].children[0].name
bpy.context.active_object.modifiers['Armature'].object.data.name
bpy.context.active_object.vertex_groups[0].name
0

Share this post


Link to post
Share on other sites

Here is the Blender exporter for exporting skinned animations. Skinned animation takes more than this data. Namely, it takes the "skinning" data. That is, when you skin a model you are assigning vertices to a bone in the armature and when you weight paint, you assign the percentage that each bone influences the vertex. So, all that data has to be exported. I would want to export that data separately; I would export this animation data exactly like this and then export the model as a separate file which would include the skinning data to describe which bones the vertex is influenced by and the percentage weight. I never got around to writing that exporter unfortunately. Learning skinning and weighting in Blender will help understand how to write that exporter and use the data in code.

 

But this exporter worked to export the armature animation. And having the animation data separate from the model allows the animation data to be re-used on many models. So, a walk animation could be used on any humanoid model that uses the same armature. Since the humanoid armature in Blender is standard, you could reuse the data a lot.

 

#script to export annimations
import bpy


def write_some_data(context, filepath):
    print("Exporting data...")
    #bpy.context.active_object.data.update(calc_tessface=True)         #calc_tessface=True must be set before working with faces.
    
    f = open(filepath, 'w', encoding='utf-8')
    if bpy.context.active_object != None and bpy.context.active_object.parent == None and bpy.context.active_object.type == 'MESH':
        ModelsArmature = bpy.context.active_object.find_armature()
        f.write("Punc!It Armature Animation\n")
        f.write("Armature Name:%s\n" % ModelsArmature.name)
        for Animation in bpy.data.actions:
            ModelsArmature.animation_data.action = Animation
            f.write("Action:%s\n" % Animation.name)
            
            FirstFrame = bpy.context.scene.frame_start
            LastFrame = bpy.context.scene.frame_end
            f.write("Start:%d\n" % FirstFrame)
            f.write("End:%d\n" % LastFrame)
            bpy.context.scene.frame_set(FirstFrame)
            
            NumberOfKeyFrames = len(Animation.fcurves[0].keyframe_points) #KeyFrames in animation
            for KeyFramePoint in Animation.fcurves[0].keyframe_points:
                KeyFrame = KeyFramePoint.co.x
                bpy.context.scene.frame_set(KeyFrame)                
                f.write("Frame:%d\n" % KeyFrame)
                for Bone in ModelsArmature.pose.bones:
                    f.write("Bone:%s\n" % Bone.name)
                    if (Bone.parent == None):
                        f.write("Parent:None\n")
                    else:
                        f.write("Parent:%s\n" % Bone.parent.name)
                    f.write("Head:%s\n" % str(tuple(Bone.head)))
                    f.write("Tail:%s\n" % str(tuple(Bone.tail)))
                    f.write("Length:%s\n" % str(Bone.length))
                    WorldMatrixRowNumber = 0
                    for WorldMatrixRow in Bone.matrix.row:
                        f.write("WMR:%d" % WorldMatrixRowNumber)
                        f.write(":%s\n" % str(tuple(WorldMatrixRow)))
                        WorldMatrixRowNumber = WorldMatrixRowNumber + 1
                    BasisMatrixRowNumber = 0
                    for BasisMatrixRow in Bone.matrix_basis:
                        f.write("BMR:%d" % BasisMatrixRowNumber)
                        f.write(":%s\n" % str(tuple(BasisMatrixRow)))
                        BasisMatrixRowNumber = BasisMatrixRowNumber + 1
    else:
        f.write("You must select the root mesh before exporting the model!")
    f.close()
    
    return {'FINISHED'}


# ExportHelper is a helper class, defines filename and
# invoke() function which calls the file selector.
from bpy_extras.io_utils import ExportHelper
from bpy.props import StringProperty, BoolProperty, EnumProperty
from bpy.types import Operator


class ExportSomeData(Operator, ExportHelper):
    """This appears in the tooltip of the operator and in the generated docs"""
    bl_idname = "export_test.some_data"  # important since its how bpy.ops.import_test.some_data is constructed
    bl_label = "Export Button"

    # ExportHelper mixin class uses this
    filename_ext = ".txt"

    filter_glob = StringProperty(
            default="*.txt",
            options={'HIDDEN'},
            )

    def execute(self, context):
        return write_some_data(context, self.filepath)


# Only needed if you want to add into a dynamic menu
def menu_func_export(self, context):
    self.layout.operator(ExportSomeData.bl_idname, text="Custom Exporter Test")


def register():
    bpy.utils.register_class(ExportSomeData)
    bpy.types.INFO_MT_file_export.append(menu_func_export)


def unregister():
    bpy.utils.unregister_class(ExportSomeData)
    bpy.types.INFO_MT_file_export.remove(menu_func_export)


if __name__ == "__main__":
    register()

    # test call
    bpy.ops.export_test.some_data('INVOKE_DEFAULT')
0

Share this post


Link to post
Share on other sites

Posted (edited)

That should produce a file something like this (This is the short version as the actual data file was too long to post here - you can get the whole thing off my website by downloading the "Armature Animation example" which is an XNA project but contains the Python script and an animation file called "RoboGuyAnimationFile"):

Punc!It Armature Animation
Armature Name:Armature
Action:MyBindPose
Start:1
End:100
Frame:1
Bone:hips
Parent:None
Head:(0.0, 0.0551999993622303, 1.0098999738693237)
Tail:(0.0, 0.017199985682964325, 1.1836999654769897)
Length:0.1779057000841996
WMR:0:(1.0, 0.0, 0.0, 0.0)
WMR:1:(0.0, -0.2135963886976242, -0.9769219756126404, 0.0551999993622303)
WMR:2:(0.0, 0.9769219756126404, -0.2135963886976242, 1.0098999738693237)
WMR:3:(0.0, 0.0, 0.0, 1.0)
BMR:0:(1.0, 0.0, 0.0, 0.0)
BMR:1:(0.0, 1.0, 0.0, 0.0)
BMR:2:(0.0, 0.0, 1.0, 0.0)
BMR:3:(0.0, 0.0, 0.0, 1.0)
Bone:spine
Parent:hips
Head:(0.0, 0.017199985682964325, 1.1836999654769897)
Tail:(0.0, 0.0003999844193458557, 1.3417999744415283)
Length:0.15899010307891734
WMR:0:(1.0, 0.0, 0.0, 0.0)
WMR:1:(0.0, -0.10566695779561996, -0.9944015741348267, 0.017199985682964325)
WMR:2:(0.0, 0.9944015741348267, -0.10566695779561996, 1.1836999654769897)
WMR:3:(0.0, 0.0, 0.0, 1.0)
BMR:0:(1.0, 0.0, 0.0, 0.0)
BMR:1:(0.0, 1.0, 0.0, 0.0)
BMR:2:(0.0, 0.0, 1.0, 0.0)
BMR:3:(0.0, 0.0, 0.0, 1.0)
Bone:ribs
Parent:spine
Head:(0.0, 0.00039998392458073795, 1.3417999744415283)
Tail:(0.0, 0.011400014162063599, 1.6582000255584717)
Length:0.316591208061175
WMR:0:(1.0, 0.0, 0.0, 0.0)
WMR:1:(0.0, 0.034745220094919205, -0.9993961453437805, 0.00039998392458073795)
WMR:2:(0.0, 0.9993961453437805, 0.034745220094919205, 1.3417999744415283)
WMR:3:(0.0, 0.0, 0.0, 1.0)
BMR:0:(1.0, 0.0, 0.0, 0.0)
BMR:1:(0.0, 1.0, 0.0, 0.0)
BMR:2:(0.0, 0.0, 1.0, 0.0)
BMR:3:(0.0, 0.0, 0.0, 1.0)
Bone:neck
Parent:ribs
Head:(0.0, 0.011400015093386173, 1.6582000255584717)
Tail:(0.0, -0.024699967354536057, 1.7812999486923218)
Length:0.1282840587955442
WMR:0:(1.0, 0.0, 0.0, 0.0)
WMR:1:(0.0, -0.28140658140182495, -0.9595885872840881, 0.011400015093386173)
WMR:2:(0.0, 0.9595885872840881, -0.28140658140182495, 1.6582000255584717)
WMR:3:(0.0, 0.0, 0.0, 1.0)
BMR:0:(1.0, 0.0, 0.0, 0.0)
BMR:1:(0.0, 1.0, 0.0, 0.0)
BMR:2:(0.0, 0.0, 1.0, 0.0)
BMR:3:(0.0, 0.0, 0.0, 1.0)
Bone:head
Parent:neck
Head:(0.0, -0.024699965491890907, 1.7812999486923218)
Tail:(0.0, -0.024699928238987923, 1.9347000122070312)
Length:0.153400063514714
WMR:0:(1.0, 0.0, 0.0, 0.0)
WMR:1:(0.0, 2.455568903769745e-07, -0.9999999403953552, -0.024699965491890907)
WMR:2:(0.0, 0.9999999403953552, 2.455568903769745e-07, 1.7812999486923218)
WMR:3:(0.0, 0.0, 0.0, 1.0)
BMR:0:(1.0, 0.0, 0.0, 0.0)
BMR:1:(0.0, 1.0, 0.0, 0.0)
BMR:2:(0.0, 0.0, 1.0, 0.0)
BMR:3:(0.0, 0.0, 0.0, 1.0)
Bone:shoulder.L
Parent:ribs
Head:(0.018300000578165054, -0.06839998811483383, 1.6051000356674194)
Tail:(0.16940002143383026, 0.02050001174211502, 1.6050000190734863)
Length:0.1753123994652116
WMR:0:(0.5070948600769043, 0.8618901968002319, 0.000529240642208606, 0.018300000578165054)
WMR:1:(-0.8618903160095215, 0.5070948004722595, 0.00022575189359486103, -0.06839998811483383)
WMR:2:(-7.374442793661729e-05, -0.0005706493393518031, 0.9999998807907104, 1.6051000356674194)
WMR:3:(0.0, 0.0, 0.0, 1.0)
BMR:0:(1.0, 0.0, 0.0, 0.0)
BMR:1:(0.0, 1.0, 0.0, 0.0)
BMR:2:(0.0, 0.0, 1.0, 0.0)
BMR:3:(0.0, 0.0, 0.0, 1.0)
Bone:upper_arm.L
Parent:shoulder.L
Head:(0.19530001282691956, 0.026700008660554886, 1.5845999717712402)
Tail:(0.30880507826805115, 0.0885000005364418, 1.326655626296997)
Length:0.28850983386843326
WMR:0:(-0.9150146842002869, 0.39341846108436584, 0.08927633613348007, 0.19530001282691956)
WMR:1:(-0.003204085398465395, 0.21420414745807648, -0.9767836928367615, 0.026700008660554886)
WMR:2:(-0.40340808033943176, -0.8940573334693909, -0.19473931193351746, 1.5845999717712402)
WMR:3:(0.0, 0.0, 0.0, 1.0)
BMR:0:(0.7932483553886414, 0.5946226716041565, 0.13107618689537048, 0.0)
BMR:1:(-0.5949065089225769, 0.8027327656745911, -0.04130832478404045, 0.0)
BMR:2:(-0.12978202104568481, -0.045210305601358414, 0.9905112981796265, 0.0)
BMR:3:(0.0, 0.0, 0.0, 1.0)
Bone:forearm.L
Parent:upper_arm.L
Head:(0.30880507826805115, 0.0885000005364418, 1.326655626296997)
Tail:(0.30192404985427856, 0.049199994653463364, 1.0668660402297974)
Length:0.2628354390933617
WMR:0:(-0.9995909333229065, -0.02618001215159893, 0.011519014835357666, 0.30880507826805115)
WMR:1:(-0.007477705366909504, -0.14952321350574493, -0.9887299537658691, 0.0885000005364418)
WMR:2:(0.027607256546616554, -0.9884114861488342, 0.1492663025856018, 1.326655626296997)
WMR:3:(0.0, 0.0, 0.0, 1.0)
BMR:0:(0.9359229207038879, 0.3483165502548218, -0.05219045653939247, 0.0)
BMR:1:(-0.34817326068878174, 0.9373520016670227, 0.012107320129871368, 0.0)
BMR:2:(0.05313801020383835, 0.006839803420007229, 0.9985637664794922, 0.0)
BMR:3:(0.0, 0.0, 0.0, 1.0)
Bone:hand.L
Parent:forearm.L
Head:(0.30192404985427856, 0.049199994653463364, 1.0668660402297974)
Tail:(0.2952873706817627, 0.04119998961687088, 0.9873819351196289)
Length:0.0801608916878344
WMR:0:(-0.0008265578071586788, -0.08279184997081757, -0.996566653251648, 0.30192404985427856)
WMR:1:(0.9949796199798584, -0.09979938715696335, 0.007465818431228399, 0.049199994653463364)
WMR:2:(-0.10007485002279282, -0.9915573000907898, 0.08245860785245895, 1.0668660402297974)
WMR:3:(0.0, 0.0, 0.0, 1.0)
BMR:0:(1.0, 0.0, 0.0, 0.0)
BMR:1:(0.0, 1.0, 0.0, 0.0)
BMR:2:(0.0, 0.0, 1.0, 0.0)
BMR:3:(0.0, 0.0, 0.0, 1.0)
Bone:palm.01.L
Parent:hand.L
Head:(0.3039860129356384, 0.022399989888072014, 1.0296443700790405)
Tail:(0.2986827790737152, 0.0050999801605939865, 0.9624106884002686)
Length:0.0696260194040096
WMR:0:(-0.00568762794137001, -0.0761675164103508, -0.9970789551734924, 0.3039860129356384)
WMR:1:(0.9685460329055786, -0.24847060441970825, 0.013455983251333237, 0.022399989888072014)
WMR:2:(-0.24876970052719116, -0.9656403064727783, 0.07518486678600311, 1.0296443700790405)
WMR:3:(0.0, 0.0, 0.0, 1.0)
BMR:0:(1.0, 0.0, 0.0, 0.0)
BMR:1:(0.0, 1.0, 0.0, 0.0)
BMR:2:(0.0, 0.0, 1.0, 0.0)
BMR:3:(0.0, 0.0, 0.0, 1.0)
Bone:finger_index.01.L
Parent:palm.01.L
Head:(0.2986827790737152, 0.0050999801605939865, 0.9624106884002686)
Tail:(0.2806694805622101, 0.001299968920648098, 0.9213048815727234)
Length:0.045040052882204376
WMR:0:(0.0950925275683403, -0.3999395966529846, -0.9115952253341675, 0.2986827790737152)
WMR:1:(0.9865608215332031, -0.08436965197324753, 0.13992759585380554, 0.0050999801605939865)
WMR:2:(-0.1328735500574112, -0.9126502871513367, 0.3865416646003723, 0.9624106884002686)
WMR:3:(0.0, 0.0, 0.0, 1.0)
BMR:0:(1.0, 0.0, 0.0, 0.0)
BMR:1:(0.0, 1.0, 0.0, 0.0)
BMR:2:(0.0, 0.0, 1.0, 0.0)
BMR:3:(0.0, 0.0, 0.0, 1.0)
Bone:finger_index.02.L
Parent:finger_index.01.L
Head:(0.2806694805622101, 0.0012999688042327762, 0.9213048815727234)
Tail:(0.2655388414859772, -0.00030004081781953573, 0.8975337743759155)
Length:0.028223426563902844
WMR:0:(0.08646058291196823, -0.5361015200614929, -0.8397141695022583, 0.2806694805622101)
WMR:1:(0.9888078570365906, -0.056690819561481476, 0.13800522685050964, 0.0012999688042327762)
WMR:2:(-0.12158889323472977, -0.8422480225563049, 0.5251997709274292, 0.9213048815727234)
WMR:3:(0.0, 0.0, 0.0, 1.0)
BMR:0:(1.0, 0.0, 0.0, 0.0)
BMR:1:(0.0, 1.0, 0.0, 0.0)
BMR:2:(0.0, 0.0, 1.0, 0.0)
BMR:3:(0.0, 0.0, 0.0, 1.0)
Bone:finger_index.03.L
Parent:finger_index.02.L
Head:(0.2655388414859772, -0.00030004081781953573, 0.8975337743759155)
Tail:(0.24943029880523682, 0.0005999515415169299, 0.881397008895874)
Length:0.02281864004935344
WMR:0:(0.11580153554677963, -0.7059381008148193, -0.6987428069114685, 0.2655388414859772)
WMR:1:(0.9914401769638062, 0.03944113105535507, 0.1244625449180603, -0.00030004081781953573)
WMR:2:(-0.06030363589525223, -0.7071748375892639, 0.7044626474380493, 0.8975337743759155)
WMR:3:(0.0, 0.0, 0.0, 1.0)
BMR:0:(1.0, 0.0, 0.0, 0.0)
BMR:1:(0.0, 1.0, 0.0, 0.0)
BMR:2:(0.0, 0.0, 1.0, 0.0)
BMR:3:(0.0, 0.0, 0.0, 1.0)
Bone:thumb.01.L
Parent:palm.01.L
Head:(0.28035271167755127, 0.021399999037384987, 1.0403861999511719)
Tail:(0.2600117325782776, 0.0014999918639659882, 1.0098435878753662)
Length:0.04174466275624186
WMR:0:(0.8725852370262146, -0.48727157711982727, -0.034081779420375824, 0.28035271167755127)
WMR:1:(-0.23309919238090515, -0.47670814394950867, 0.8475931882858276, 0.021399999037384987)
WMR:2:(-0.42925503849983215, -0.7316528558731079, -0.5295511484146118, 1.0403861999511719)
WMR:3:(0.0, 0.0, 0.0, 1.0)
BMR:0:(1.0, 0.0, 0.0, 0.0)
BMR:1:(0.0, 1.0, 0.0, 0.0)
BMR:2:(0.0, 0.0, 1.0, 0.0)
BMR:3:(0.0, 0.0, 0.0, 1.0)
Bone:thumb.02.L
Parent:thumb.01.L
Head:(0.2600117325782776, 0.0014999917475506663, 1.0098435878753662)
Tail:(0.24852174520492554, -0.00570001220330596, 0.9792690873146057)
Length:0.03344637428703545
WMR:0:(0.9349398016929626, -0.3435346186161041, 0.08872213214635849, 0.2600117325782776)
WMR:1:(-0.1703493595123291, -0.21526996791362762, 0.9615820050239563, 0.0014999917475506663)
WMR:2:(-0.3112374246120453, -0.9141350984573364, -0.2597854435443878, 1.0098435878753662)
WMR:3:(0.0, 0.0, 0.0, 1.0)
BMR:0:(1.0, 0.0, 0.0, 0.0)
BMR:1:(0.0, 1.0, 0.0, 0.0)
BMR:2:(0.0, 0.0, 1.0, 0.0)
BMR:3:(0.0, 0.0, 0.0, 1.0)
Bone:thumb.03.L
Parent:thumb.02.L
Head:(0.24852174520492554, -0.00570001220330596, 0.9792690873146057)
Tail:(0.24306833744049072, -0.009800013154745102, 0.9596298933029175)
Length:0.02079056529957112
WMR:0:(0.9595236778259277, -0.2623019218444824, 0.10252860188484192, 0.24852174520492554)
WMR:1:(-0.1573072373867035, -0.19720466434955597, 0.9676594138145447, -0.00570001220330596)
WMR:2:(-0.2335997223854065, -0.944620668888092, -0.23048460483551025, 0.9792690873146057)
WMR:3:(0.0, 0.0, 0.0, 1.0)
BMR:0:(1.0, 0.0, 0.0, 0.0)
BMR:1:(0.0, 1.0, 0.0, 0.0)
BMR:2:(0.0, 0.0, 1.0, 0.0)
BMR:3:(0.0, 0.0, 0.0, 1.0)
Bone:palm.02.L
Parent:hand.L
Head:(0.3061484098434448, 0.038899991661310196, 1.0252189636230469)
Tail:(0.3019583523273468, 0.02769998088479042, 0.9580886363983154)
Length:0.06818707837033267
WMR:0:(-0.014553106389939785, -0.06144958361983299, -0.9980041980743408, 0.3061484098434448)
WMR:1:(0.9864088296890259, -0.1642541140317917, -0.004270466044545174, 0.038899991661310196)
WMR:2:(-0.1636638641357422, -0.9845023155212402, 0.06300473213195801, 1.0252189636230469)
WMR:3:(0.0, 0.0, 0.0, 1.0)
BMR:0:(1.0, 0.0, 0.0, 0.0)
BMR:1:(0.0, 1.0, 0.0, 0.0)
BMR:2:(0.0, 0.0, 1.0, 0.0)
BMR:3:(0.0, 0.0, 0.0, 1.0)
Bone:finger_middle.01.L
Parent:palm.02.L
Head:(0.3019583523273468, 0.02769998274743557, 0.9580886363983154)
Tail:(0.2784064710140228, 0.023399967700242996, 0.9147172570228577)
Length:0.049540466204234135
WMR:0:(0.03002334013581276, -0.4754068851470947, -0.8792536854743958, 0.3019583523273468)
WMR:1:(0.9929408431053162, -0.08679802715778351, 0.08083651959896088, 0.02769998274743557)
WMR:2:(-0.11474771052598953, -0.8754739761352539, 0.4694449007511139, 0.9580886363983154)
WMR:3:(0.0, 0.0, 0.0, 1.0)
BMR:0:(1.0, 0.0, 0.0, 0.0)
BMR:1:(0.0, 1.0, 0.0, 0.0)
BMR:2:(0.0, 0.0, 1.0, 0.0)
BMR:3:(0.0, 0.0, 0.0, 1.0)
Bone:finger_middle.02.L
Parent:finger_middle.01.L
Head:(0.2784064710140228, 0.023399967700242996, 0.9147172570228577)
Tail:(0.256862610578537, 0.021799959242343903, 0.8908450603485107)
Length:0.032195958187134936
WMR:0:(-0.016263922676444054, -0.6691475510597229, -0.7429516315460205, 0.2784064710140228)
WMR:1:(0.9985017776489258, -0.049695923924446106, 0.022901061922311783, 0.023399967700242996)
WMR:2:(-0.052245840430259705, -0.741466224193573, 0.6689532399177551, 0.9147172570228577)
WMR:3:(0.0, 0.0, 0.0, 1.0)
BMR:0:(1.0, 0.0, 0.0, 0.0)
BMR:1:(0.0, 1.0, 0.0, 0.0)
BMR:2:(0.0, 0.0, 1.0, 0.0)
BMR:3:(0.0, 0.0, 0.0, 1.0)
Bone:finger_middle.03.L
Parent:finger_middle.02.L
Head:(0.256862610578537, 0.021799959242343903, 0.8908450603485107)
Tail:(0.23979225754737854, 0.02159995399415493, 0.8758766055107117)
Length:0.022704439982939768
WMR:0:(-0.01572253555059433, -0.7518513798713684, -0.659145176410675, 0.256862610578537)
WMR:1:(0.9998658895492554, -0.008809125982224941, -0.01380158681422472, 0.021799959242343903)
WMR:2:(0.004570264369249344, -0.6592739820480347, 0.7518890500068665, 0.8908450603485107)
WMR:3:(0.0, 0.0, 0.0, 1.0)
BMR:0:(1.0, 0.0, 0.0, 0.0)
BMR:1:(0.0, 1.0, 0.0, 0.0)
BMR:2:(0.0, 0.0, 1.0, 0.0)
BMR:3:(0.0, 0.0, 0.0, 1.0)
Bone:palm.03.L
Parent:hand.L
Head:(0.3055240213871002, 0.05449999123811722, 1.0256550312042236)
Tail:(0.30269524455070496, 0.05209998041391373, 0.955956220626831)
Length:0.06979746575807515
WMR:0:(-0.040807563811540604, -0.040528569370508194, -0.9983448386192322, 0.3055240213871002)
WMR:1:(0.9986307621002197, -0.034385357052087784, -0.03942333161830902, 0.05449999123811722)
WMR:2:(-0.03273067623376846, -0.9985866546630859, 0.0418761782348156, 1.0256550312042236)
WMR:3:(0.0, 0.0, 0.0, 1.0)
BMR:0:(1.0, 0.0, 0.0, 0.0)
BMR:1:(0.0, 1.0, 0.0, 0.0)
BMR:2:(0.0, 0.0, 1.0, 0.0)
BMR:3:(0.0, 0.0, 0.0, 1.0)
Bone:finger_ring.01.L
Parent:palm.03.L
Head:(0.30269524455070496, 0.05209998041391373, 0.955956220626831)
Tail:(0.27694419026374817, 0.04989996924996376, 0.9193423390388489)
Length:0.044816661755981785
WMR:0:(-0.05744895339012146, -0.5745863914489746, -0.8164253234863281, 0.30269524455070496)
WMR:1:(0.9981566071510315, -0.049089159816503525, -0.03568858653306961, 0.05209998041391373)
WMR:2:(-0.019571460783481598, -0.8169706463813782, 0.5763472318649292, 0.955956220626831)
WMR:3:(0.0, 0.0, 0.0, 1.0)
BMR:0:(1.0, 0.0, 0.0, 0.0)
BMR:1:(0.0, 1.0, 0.0, 0.0)
BMR:2:(0.0, 0.0, 1.0, 0.0)
BMR:3:(0.0, 0.0, 0.0, 1.0)
Bone:finger_ring.02.L
Parent:finger_ring.01.L
Head:(0.27694419026374817, 0.04989996924996376, 0.9193423390388489)
Tail:(0.25495731830596924, 0.0493999607861042, 0.8963721990585327)
Length:0.03180094145881558
WMR:0:(-0.06333208084106445, -0.691390335559845, -0.7197003960609436, 0.27694419026374817)
WMR:1:(0.997233510017395, -0.01572306454181671, -0.07264977693557739, 0.04989996924996376)
WMR:2:(0.038913462311029434, -0.7223105430603027, 0.6904733180999756, 0.9193423390388489)
WMR:3:(0.0, 0.0, 0.0, 1.0)
BMR:0:(1.0, 0.0, 0.0, 0.0)
BMR:1:(0.0, 1.0, 0.0, 0.0)
BMR:2:(0.0, 0.0, 1.0, 0.0)
BMR:3:(0.0, 0.0, 0.0, 1.0)
Bone:finger_ring.03.L
Parent:finger_ring.02.L
Head:(0.25495731830596924, 0.0493999607861042, 0.8963721990585327)
Tail:(0.2385593205690384, 0.049799952656030655, 0.8877090811729431)
Length:0.01855003867316774
WMR:0:(-0.054464541375637054, -0.8839878439903259, -0.46432676911354065, 0.25495731830596924)
WMR:1:(0.9873839020729065, 0.021562909707427025, -0.156869575381279, 0.0493999607861042)
WMR:2:(0.14868304133415222, -0.4670126736164093, 0.8716609477996826, 0.8963721990585327)
WMR:3:(0.0, 0.0, 0.0, 1.0)
BMR:0:(1.0, 0.0, 0.0, 0.0)
BMR:1:(0.0, 1.0, 0.0, 0.0)
BMR:2:(0.0, 0.0, 1.0, 0.0)
BMR:3:(0.0, 0.0, 0.0, 1.0)
Bone:palm.04.L
Parent:hand.L
Head:(0.3034741282463074, 0.06959999352693558, 1.0283842086791992)
Tail:(0.29747551679611206, 0.0762999877333641, 0.9541244506835938)
Length:0.07480230557451074
WMR:0:(-0.003450550138950348, -0.08019282668828964, -0.9967735409736633, 0.3034741282463074)
WMR:1:(0.9959237575531006, 0.08956936001777649, -0.010653658770024776, 0.06959999352693558)
WMR:2:(0.09013469517230988, -0.9927470684051514, 0.07955678552389145, 1.0283842086791992)
WMR:3:(0.0, 0.0, 0.0, 1.0)
BMR:0:(1.0, 0.0, 0.0, 0.0)
BMR:1:(0.0, 1.0, 0.0, 0.0)
BMR:2:(0.0, 0.0, 1.0, 0.0)
BMR:3:(0.0, 0.0, 0.0, 1.0)
Bone:finger_pinky.01.L
Parent:palm.04.L
Head:(0.29747551679611206, 0.0762999877333641, 0.9541244506835938)
Tail:(0.27759575843811035, 0.07649997621774673, 0.9345836043357849)
Length:0.027876324430510892
WMR:0:(-0.12287505716085434, -0.7131419777870178, -0.6901670098304749, 0.29747551679611206)
WMR:1:(0.9831879138946533, 0.007174238096922636, -0.18245655298233032, 0.0762999877333641)
WMR:2:(0.13506880402565002, -0.7009831666946411, 0.7002708315849304, 0.9541244506835938)
WMR:3:(0.0, 0.0, 0.0, 1.0)
BMR:0:(1.0, 0.0, 0.0, 0.0)
BMR:1:(0.0, 1.0, 0.0, 0.0)
BMR:2:(0.0, 0.0, 1.0, 0.0)
BMR:3:(0.0, 0.0, 0.0, 1.0)
Bone:finger_pinky.02.L
Parent:finger_pinky.01.L
Head:(0.27759575843811035, 0.07649997621774673, 0.9345836043357849)
Tail:(0.2601030468940735, 0.0769999697804451, 0.9202945828437805)
Length:0.022592500656735275
WMR:0:(-0.11284443736076355, -0.7742713093757629, -0.6227120757102966, 0.27759575843811035)
WMR:1:(0.9785446524620056, 0.022131117060780525, -0.2048439085483551, 0.07649997621774673)
WMR:2:(0.172386035323143, -0.6324669718742371, 0.755161464214325, 0.9345836043357849)
WMR:3:(0.0, 0.0, 0.0, 1.0)
BMR:0:(1.0, 0.0, 0.0, 0.0)
BMR:1:(0.0, 1.0, 0.0, 0.0)
BMR:2:(0.0, 0.0, 1.0, 0.0)
BMR:3:(0.0, 0.0, 0.0, 1.0)
Bone:finger_pinky.03.L
Parent:finger_pinky.02.L
Head:(0.2601030468940735, 0.0769999697804451, 0.9202945828437805)
Tail:(0.24699437618255615, 0.07719997316598892, 0.9129698276519775)
Length:0.015017632562992945
WMR:0:(-0.10453005135059357, -0.8728853464126587, -0.4765971899032593, 0.2601030468940735)
WMR:1:(0.9713146686553955, 0.013317709788680077, -0.23742561042308807, 0.0769999697804451)
WMR:2:(0.21359246969223022, -0.48774388432502747, 0.8464540839195251, 0.9202945828437805)
WMR:3:(0.0, 0.0, 0.0, 1.0)
BMR:0:(1.0, 0.0, 0.0, 0.0)
BMR:1:(0.0, 1.0, 0.0, 0.0)
BMR:2:(0.0, 0.0, 1.0, 0.0)
BMR:3:(0.0, 0.0, 0.0, 1.0)
Bone:shoulder.R
Parent:ribs
Head:(-0.018300000578165054, -0.06839998811483383, 1.6051000356674194)
Tail:(-0.16940002143383026, 0.02050001174211502, 1.6050000190734863)
Length:0.1753123994652116
WMR:0:(0.5070948600769043, -0.8618901968002319, -0.000529240642208606, -0.018300000578165054)
WMR:1:(0.8618903160095215, 0.5070948004722595, 0.00022575189359486103, -0.06839998811483383)
WMR:2:(7.374442793661729e-05, -0.0005706493393518031, 0.9999998807907104, 1.6051000356674194)
WMR:3:(0.0, 0.0, 0.0, 1.0)
BMR:0:(1.0, 0.0, 0.0, 0.0)
BMR:1:(0.0, 1.0, 0.0, 0.0)
BMR:2:(0.0, 0.0, 1.0, 0.0)
BMR:3:(0.0, 0.0, 0.0, 1.0)
Bone:upper_arm.R
Parent:shoulder.R
Head:(-0.19530001282691956, 0.026700008660554886, 1.5845999717712402)
Tail:(-0.3024795651435852, 0.0885000005364418, 1.3239638805389404)
Length:0.28850973550906783
WMR:0:(-0.924582302570343, -0.3714936375617981, -0.08449970185756683, -0.19530001282691956)
WMR:1:(0.0032040609512478113, 0.21420414745807648, -0.9767836928367615, 0.026700008660554886)
WMR:2:(0.3809690773487091, -0.9033876061439514, -0.19685900211334229, 1.5845999717712402)
WMR:3:(0.0, 0.0, 0.0, 1.0)
BMR:0:(0.7781602144241333, -0.6133349537849426, -0.1352292150259018, 0.0)
BMR:1:(0.6136394739151001, 0.7883368134498596, -0.04440385103225708, 0.0)
BMR:2:(0.13384060561656952, -0.04842866212129593, 0.9898188710212708, 0.0)
BMR:3:(0.0, 0.0, 0.0, 1.0)
Bone:forearm.R
Parent:upper_arm.R
Head:(-0.3024795651435852, 0.0885000005364418, 1.3239637613296509)
Tail:(-0.30127403140068054, 0.049199994653463364, 1.064085841178894)
Length:0.26283545642833384
WMR:0:(-0.9999554753303528, 0.004586691502481699, -0.008256259374320507, -0.3024795651435852)
WMR:1:(0.007477679755538702, -0.14952321350574493, -0.9887299537658691, 0.0885000005364418)
WMR:2:(-0.005769494455307722, -0.9887475967407227, 0.14948229491710663, 1.3239637613296509)
WMR:3:(0.0, 0.0, 0.0, 1.0)
BMR:0:(0.9512011408805847, -0.3051568865776062, 0.04577907174825668, 0.0)
BMR:1:(0.30504775047302246, 0.9522894620895386, 0.009522203356027603, 0.0)
BMR:2:(-0.04650069400668144, 0.004907271824777126, 0.9989061951637268, 0.0)
BMR:3:(0.0, 0.0, 0.0, 1.0)
Bone:hand.R
Parent:forearm.R
Head:(-0.30127403140068054, 0.049199994653463364, 1.064085841178894)
Tail:(-0.2963748872280121, 0.04119998961687088, 0.9844757318496704)
Length:0.08016090818859924
WMR:0:(0.0013592976611107588, 0.06111632287502289, 0.9981299042701721, -0.30127403140068054)
WMR:1:(-0.9949796199798584, -0.09979937970638275, 0.007465844042599201, 0.049199994653463364)
WMR:2:(0.10006904602050781, -0.9931290149688721, 0.06067381799221039, 1.064085841178894)
WMR:3:(0.0, 0.0, 0.0, 1.0)
BMR:0:(1.0, 0.0, 0.0, 0.0)
BMR:1:(0.0, 1.0, 0.0, 0.0)
BMR:2:(0.0, 0.0, 1.0, 0.0)
BMR:3:(0.0, 0.0, 0.0, 1.0)
Bone:palm.01.R
Parent:hand.R
Head:(-0.30414843559265137, 0.022399989888072014, 1.0269181728363037)
Tail:(-0.30031484365463257, 0.005099982023239136, 0.9595847129821777)
Length:0.0696260117714473
WMR:0:(-0.00025309206102974713, 0.05505960434675217, 0.9984832406044006, -0.30414843559265137)
WMR:1:(-0.9685460329055786, -0.24847058951854706, 0.013456009328365326, 0.022399989888072014)
WMR:2:(0.24883460998535156, -0.9670735001564026, 0.05339062586426735, 1.0269181728363037)
WMR:3:(0.0, 0.0, 0.0, 1.0)
BMR:0:(1.0, 0.0, 0.0, 0.0)
BMR:1:(0.0, 1.0, 0.0, 0.0)
BMR:2:(0.0, 0.0, 1.0, 0.0)
BMR:3:(0.0, 0.0, 0.0, 1.0)
Bone:finger_index.01.R
Parent:palm.01.R
Head:(-0.30031484365463257, 0.005099981091916561, 0.9595847129821777)
Tail:(-0.2832036018371582, 0.0011999702546745539, 0.9180952906608582)
Length:0.04504860536824087
WMR:0:(0.09713990241289139, 0.379839688539505, 0.9199380874633789, -0.30031484365463257)
WMR:1:(-0.9863735437393188, -0.08657345920801163, 0.1399010419845581, 0.005099981091916561)
WMR:2:(0.1327822059392929, -0.9209924936294556, 0.366254061460495, 0.9595847129821777)
WMR:3:(0.0, 0.0, 0.0, 1.0)
BMR:0:(1.0, 0.0, 0.0, 0.0)
BMR:1:(0.0, 1.0, 0.0, 0.0)
BMR:2:(0.0, 0.0, 1.0, 0.0)
BMR:3:(0.0, 0.0, 0.0, 1.0)
Bone:finger_index.02.R
Parent:finger_index.01.R
Head:(-0.2832036018371582, 0.0011999703710898757, 0.9180952906608582)
Tail:(-0.26859575510025024, -0.000300038605928421, 0.8939993977546692)
Length:0.028217924589995197
WMR:0:(0.0909094512462616, 0.5176796913146973, 0.8507311940193176, -0.2832036018371582)
WMR:1:(-0.989000141620636, -0.0531579852104187, 0.1380321979522705, 0.0011999703710898757)
WMR:2:(0.11667963862419128, -0.8539217114448547, 0.5071527361869812, 0.9180952906608582)
WMR:3:(0.0, 0.0, 0.0, 1.0)
BMR:0:(1.0, 0.0, 0.0, 0.0)
BMR:1:(0.0, 1.0, 0.0, 0.0)
BMR:2:(0.0, 0.0, 1.0, 0.0)
BMR:3:(0.0, 0.0, 0.0, 1.0)
Bone:finger_index.03.R
Parent:finger_index.02.R
Head:(-0.26859575510025024, -0.0003000386350322515, 0.8939993977546692)
Tail:(-0.2528434991836548, 0.0005999548593536019, 0.877514660358429)
Length:0.022818635404477372
WMR:0:(0.11709101498126984, 0.6903250813484192, 0.713961660861969, -0.26859575510025024)
WMR:1:(-0.9914400577545166, 0.03944117948412895, 0.1244625598192215, -0.0003000386350322515)
WMR:2:(0.05776016414165497, -0.7224237322807312, 0.689034104347229, 0.8939993977546692)
WMR:3:(0.0, 0.0, 0.0, 1.0)
BMR:0:(1.0, 0.0, 0.0, 0.0)
BMR:1:(0.0, 1.0, 0.0, 0.0)
BMR:2:(0.0, 0.0, 1.0, 0.0)
BMR:3:(0.0, 0.0, 0.0, 1.0)
Bone:thumb.01.R
Parent:palm.01.R
Head:(-0.28028616309165955, 0.021399999037384987, 1.0371413230895996)
Tail:(-0.26061710715293884, 0.0014999937266111374, 1.0061618089675903)
Length:0.04174460765326611
WMR:0:(0.8817521929740906, 0.4711759388446808, 0.022508161142468452, -0.28028616309165955)
WMR:1:(0.23309920728206635, -0.4767081141471863, 0.8475931882858276, 0.021399999037384987)
WMR:2:(0.41009530425071716, -0.7421203851699829, -0.5301691889762878, 1.0371413230895996)
WMR:3:(0.0, 0.0, 0.0, 1.0)
BMR:0:(1.0, 0.0, 0.0, 0.0)
BMR:1:(0.0, 1.0, 0.0, 0.0)
BMR:2:(0.0, 0.0, 1.0, 0.0)
BMR:3:(0.0, 0.0, 0.0, 1.0)
Bone:thumb.02.R
Parent:thumb.01.R
Head:(-0.26061710715293884, 0.0014999930281192064, 1.0061618089675903)
Tail:(-0.24979761242866516, -0.005700009874999523, 0.975343644618988)
Length:0.03344638632734788
WMR:0:(0.9415143728256226, 0.3234878182411194, -0.09437473118305206, -0.26061710715293884)
WMR:1:(0.1703493744134903, -0.21526993811130524, 0.9615820050239563, 0.0014999930281192064)
WMR:2:(0.29074400663375854, -0.9214198589324951, -0.25778576731681824, 1.0061618089675903)
WMR:3:(0.0, 0.0, 0.0, 1.0)
BMR:0:(1.0, 0.0, 0.0, 0.0)
BMR:1:(0.0, 1.0, 0.0, 0.0)
BMR:2:(0.0, 0.0, 1.0, 0.0)
BMR:3:(0.0, 0.0, 0.0, 1.0)
Bone:thumb.03.R
Parent:thumb.02.R
Head:(-0.24979761242866516, -0.0057000103406608105, 0.975343644618988)
Tail:(-0.24477443099021912, -0.009800011292099953, 0.955590009689331)
Length:0.020790585669949638
WMR:0:(0.9643967747688293, 0.241608664393425, -0.10753796994686127, -0.24979761242866516)
WMR:1:(0.15730726718902588, -0.19720463454723358, 0.9676594138145447, -0.0057000103406608105)
WMR:2:(0.21258790791034698, -0.9501240253448486, -0.2281903773546219, 0.975343644618988)
WMR:3:(0.0, 0.0, 0.0, 1.0)
BMR:0:(1.0, 0.0, 0.0, 0.0)
BMR:1:(0.0, 1.0, 0.0, 0.0)
BMR:2:(0.0, 0.0, 1.0, 0.0)
BMR:3:(0.0, 0.0, 0.0, 1.0)
Bone:palm.02.R
Parent:hand.R
Head:(-0.3064069449901581, 0.038899991661310196, 1.0225409269332886)
Tail:(-0.3036840260028839, 0.02769998274743557, 0.9553350806236267)
Length:0.06818709750150699
WMR:0:(-0.010975182056427002, 0.0399332270026207, 0.9991422295570374, -0.3064069449901581)
WMR:1:(-0.9864088296890259, -0.1642540991306305, -0.004270440433174372, 0.038899991661310196)
WMR:2:(0.16394269466400146, -0.9856095910072327, 0.04119318351149559, 1.0225409269332886)
WMR:3:(0.0, 0.0, 0.0, 1.0)
BMR:0:(1.0, 0.0, 0.0, 0.0)
BMR:1:(0.0, 1.0, 0.0, 0.0)
BMR:2:(0.0, 0.0, 1.0, 0.0)
BMR:3:(0.0, 0.0, 0.0, 1.0)
Bone:finger_middle.01.R
Parent:palm.02.R
Head:(-0.3036840260028839, 0.02769998274743557, 0.9553350806236267)
Tail:(-0.2810850143432617, 0.023299969732761383, 0.9114596843719482)
Length:0.04954922641941893
WMR:0:(0.03160826116800308, 0.4560922086238861, 0.8893712162971497, -0.3036840260028839)
WMR:1:(-0.992764949798584, -0.08880080282688141, 0.08082223683595657, 0.02769998274743557)
WMR:2:(0.11583929508924484, -0.8854911923408508, 0.44998544454574585, 0.9553350806236267)
WMR:3:(0.0, 0.0, 0.0, 1.0)
BMR:0:(1.0, 0.0, 0.0, 0.0)
BMR:1:(0.0, 1.0, 0.0, 0.0)
BMR:2:(0.0, 0.0, 1.0, 0.0)
BMR:3:(0.0, 0.0, 0.0, 1.0)
Bone:finger_middle.02.R
Parent:finger_middle.01.R
Head:(-0.2810850143432617, 0.023299969732761383, 0.9114596843719482)
Tail:(-0.2600676715373993, 0.0217999629676342, 0.887122631072998)
Length:0.032191161553918914
WMR:0:(-0.01309398002922535, 0.6528918147087097, 0.757338285446167, -0.2810850143432617)
WMR:1:(-0.9986511468887329, -0.046596869826316833, 0.022904489189386368, 0.023299969732761383)
WMR:2:(0.050243765115737915, -0.7560167908668518, 0.6526212692260742, 0.9114596843719482)
WMR:3:(0.0, 0.0, 0.0, 1.0)
BMR:0:(1.0, 0.0, 0.0, 0.0)
BMR:1:(0.0, 1.0, 0.0, 0.0)
BMR:2:(0.0, 0.0, 1.0, 0.0)
BMR:3:(0.0, 0.0, 0.0, 1.0)
Bone:finger_middle.03.R
Parent:finger_middle.02.R
Head:(-0.2600676715373993, 0.0217999629676342, 0.887122631072998)
Tail:(-0.2433283030986786, 0.02159995771944523, 0.8717849254608154)
Length:0.02270444166396787
WMR:0:(-0.01581859029829502, 0.7372732758522034, 0.6754097938537598, -0.2600676715373993)
WMR:1:(-0.9998659491539001, -0.008809060789644718, -0.013801590539515018, 0.0217999629676342)
WMR:2:(-0.004225800279527903, -0.6755375266075134, 0.7373137474060059, 0.887122631072998)
WMR:3:(0.0, 0.0, 0.0, 1.0)
BMR:0:(1.0, 0.0, 0.0, 0.0)
BMR:1:(0.0, 1.0, 0.0, 0.0)
BMR:2:(0.0, 0.0, 1.0, 0.0)
BMR:3:(0.0, 0.0, 0.0, 1.0)
Bone:palm.03.R
Parent:hand.R
Head:(-0.30577319860458374, 0.054399993270635605, 1.022963285446167)
Tail:(-0.3044673204421997, 0.05209998041391373, 0.9532193541526794)
Length:0.06979406371022387
WMR:0:(-0.04005623981356621, 0.01871049590408802, 0.9990224242210388, -0.30577319860458374)
WMR:1:(-0.9986790418624878, -0.032954249531030655, -0.039425238966941833, 0.054399993270635605)
WMR:2:(0.03218439221382141, -0.9992818832397461, 0.020005786791443825, 1.022963285446167)
WMR:3:(0.0, 0.0, 0.0, 1.0)
BMR:0:(1.0, 0.0, 0.0, 0.0)
BMR:1:(0.0, 1.0, 0.0, 0.0)
BMR:2:(0.0, 0.0, 1.0, 0.0)
BMR:3:(0.0, 0.0, 0.0, 1.0)
Bone:finger_ring.01.R
Parent:palm.03.R
Head:(-0.3044673204421997, 0.05209998041391373, 0.9532193541526794)
Tail:(-0.2795220613479614, 0.04989997297525406, 0.9160518050193787)
Length:0.044816656419072176
WMR:0:(-0.057007744908332825, 0.5566065907478333, 0.8288182616233826, -0.3044673204421997)
WMR:1:(-0.9981566667556763, -0.04908903315663338, -0.035688575357198715, 0.05209998041391373)
WMR:2:(0.020821411162614822, -0.8293249011039734, 0.5583789348602295, 0.9532193541526794)
WMR:3:(0.0, 0.0, 0.0, 1.0)
BMR:0:(1.0, 0.0, 0.0, 0.0)
BMR:1:(0.0, 1.0, 0.0, 0.0)
BMR:2:(0.0, 0.0, 1.0, 0.0)
BMR:3:(0.0, 0.0, 0.0, 1.0)
Bone:finger_ring.02.R
Parent:finger_ring.01.R
Head:(-0.2795220613479614, 0.04989997297525406, 0.9160518050193787)
Tail:(-0.2580421268939972, 0.0493999682366848, 0.8926069140434265)
Length:0.03180095127129806
WMR:0:(-0.06416677683591843, 0.6754500865936279, 0.7346089482307434, -0.2795220613479614)
WMR:1:(-0.9972335696220398, -0.015722934156656265, -0.0726497694849968, 0.04989997297525406)
WMR:2:(-0.037521060556173325, -0.7372384071350098, 0.6745902895927429, 0.9160518050193787)
WMR:3:(0.0, 0.0, 0.0, 1.0)
BMR:0:(1.0, 0.0, 0.0, 0.0)
BMR:1:(0.0, 1.0, 0.0, 0.0)
BMR:2:(0.0, 0.0, 1.0, 0.0)
BMR:3:(0.0, 0.0, 0.0, 1.0)
...
Edited by BBeck
0

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0