Advertisement
Pixezy

VAT Blender to Godot

Sep 8th, 2024
340
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 7.35 KB | None | 0 0
  1. # ##### BEGIN GPL LICENSE BLOCK #####
  2. #
  3. #  This program is free software; you can redistribute it and/or
  4. #  modify it under the terms of the GNU General Public License
  5. #  as published by the Free Software Foundation; either version 2
  6. #  of the License, or (at your option) any later version.
  7. #
  8. #  This program is distributed in the hope that it will be useful,
  9. #  but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11. #  GNU General Public License for more details.
  12. #
  13. #  You should have received a copy of the GNU General Public License
  14. #  along with this program; if not, write to the Free Software Foundation,
  15. #  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  16. #
  17. # ##### END GPL LICENSE BLOCK #####
  18.  
  19. # <pep8 compliant>
  20.  
  21.  
  22. bl_info = {
  23.     "name": "Vertex Animation",
  24.     "author": "Joshua Bogart",
  25.     "version": (1, 0),
  26.     "blender": (4, 0, 1),
  27.     "location": "View3D > Sidebar > Unreal Tools Tab",
  28.     "description": "A tool for storing per frame vertex data for use in a vertex shader.",
  29.     "warning": "",
  30.     "doc_url": "",
  31.     "category": "Unreal Tools",
  32. }
  33.  
  34.  
  35. import bpy
  36. import bmesh
  37.  
  38.  
  39. def get_per_frame_mesh_data(context, data, objects):
  40.     """Return a list of combined mesh data per frame"""
  41.     meshes = []
  42.     for i in frame_range(context.scene):
  43.         context.scene.frame_set(i)
  44.         depsgraph = context.evaluated_depsgraph_get()
  45.         bm = bmesh.new()
  46.         for ob in objects:
  47.             eval_object = ob.evaluated_get(depsgraph)
  48.             me = data.meshes.new_from_object(eval_object)
  49.             me.transform(ob.matrix_world)
  50.             bm.from_mesh(me)
  51.             data.meshes.remove(me)
  52.         me = data.meshes.new("mesh")
  53.         bm.normal_update()
  54.         bm.to_mesh(me)
  55.         bm.free()
  56.         me.update()
  57.         meshes.append(me)
  58.     return meshes
  59.  
  60.  
  61. def create_export_mesh_object(context, data, me):
  62.     """Return a mesh object with correct UVs"""
  63.     while len(me.uv_layers) < 2:
  64.         me.uv_layers.new()
  65.     uv_layer = me.uv_layers[1]
  66.     uv_layer.name = "vertex_anim"
  67.     for loop in me.loops:
  68.         uv_layer.data[loop.index].uv = (
  69.             (loop.vertex_index + 0.5)/len(me.vertices),0.0)
  70.     ob = data.objects.new("export_mesh", me)
  71.     context.scene.collection.objects.link(ob)
  72.     return ob
  73.  
  74.  
  75. def get_vertex_data(data, meshes):
  76.     """Return lists of vertex offsets and normals from a list of mesh data"""
  77.     original = meshes[0].vertices
  78.     offsets = []
  79.     normals = []
  80.     for me in reversed(meshes):
  81.         for v in me.vertices:
  82.             #offset = v.co - original[v.index].co
  83.             offset = v.co
  84.             x, y, z = offset
  85.             offsets.extend((x, -y, z, 1))
  86.             x, y, z = v.normal
  87.             normals.extend(((x + 1) * 0.5, (-y + 1) * 0.5, (z + 1) * 0.5, 1))
  88.         if not me.users:
  89.             data.meshes.remove(me)
  90.     return offsets, normals
  91.  
  92.  
  93. def frame_range(scene):
  94.     """Return a range object with with scene's frame start, end, and step"""
  95.     return range(scene.frame_start, scene.frame_end, scene.frame_step)
  96.  
  97.  
  98. def bake_vertex_data(data, offsets, normals, size):
  99.     """Stores vertex offsets and normals in seperate image textures"""
  100.     width, height = size
  101.     offset_texture = data.images.new(
  102.         #name="offsets",
  103.         name="absolutes",
  104.         width=width,
  105.         height=height,
  106.         alpha=True,
  107.         float_buffer=True
  108.     )
  109.     normal_texture = data.images.new(
  110.         name="normals",
  111.         width=width,
  112.         height=height,
  113.         alpha=True
  114.     )
  115.     offset_texture.pixels = offsets
  116.     normal_texture.pixels = normals
  117.    
  118. def is_simulation_baked(ob, mod_type):
  119.     for mod in ob.modifiers:
  120.         if mod.type == mod_type and mod.point_cache.is_baked:
  121.             return True
  122.     return False
  123.  
  124.  
  125.  
  126. class OBJECT_OT_ProcessAnimMeshes(bpy.types.Operator):
  127.     """Store combined per frame vertex offsets and normals for all
  128.    selected mesh objects into seperate image textures"""
  129.     bl_idname = "object.process_anim_meshes"
  130.     bl_label = "Process Anim Meshes"
  131.  
  132.     @property
  133.     def allowed_modifiers(self):
  134.         return [
  135.             'ARMATURE', 'CAST','CLOTH','CURVE', 'DISPLACE', 'HOOK',
  136.             'LAPLACIANDEFORM', 'LATTICE', 'MESH_DEFORM',
  137.             'SHRINKWRAP', 'SIMPLE_DEFORM', 'SMOOTH',
  138.             'CORRECTIVE_SMOOTH', 'LAPLACIANSMOOTH',
  139.             'SURFACE_DEFORM', 'WARP', 'WAVE',
  140.         ]
  141.  
  142.     @classmethod
  143.     def poll(cls, context):
  144.         ob = context.active_object
  145.         return ob and ob.type == 'MESH' and ob.mode == 'OBJECT'
  146.  
  147.     def execute(self, context):
  148.         units = context.scene.unit_settings
  149.         data = bpy.data
  150.         objects = [ob for ob in context.selected_objects if ob.type == 'MESH']
  151.         vertex_count = sum([len(ob.data.vertices) for ob in objects])
  152.         frame_count = len(frame_range(context.scene))
  153.         for ob in objects:
  154.             for mod in ob.modifiers:
  155.                 if mod.type not in self.allowed_modifiers:
  156.                     self.report(
  157.                         {'ERROR'},
  158.                         f"Objects with {mod.type.title()} modifiers are not allowed!"
  159.                     )
  160.                     return {'CANCELLED'}
  161.          
  162.         if vertex_count > 8192:
  163.             self.report(
  164.                 {'ERROR'},
  165.                 f"Vertex count of {vertex_count :,}, execedes limit of 8,192!"
  166.             )
  167.             return {'CANCELLED'}
  168.         if frame_count > 8192:
  169.             self.report(
  170.                 {'ERROR'},
  171.                 f"Frame count of {frame_count :,}, execedes limit of 8,192!"
  172.             )
  173.             return {'CANCELLED'}
  174.         if mod.type == 'CLOTH' and not is_simulation_baked(ob, 'CLOTH'):
  175.                 self.report(
  176.                     {'ERROR'},
  177.                     f"Cloth simulation for object {ob.name} is not baked!"
  178.                 )
  179.                 return {'CANCELLED'}
  180.         meshes = get_per_frame_mesh_data(context, data, objects)
  181.         export_mesh_data = meshes[0].copy()
  182.         create_export_mesh_object(context, data, export_mesh_data)
  183.         offsets, normals = get_vertex_data(data, meshes)
  184.         texture_size = vertex_count, frame_count
  185.         bake_vertex_data(data, offsets, normals, texture_size)
  186.         return {'FINISHED'}
  187.  
  188.  
  189. class VIEW3D_PT_VertexAnimation(bpy.types.Panel):
  190.     """Creates a Panel in 3D Viewport"""
  191.     bl_label = "Vertex Animation"
  192.     bl_idname = "VIEW3D_PT_vertex_animation"
  193.     bl_space_type = 'VIEW_3D'
  194.     bl_region_type = 'UI'
  195.     bl_category = "Unreal Tools"
  196.  
  197.     def draw(self, context):
  198.         layout = self.layout
  199.         layout.use_property_split = True
  200.         layout.use_property_decorate = False
  201.         scene = context.scene
  202.         col = layout.column(align=True)
  203.         col.prop(scene, "frame_start", text="Frame Start")
  204.         col.prop(scene, "frame_end", text="End")
  205.         col.prop(scene, "frame_step", text="Step")
  206.         row = layout.row()
  207.         row.operator("object.process_anim_meshes")
  208.  
  209.  
  210. def register():
  211.     bpy.utils.register_class(OBJECT_OT_ProcessAnimMeshes)
  212.     bpy.utils.register_class(VIEW3D_PT_VertexAnimation)
  213.  
  214.  
  215. def unregister():
  216.     bpy.utils.unregister_class(OBJECT_OT_ProcessAnimMeshes)
  217.     bpy.utils.unregister_class(VIEW3D_PT_VertexAnimation)
  218.  
  219.  
  220. if __name__ == "__main__":
  221.     register()
  222.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement