Compare commits
83 Commits
Author | SHA1 | Date |
---|---|---|
|
6bab53b555 | |
|
8f9217bf6f | |
|
5dd86517c7 | |
|
839602bce3 | |
|
a93d473f3d | |
|
8a8216dc4d | |
|
a72a008600 | |
|
f3ce5e2fd5 | |
|
bbe112b604 | |
|
1c63605918 | |
|
55bc9c3f54 | |
|
30b2c1465c | |
|
42764ccd59 | |
|
49bbbc2dce | |
|
69ac02169c | |
|
c31c441684 | |
|
c14c5432e7 | |
|
98c9ace5d8 | |
|
8d4e4501e2 | |
|
d07fa2d299 | |
|
8974148824 | |
|
844e03760b | |
|
5b59ec1ba3 | |
|
f1f0318b54 | |
|
0a6c810f0b | |
|
035cfbed04 | |
|
7289d51563 | |
|
ae736ee8c4 | |
|
291aee7fe5 | |
|
f1f879097d | |
|
bd0ac82b99 | |
|
bc4d0a2bcd | |
|
ff78241314 | |
|
e689430fc8 | |
|
7697680b48 | |
|
6ba0413c63 | |
|
e4fcacd862 | |
|
75d718f880 | |
|
8736d3f4b7 | |
|
97a025dce7 | |
|
7cc84a24c4 | |
|
db0b04271a | |
|
771b23154e | |
|
b26f988ad7 | |
|
020db04f31 | |
|
5a3ae3be48 | |
|
3a475f1139 | |
|
a2b32c4481 | |
|
4c3d991d29 | |
|
1cb85eab8f | |
|
fa05591cd0 | |
|
26972e89b0 | |
|
2ab7d1568c | |
|
b7f252160f | |
|
4f3916b70a | |
|
bc89429a2c | |
|
efda4128fd | |
|
54fcba4f6b | |
|
018b64e56e | |
|
4efc99c292 | |
|
e02111e871 | |
|
12e38abae2 | |
|
8b4b5e54bf | |
|
89c5df1a2a | |
|
cce17cae23 | |
|
274ee76526 | |
|
1b1764dced | |
|
1d0fa8e490 | |
|
0b46c57a68 | |
|
635195c12f | |
|
dc0b7c2dcd | |
|
65387ed4ec | |
|
1f61ef05f6 | |
|
fb02265dec | |
|
abd10197ea | |
|
3383b76238 | |
|
974cf50793 | |
|
2facd88064 | |
|
3cadd3b6ab | |
|
2276c7415a | |
|
757463a270 | |
|
64effa5844 | |
|
1cfbc10731 |
|
@ -12,3 +12,4 @@
|
||||||
*.xcf filter=lfs diff=lfs merge=lfs -text lockable
|
*.xcf filter=lfs diff=lfs merge=lfs -text lockable
|
||||||
*.jpg filter=lfs diff=lfs merge=lfs -text lockable
|
*.jpg filter=lfs diff=lfs merge=lfs -text lockable
|
||||||
*.blend filter=lfs diff=lfs merge=lfs -text lockable
|
*.blend filter=lfs diff=lfs merge=lfs -text lockable
|
||||||
|
*.zip filter=lfs diff=lfs merge=lfs -text lockable
|
||||||
|
|
|
@ -50,6 +50,7 @@ SourceArt/**/*.tga
|
||||||
# Binary Files
|
# Binary Files
|
||||||
Binaries/*
|
Binaries/*
|
||||||
Plugins/*/Binaries/*
|
Plugins/*/Binaries/*
|
||||||
|
Plugins/Marketplace/*/Binaries/*
|
||||||
|
|
||||||
# Packages
|
# Packages
|
||||||
Packages/*
|
Packages/*
|
||||||
|
@ -74,6 +75,7 @@ Saved/*
|
||||||
# Compiled source files for the engine to use
|
# Compiled source files for the engine to use
|
||||||
Intermediate/*
|
Intermediate/*
|
||||||
Plugins/*/Intermediate/*
|
Plugins/*/Intermediate/*
|
||||||
|
Plugins/Marketplace/*/Intermediate/*
|
||||||
|
|
||||||
# Cache files for the editor to use
|
# Cache files for the editor to use
|
||||||
DerivedDataCache/*
|
DerivedDataCache/*
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,160 @@
|
||||||
|
import bpy
|
||||||
|
import os
|
||||||
|
from bpy.props import (StringProperty, PointerProperty, EnumProperty, BoolProperty)
|
||||||
|
from bpy.types import (Panel, Operator, AddonPreferences, PropertyGroup)
|
||||||
|
|
||||||
|
bl_info = \
|
||||||
|
{
|
||||||
|
"name": "Unreal Exporter",
|
||||||
|
"author": "Bozarre",
|
||||||
|
"version": (1, 0, 0),
|
||||||
|
"blender": (4, 2, 0),
|
||||||
|
"location": "View 3D > Object Mode > Unreal Exporter",
|
||||||
|
"description":
|
||||||
|
"Batch exporter for Unreal Engine",
|
||||||
|
"warning": "",
|
||||||
|
"wiki_url": "",
|
||||||
|
"tracker_url": "",
|
||||||
|
"category": "Exporter",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class UEExporterSettings(PropertyGroup):
|
||||||
|
|
||||||
|
path : StringProperty(
|
||||||
|
#name="",
|
||||||
|
description="Path to Directory (empty means same as curren file)",
|
||||||
|
default="//",
|
||||||
|
maxlen=1024,
|
||||||
|
subtype='FILE_PATH')
|
||||||
|
|
||||||
|
source_collection : StringProperty(
|
||||||
|
description="Collection name (collisions don't have to be in the same collection",
|
||||||
|
default="Export",
|
||||||
|
maxlen=1024)
|
||||||
|
|
||||||
|
collisions: BoolProperty(
|
||||||
|
name="Export Collisions",
|
||||||
|
description="Whether to export the collision shapes",
|
||||||
|
default = True
|
||||||
|
)
|
||||||
|
|
||||||
|
local_origin: BoolProperty(
|
||||||
|
name="Export Origin",
|
||||||
|
description="Whether to use the objects origin as the export origin",
|
||||||
|
default = False
|
||||||
|
)
|
||||||
|
|
||||||
|
class VIEW3D_PT_PanelExportAll(bpy.types.Panel):
|
||||||
|
bl_label = "Export Selected"
|
||||||
|
bl_space_type = "VIEW_3D"
|
||||||
|
bl_region_type = "UI"
|
||||||
|
bl_category = "UE Exporter"
|
||||||
|
bl_context = "objectmode"
|
||||||
|
|
||||||
|
def draw(self, context):
|
||||||
|
layout = self.layout
|
||||||
|
scn = context.scene
|
||||||
|
layout.label(text="Export Path Location:")
|
||||||
|
layout.prop(scn.ue_exporter, "path", text="")
|
||||||
|
layout.label(text="Collection to export")
|
||||||
|
layout.prop(scn.ue_exporter, "source_collection", text="")
|
||||||
|
layout.prop(scn.ue_exporter, "local_origin", text=" Export Origin")
|
||||||
|
layout.prop(scn.ue_exporter, "collisions", text=" Export Collisions")
|
||||||
|
layout.operator("ue_exporter_obs.separate_export", text='Export Seperate', icon='TRIA_RIGHT')
|
||||||
|
layout.operator("ue_exporter_obs.combine_export", text='Export Combined', icon='TRIA_RIGHT')
|
||||||
|
|
||||||
|
|
||||||
|
class OBJECT_OT_SeparateExport(bpy.types.Operator):
|
||||||
|
bl_idname = "ue_exporter_obs.separate_export"
|
||||||
|
bl_label = "Export Selected"
|
||||||
|
bl_options = {"UNDO"}
|
||||||
|
def execute(self, context):
|
||||||
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
def invoke(self, context, event):
|
||||||
|
SeparateExport(context.scene.ue_exporter.path)
|
||||||
|
self.report({'INFO'}, 'Exported')
|
||||||
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
class OBJECT_OT_CombineExport(bpy.types.Operator):
|
||||||
|
bl_idname = "ue_exporter_obs.combine_export"
|
||||||
|
bl_label = "Export Selected"
|
||||||
|
bl_options = {"UNDO"}
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
def invoke(self, context, event):
|
||||||
|
CombineExport(context.scene.ue_exporter.path)
|
||||||
|
self.report({'INFO'}, 'Did nothing (yet)')
|
||||||
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
def SeparateExport(exportFolder):
|
||||||
|
collection_collision_export = bpy.data.collections.new("Collision.Export")
|
||||||
|
bpy.context.scene.collection.children.link(collection_collision_export)
|
||||||
|
objects = bpy.data.collections[bpy.context.scene.ue_exporter.source_collection].all_objects
|
||||||
|
bpy.ops.object.select_all(action='DESELECT')
|
||||||
|
for object in list(objects):
|
||||||
|
if object.type not in ['MESH']:
|
||||||
|
continue
|
||||||
|
if (('UCX_' + object.name) in bpy.data.objects):
|
||||||
|
collision = bpy.data.objects['UCX_' + object.name]
|
||||||
|
export_collision = collision.copy()
|
||||||
|
export_collision.data = collision.data.copy()
|
||||||
|
export_collision.animation_data_clear()
|
||||||
|
bpy.context.collection.objects.link(export_collision)
|
||||||
|
collection_collision_export.objects.link(export_collision)
|
||||||
|
export_collision.select_set(True)
|
||||||
|
bpy.context.view_layer.objects.active = export_collision
|
||||||
|
bpy.ops.object.modifier_apply(modifier='GeometryNodes')
|
||||||
|
bpy.ops.mesh.separate(type='LOOSE')
|
||||||
|
object.select_set(True)
|
||||||
|
exportName = bpy.path.abspath(exportFolder) + object.name + '.fbx'
|
||||||
|
bpy.ops.export_scene.fbx(filepath=exportName, use_selection=True, mesh_smooth_type='FACE')
|
||||||
|
bpy.ops.object.select_all(action='DESELECT')
|
||||||
|
objects = collection_collision_export.all_objects
|
||||||
|
for object in objects:
|
||||||
|
object.select_set(True)
|
||||||
|
bpy.ops.object.delete()
|
||||||
|
bpy.data.collections.remove(collection_collision_export)
|
||||||
|
|
||||||
|
def CombineExport(exportFolder):
|
||||||
|
return
|
||||||
|
#TBD
|
||||||
|
|
||||||
|
classes = (
|
||||||
|
VIEW3D_PT_PanelExportAll,
|
||||||
|
OBJECT_OT_SeparateExport,
|
||||||
|
OBJECT_OT_CombineExport,
|
||||||
|
UEExporterSettings
|
||||||
|
)
|
||||||
|
|
||||||
|
def apply_modifiers(obj):
|
||||||
|
ctx = bpy.context.copy()
|
||||||
|
ctx['object'] = obj
|
||||||
|
for _, m in enumerate(obj.modifiers):
|
||||||
|
try:
|
||||||
|
ctx['modifier'] = m
|
||||||
|
bpy.ops.object.modifier_apply(ctx, modifier=m.name)
|
||||||
|
except RuntimeError:
|
||||||
|
print(f"Error applying {m.name} to {obj.name}, removing it instead.")
|
||||||
|
obj.modifiers.remove(m)
|
||||||
|
|
||||||
|
for m in obj.modifiers:
|
||||||
|
obj.modifiers.remove(m)
|
||||||
|
|
||||||
|
def register():
|
||||||
|
for c in classes:
|
||||||
|
bpy.utils.register_class(c)
|
||||||
|
bpy.types.Scene.ue_exporter = bpy.props.PointerProperty(type=UEExporterSettings)
|
||||||
|
|
||||||
|
|
||||||
|
def unregister():
|
||||||
|
for c in reversed(classes):
|
||||||
|
bpy.utils.unregister_class(c)
|
||||||
|
del bpy.types.Scene.ue_exporter
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
register()
|
|
@ -0,0 +1,619 @@
|
||||||
|
##
|
||||||
|
# A script to split simple, architectural geometry into convex pieces.
|
||||||
|
#
|
||||||
|
# This script makes use of Blender's built-in "Split Concave Faces" clean-up
|
||||||
|
# algorithm to break-up the faces of an object into convex pieces. The script
|
||||||
|
# attempts to identify all the edges that represent convex boundaries, and then
|
||||||
|
# it splits objects up along those edges. Each resulting piece is then made into
|
||||||
|
# a closed object by converting it into a convex hull.
|
||||||
|
#
|
||||||
|
# Be sure to select the object you wish the split into convex pieces before
|
||||||
|
# running the script.
|
||||||
|
#
|
||||||
|
# NOTE: This script is expecting to work with flat, reasonably clean geometry.
|
||||||
|
# For example, it is expected to be used when generating collision on the
|
||||||
|
# ceiling and walls of an architectural visualization project, but is not
|
||||||
|
# expected to perform well with round or n-gon geometry. Using
|
||||||
|
# create_closed_objects=True and matchup_degenerates=True, in particular, does
|
||||||
|
# not work well with objects that have openings inside.
|
||||||
|
#
|
||||||
|
# If this script doesn't work for you, a plug-in like V-HACD may work better.
|
||||||
|
# This script was written to handle cases V-HACD did not handle well -- flat,
|
||||||
|
# reasonably rectangular arch. vis. geometry.
|
||||||
|
#
|
||||||
|
# @author Guy Elsmore-Paddock <guy.paddock@gmail.com>
|
||||||
|
#
|
||||||
|
|
||||||
|
import bmesh
|
||||||
|
import bpy
|
||||||
|
import operator
|
||||||
|
import re
|
||||||
|
|
||||||
|
from itertools import combinations, count
|
||||||
|
from math import atan2, pi, radians, degrees
|
||||||
|
from mathutils import Vector
|
||||||
|
|
||||||
|
|
||||||
|
def split_into_convex_pieces(ob, create_closed_objects=True,
|
||||||
|
matchup_degenerates=True):
|
||||||
|
object_name = ob.name
|
||||||
|
|
||||||
|
deselect_all_objects()
|
||||||
|
make_all_faces_convex(ob)
|
||||||
|
|
||||||
|
eliminated_piece_names = \
|
||||||
|
split_on_convex_boundaries(
|
||||||
|
ob,
|
||||||
|
create_closed_objects,
|
||||||
|
matchup_degenerates
|
||||||
|
)
|
||||||
|
|
||||||
|
rename_pieces(object_name, eliminated_piece_names)
|
||||||
|
|
||||||
|
# Deselect everything, for the convenience of the user.
|
||||||
|
deselect_all_objects()
|
||||||
|
|
||||||
|
|
||||||
|
def make_all_faces_convex(ob):
|
||||||
|
bpy.context.view_layer.objects.active = ob
|
||||||
|
bpy.ops.object.mode_set(mode='EDIT')
|
||||||
|
|
||||||
|
# This is what actually defines the new geometry -- Blender creates the
|
||||||
|
# convex shapes we need to split by.
|
||||||
|
bpy.ops.mesh.select_all(action='SELECT')
|
||||||
|
bpy.ops.mesh.vert_connect_concave()
|
||||||
|
bpy.ops.mesh.select_all(action='DESELECT')
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
# Splits an object into smaller pieces by its convex, planar edges.
|
||||||
|
#
|
||||||
|
# In an ideal world, we could just split the object by all the edges that are
|
||||||
|
# attached to -- and are co-planar with -- the faces of the object, since those
|
||||||
|
# edges are most likely to represent the convex boundaries of the object. But,
|
||||||
|
# Blender does not provide an easy way to find such edges.
|
||||||
|
#
|
||||||
|
# Instead, we use several heuristics to simulate this type of selection:
|
||||||
|
# 1. First, we select all the sharp edges of the object, since sharp edges are
|
||||||
|
# only co-planar with one of the faces they connect with and are therefore
|
||||||
|
# unlikely to represent convex boundary edges.
|
||||||
|
# 2. Second, we select all edges that are similar in angle to the sharp edges,
|
||||||
|
# to catch any edges that are almost steep enough to be sharp edges.
|
||||||
|
# 3. Third, we invert the selection, which should (hopefully) cause all the
|
||||||
|
# convex boundary edges we want to be selected.
|
||||||
|
# 4. Fourth, we seek out any sharp edges that connect with the convex boundary
|
||||||
|
# edges, since we will need to split on these edges as well so that our
|
||||||
|
# "cuts" go all the way around the object (e.g. if the convex boundary
|
||||||
|
# edges lay on the top and bottom faces of an object, we need to select
|
||||||
|
# sharp edges to connect the top and bottom edges on the left and right
|
||||||
|
# sides so that each split piece is a complete shape instead of just
|
||||||
|
# disconnected, detached planes).
|
||||||
|
# 4. Next, we split the object by all selected edges, which should result in
|
||||||
|
# creation of each convex piece we seek.
|
||||||
|
#
|
||||||
|
def split_on_convex_boundaries(ob, create_closed_objects=True,
|
||||||
|
matchup_degenerates=True):
|
||||||
|
bpy.ops.object.mode_set(mode='EDIT')
|
||||||
|
|
||||||
|
select_convex_boundary_edges(ob)
|
||||||
|
|
||||||
|
# Now perform an vertex + edge split along each selected edge, which should
|
||||||
|
# result in the object being broken-up along each planar edge and connected
|
||||||
|
# sharp edges (e.g. on corners).
|
||||||
|
bpy.ops.mesh.edge_split(type='VERT')
|
||||||
|
|
||||||
|
# Now, just break each loose part off into a separate object.
|
||||||
|
bpy.ops.mesh.select_all(action='SELECT')
|
||||||
|
bpy.ops.mesh.separate(type='LOOSE')
|
||||||
|
|
||||||
|
if create_closed_objects:
|
||||||
|
# And then make each piece fully enclosed.
|
||||||
|
return create_closed_shapes_from_pieces(ob, matchup_degenerates)
|
||||||
|
else:
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
# Selects all edges that denote the boundaries of convex pieces.
|
||||||
|
#
|
||||||
|
# This is a multi-step process driven by heuristics:
|
||||||
|
# 1. First, we select all the sharp edges of the object, since sharp edges are
|
||||||
|
# only co-planar with one of the faces they connect with and are therefore
|
||||||
|
# unlikely to represent convex boundary edges.
|
||||||
|
# 2. Second, we select all edges that are similar in length to the sharp
|
||||||
|
# edges, to catch any edges that are almost steep enough to be sharp edges.
|
||||||
|
# 3. Third, we invert the selection, which should (hopefully) cause all the
|
||||||
|
# convex boundary edges we want to be selected.
|
||||||
|
#
|
||||||
|
def select_convex_boundary_edges(ob, max_edge_length_proportion=0.1):
|
||||||
|
bpy.ops.object.mode_set(mode='EDIT')
|
||||||
|
|
||||||
|
mesh = ob.data
|
||||||
|
bm = bmesh.from_edit_mesh(mesh)
|
||||||
|
|
||||||
|
# Enter "Edge" select mode
|
||||||
|
bpy.context.tool_settings.mesh_select_mode = [False, True, False]
|
||||||
|
|
||||||
|
# Find all sharp edges and edges of similar length
|
||||||
|
bpy.ops.mesh.select_all(action='DESELECT')
|
||||||
|
bpy.ops.mesh.edges_select_sharp()
|
||||||
|
bpy.ops.mesh.select_similar(type='LENGTH', threshold=0.01)
|
||||||
|
|
||||||
|
# Invert the selection to find the convex boundary edges.
|
||||||
|
bpy.ops.mesh.select_all(action='INVERT')
|
||||||
|
|
||||||
|
bm.faces.ensure_lookup_table()
|
||||||
|
bm.edges.ensure_lookup_table()
|
||||||
|
|
||||||
|
edges_to_select = []
|
||||||
|
max_edge_length = max(ob.dimensions) * max_edge_length_proportion
|
||||||
|
|
||||||
|
for selected_edge in [e for e in bm.edges if e.select]:
|
||||||
|
edge_bridges =\
|
||||||
|
find_shortest_edge_bridges(
|
||||||
|
selected_edge,
|
||||||
|
max_edge_length=max_edge_length
|
||||||
|
)
|
||||||
|
|
||||||
|
for path in edge_bridges.values():
|
||||||
|
for edge in path:
|
||||||
|
edges_to_select.append(edge)
|
||||||
|
|
||||||
|
# Select the edges after we pick which edges we *want* to select, to ensure
|
||||||
|
# that we only base our decisions on the initial convex boundary edges.
|
||||||
|
for edge in edges_to_select:
|
||||||
|
edge.select = True
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
# Locate the shortest path of edges to connect already-selected edges.
|
||||||
|
#
|
||||||
|
# This is used to find the additional edges that must be selected for a cut
|
||||||
|
# along a convex boundary to create a complete, closed object shape.
|
||||||
|
#
|
||||||
|
# The max edge length argument can be provided to avoid trying to find
|
||||||
|
# connections between convex boundaries that are very far apart in the same
|
||||||
|
# object.
|
||||||
|
#
|
||||||
|
def find_shortest_edge_bridges(starting_edge, max_edge_length=None):
|
||||||
|
edge_bridges = find_bridge_edges(starting_edge, max_edge_length)
|
||||||
|
sorted_edge_bridges = sorted(edge_bridges, key=lambda eb: eb[0])
|
||||||
|
edge_solutions = {}
|
||||||
|
|
||||||
|
for edge_bridge in sorted_edge_bridges:
|
||||||
|
path_distance, final_edge, path = edge_bridge
|
||||||
|
|
||||||
|
# Skip edges we've already found a min-length path to
|
||||||
|
if final_edge not in edge_solutions.keys():
|
||||||
|
edge_solutions[final_edge] = path
|
||||||
|
|
||||||
|
print(f"Shortest edge bridges for starting edge '{str(starting_edge.index)}':")
|
||||||
|
|
||||||
|
if len(edge_solutions) > 0:
|
||||||
|
print(
|
||||||
|
" - " +
|
||||||
|
"\n - ".join(map(
|
||||||
|
lambda i: str(
|
||||||
|
(i[0].index, str(list(map(lambda e: e.index, i[1]))))
|
||||||
|
),
|
||||||
|
edge_solutions.items()
|
||||||
|
)))
|
||||||
|
print("")
|
||||||
|
print("")
|
||||||
|
|
||||||
|
return edge_solutions
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
# Performs a recursive, depth-first search from a selected edge to other edges.
|
||||||
|
#
|
||||||
|
# This returns all possible paths -- and distances of those paths -- to traverse
|
||||||
|
# the mesh from the starting, selected edge to another selected edge. To avoid
|
||||||
|
# a lengthy search, the max_depth parameter controls how many levels of edges
|
||||||
|
# are searched.
|
||||||
|
#
|
||||||
|
# The result is an array of tuples, where each tuple contains the total distance
|
||||||
|
# of the path, the already-selected edge that the path was able to reach, and
|
||||||
|
# the list of edges that would need to be selected in order to reach that
|
||||||
|
# destination edge.
|
||||||
|
#
|
||||||
|
def find_bridge_edges(edge, max_edge_length=None, max_depth=3, current_depth=0,
|
||||||
|
path_distance=0, edge_path=None, seen_verts=None):
|
||||||
|
if edge_path is None:
|
||||||
|
edge_path = []
|
||||||
|
|
||||||
|
if seen_verts is None:
|
||||||
|
seen_verts = []
|
||||||
|
|
||||||
|
# Don't bother searching edges we've seen
|
||||||
|
if edge in edge_path:
|
||||||
|
return []
|
||||||
|
|
||||||
|
if (current_depth > 0):
|
||||||
|
first_edge = edge_path[0]
|
||||||
|
edge_length = edge.calc_length()
|
||||||
|
|
||||||
|
# Don't bother searching edges along the same normal as the first edge.
|
||||||
|
# We want our cuts to be along convex boundaries that are perpendicular.
|
||||||
|
if have_common_face(first_edge, edge):
|
||||||
|
return []
|
||||||
|
|
||||||
|
if edge.select:
|
||||||
|
return [(path_distance, edge, edge_path)]
|
||||||
|
|
||||||
|
# Disqualify edges that are too long.
|
||||||
|
if max_edge_length is not None and edge_length > max_edge_length:
|
||||||
|
print(
|
||||||
|
f"Disqualifying edge {edge.index} because length [{edge_length}] > [{max_edge_length}"
|
||||||
|
)
|
||||||
|
|
||||||
|
return []
|
||||||
|
|
||||||
|
if current_depth == max_depth:
|
||||||
|
return []
|
||||||
|
|
||||||
|
new_edge_path = edge_path + [edge]
|
||||||
|
bridges = []
|
||||||
|
|
||||||
|
for edge_vert in edge.verts:
|
||||||
|
# Don't bother searching vertices we've already seen (no backtracking).
|
||||||
|
if edge_vert in seen_verts:
|
||||||
|
continue
|
||||||
|
|
||||||
|
new_seen_verts = seen_verts + [edge_vert]
|
||||||
|
|
||||||
|
for linked_edge in edge_vert.link_edges:
|
||||||
|
# Don't bother searching selected edges connected to the starting
|
||||||
|
# edge, since that gets us nowhere.
|
||||||
|
if linked_edge.select and current_depth == 0:
|
||||||
|
continue
|
||||||
|
|
||||||
|
edge_length = linked_edge.calc_length()
|
||||||
|
|
||||||
|
found_bridge_edges = find_bridge_edges(
|
||||||
|
edge=linked_edge,
|
||||||
|
max_edge_length=max_edge_length,
|
||||||
|
max_depth=max_depth,
|
||||||
|
current_depth=current_depth + 1,
|
||||||
|
path_distance=path_distance + edge_length,
|
||||||
|
edge_path=new_edge_path,
|
||||||
|
seen_verts=new_seen_verts
|
||||||
|
)
|
||||||
|
|
||||||
|
bridges.extend(found_bridge_edges)
|
||||||
|
|
||||||
|
return bridges
|
||||||
|
|
||||||
|
|
||||||
|
def create_closed_shapes_from_pieces(ob, matchup_degenerates=True,
|
||||||
|
min_volume=0.1):
|
||||||
|
print("Converting each piece into a closed object...")
|
||||||
|
|
||||||
|
degenerate_piece_names = []
|
||||||
|
|
||||||
|
for piece in name_duplicates_of(ob):
|
||||||
|
if not make_piece_convex(piece):
|
||||||
|
degenerate_piece_names.append(piece.name)
|
||||||
|
|
||||||
|
degenerate_count = len(degenerate_piece_names)
|
||||||
|
|
||||||
|
print("")
|
||||||
|
print(f"Total degenerate (flat) pieces: {degenerate_count}")
|
||||||
|
print("")
|
||||||
|
|
||||||
|
eliminated_piece_names = []
|
||||||
|
|
||||||
|
if matchup_degenerates:
|
||||||
|
if degenerate_count > 10:
|
||||||
|
# TODO: Hopefully, some day, find a good deterministic way to
|
||||||
|
# automatically match up any number of degenerate pieces using a
|
||||||
|
# heuristic that generates sane geometry.
|
||||||
|
print(
|
||||||
|
"There are too many degenerates for reliable auto-matching, so "
|
||||||
|
"it will not be performed. You will need to manually combine "
|
||||||
|
"degenerate pieces.")
|
||||||
|
print("")
|
||||||
|
else:
|
||||||
|
eliminated_piece_names.extend(
|
||||||
|
matchup_degenerate_pieces(degenerate_piece_names, min_volume)
|
||||||
|
)
|
||||||
|
|
||||||
|
eliminated_piece_names.extend(
|
||||||
|
eliminate_tiny_pieces(degenerate_piece_names, min_volume)
|
||||||
|
)
|
||||||
|
|
||||||
|
return eliminated_piece_names
|
||||||
|
|
||||||
|
|
||||||
|
def matchup_degenerate_pieces(degenerate_piece_names, min_volume=0.1):
|
||||||
|
pieces_eliminated = []
|
||||||
|
degenerate_volumes = find_degenerate_combos(degenerate_piece_names)
|
||||||
|
|
||||||
|
print("Searching for a way to match-up degenerates into volumes...")
|
||||||
|
|
||||||
|
for piece1_name, piece1_volumes in degenerate_volumes.items():
|
||||||
|
# Skip pieces already joined with degenerate pieces we've processed
|
||||||
|
if piece1_name not in degenerate_piece_names:
|
||||||
|
continue
|
||||||
|
|
||||||
|
piece1 = bpy.data.objects[piece1_name]
|
||||||
|
|
||||||
|
piece1_volumes_asc = dict(
|
||||||
|
sorted(
|
||||||
|
piece1_volumes.items(),
|
||||||
|
key=operator.itemgetter(1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
piece2 = None
|
||||||
|
|
||||||
|
for piece2_name, combo_volume in piece1_volumes_asc.items():
|
||||||
|
# Skip pieces that would make a volume that's too small, or that
|
||||||
|
# have been joined with degenerate pieces we've processed
|
||||||
|
if combo_volume < min_volume or piece2_name not in degenerate_piece_names:
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
piece2 = bpy.data.objects[piece2_name]
|
||||||
|
break
|
||||||
|
|
||||||
|
if piece2 is not None:
|
||||||
|
degenerate_piece_names.remove(piece2.name)
|
||||||
|
pieces_eliminated.append(piece2.name)
|
||||||
|
|
||||||
|
print(
|
||||||
|
f" - Combining parallel degenerate '{piece1.name}' with "
|
||||||
|
f"'{piece2.name}' to form complete mesh '{piece1.name}'."
|
||||||
|
)
|
||||||
|
|
||||||
|
bpy.ops.object.mode_set(mode='OBJECT')
|
||||||
|
bpy.ops.object.select_all(action='DESELECT')
|
||||||
|
|
||||||
|
bpy.context.view_layer.objects.active = piece1
|
||||||
|
|
||||||
|
piece1.select_set(True)
|
||||||
|
piece2.select_set(True)
|
||||||
|
|
||||||
|
bpy.ops.object.join()
|
||||||
|
|
||||||
|
make_piece_convex(piece1)
|
||||||
|
|
||||||
|
return pieces_eliminated
|
||||||
|
|
||||||
|
|
||||||
|
def find_degenerate_combos(degenerate_piece_names):
|
||||||
|
volumes = {}
|
||||||
|
|
||||||
|
for piece_combo in combinations(degenerate_piece_names, 2):
|
||||||
|
piece1_name, piece2_name = piece_combo
|
||||||
|
piece1 = bpy.data.objects[piece1_name]
|
||||||
|
piece2 = bpy.data.objects[piece2_name]
|
||||||
|
|
||||||
|
if not volumes.get(piece1_name):
|
||||||
|
volumes[piece1_name] = {}
|
||||||
|
|
||||||
|
piece1_mesh = piece1.data
|
||||||
|
piece1_bm = bmesh.new()
|
||||||
|
piece1_bm.from_mesh(piece1_mesh)
|
||||||
|
|
||||||
|
piece2_mesh = piece2.data
|
||||||
|
piece2_bm = bmesh.new()
|
||||||
|
piece2_bm.from_mesh(piece2_mesh)
|
||||||
|
|
||||||
|
piece1_bm.faces.ensure_lookup_table()
|
||||||
|
piece2_bm.faces.ensure_lookup_table()
|
||||||
|
|
||||||
|
if (len(piece1_bm.faces) == 0) or (len(piece2_bm.faces) == 0):
|
||||||
|
continue
|
||||||
|
|
||||||
|
piece1_face = piece1_bm.faces[0]
|
||||||
|
piece2_face = piece2_bm.faces[0]
|
||||||
|
|
||||||
|
combo_angle_radians = piece1_face.normal.angle(piece2_face.normal)
|
||||||
|
combo_angle_degrees = int(round(degrees(combo_angle_radians)))
|
||||||
|
|
||||||
|
# We only combine faces that are parallel to each other
|
||||||
|
if combo_angle_degrees in [0, 180]:
|
||||||
|
combo_volume = convex_volume(piece1, piece2)
|
||||||
|
|
||||||
|
volumes[piece1.name][piece2.name] = combo_volume
|
||||||
|
|
||||||
|
return volumes
|
||||||
|
|
||||||
|
|
||||||
|
def eliminate_tiny_pieces(degenerate_piece_names, min_volume=0.1):
|
||||||
|
eliminated_piece_names = []
|
||||||
|
|
||||||
|
tiny_piece_names = [
|
||||||
|
n for n in degenerate_piece_names
|
||||||
|
if n not in eliminated_piece_names
|
||||||
|
and convex_volume(bpy.data.objects.get(n)) < min_volume
|
||||||
|
]
|
||||||
|
|
||||||
|
print("")
|
||||||
|
print(f"Total remaining tiny pieces: {len(tiny_piece_names)}")
|
||||||
|
|
||||||
|
# Delete tiny pieces that are too small to be useful
|
||||||
|
for tiny_piece_name in tiny_piece_names:
|
||||||
|
print(f" - Eliminating tiny piece '{tiny_piece_name}'...")
|
||||||
|
|
||||||
|
tiny_piece = bpy.data.objects[tiny_piece_name]
|
||||||
|
|
||||||
|
bpy.data.objects.remove(tiny_piece, do_unlink=True)
|
||||||
|
eliminated_piece_names.append(tiny_piece_name)
|
||||||
|
|
||||||
|
print("")
|
||||||
|
|
||||||
|
return eliminated_piece_names
|
||||||
|
|
||||||
|
|
||||||
|
def make_piece_convex(ob, min_volume=0.1):
|
||||||
|
print(
|
||||||
|
f" - Attempting to make '{ob.name}' into a closed, convex "
|
||||||
|
f"shape."
|
||||||
|
)
|
||||||
|
|
||||||
|
volume_before = convex_volume(ob)
|
||||||
|
|
||||||
|
make_convex_hull(ob)
|
||||||
|
|
||||||
|
volume_after = convex_volume(ob)
|
||||||
|
volume_delta = abs(volume_after - volume_before)
|
||||||
|
|
||||||
|
# If the volume of the piece is very small when we tried making it convex,
|
||||||
|
# then it's degenerate -- it's a plane or something flat that we need to
|
||||||
|
# remove.
|
||||||
|
is_degenerate = (volume_after < min_volume)
|
||||||
|
|
||||||
|
print(f" - Volume before: {volume_before}")
|
||||||
|
print(f" - Volume after: {volume_after}")
|
||||||
|
print(f" - Volume delta: {volume_delta}")
|
||||||
|
print(f" - Is degenerate: {is_degenerate}")
|
||||||
|
|
||||||
|
return not is_degenerate
|
||||||
|
|
||||||
|
|
||||||
|
def make_convex_hull(ob):
|
||||||
|
deselect_all_objects()
|
||||||
|
|
||||||
|
bpy.context.view_layer.objects.active = ob
|
||||||
|
ob.select_set(True)
|
||||||
|
|
||||||
|
bpy.ops.object.mode_set(mode='EDIT')
|
||||||
|
|
||||||
|
bpy.ops.mesh.select_all(action='SELECT')
|
||||||
|
bpy.ops.mesh.convex_hull()
|
||||||
|
|
||||||
|
mesh = ob.data
|
||||||
|
bm = bmesh.from_edit_mesh(mesh)
|
||||||
|
|
||||||
|
# Clean-up unnecessary edges
|
||||||
|
bmesh.ops.dissolve_limit(
|
||||||
|
bm,
|
||||||
|
angle_limit=radians(5),
|
||||||
|
verts=bm.verts,
|
||||||
|
edges=bm.edges,
|
||||||
|
)
|
||||||
|
|
||||||
|
bpy.ops.object.mode_set(mode='OBJECT')
|
||||||
|
bpy.ops.object.select_all(action='DESELECT')
|
||||||
|
|
||||||
|
|
||||||
|
def have_common_normal(e1, e2):
|
||||||
|
e1_normals = map(lambda f: f.normal, e1.link_faces)
|
||||||
|
e2_normals = map(lambda f: f.normal, e2.link_faces)
|
||||||
|
|
||||||
|
common_normals = [n for n in e1_normals if n in e2_normals]
|
||||||
|
|
||||||
|
return len(common_normals) > 0
|
||||||
|
|
||||||
|
|
||||||
|
def have_common_face(e1, e2):
|
||||||
|
common_faces = [f for f in e1.link_faces if f in e2.link_faces]
|
||||||
|
|
||||||
|
return len(common_faces) > 0
|
||||||
|
|
||||||
|
|
||||||
|
def convex_volume(*obs):
|
||||||
|
meshes = []
|
||||||
|
verts = []
|
||||||
|
|
||||||
|
for ob in obs:
|
||||||
|
mesh = ob.data
|
||||||
|
bm = bmesh.new()
|
||||||
|
|
||||||
|
bm.from_mesh(mesh)
|
||||||
|
|
||||||
|
bm.verts.ensure_lookup_table()
|
||||||
|
bm.edges.ensure_lookup_table()
|
||||||
|
bm.faces.ensure_lookup_table()
|
||||||
|
|
||||||
|
# Prevent early garbage collection.
|
||||||
|
meshes.append(bm)
|
||||||
|
|
||||||
|
geom = list(bm.verts) + list(bm.edges) + list(bm.faces)
|
||||||
|
|
||||||
|
for g in geom:
|
||||||
|
if hasattr(g, "verts"):
|
||||||
|
verts.extend(v.co for v in g.verts)
|
||||||
|
else:
|
||||||
|
verts.append(g.co)
|
||||||
|
|
||||||
|
return build_volume_from_verts(verts)
|
||||||
|
|
||||||
|
|
||||||
|
def build_volume_from_verts(verts):
|
||||||
|
# Based on code from:
|
||||||
|
# https://blender.stackexchange.com/questions/107357/how-to-find-if-geometry-linked-to-an-edge-is-coplanar
|
||||||
|
origin = sum(verts, Vector((0, 0, 0))) / len(verts)
|
||||||
|
bm = bmesh.new()
|
||||||
|
|
||||||
|
for v in verts:
|
||||||
|
bm.verts.new(v - origin)
|
||||||
|
|
||||||
|
bmesh.ops.convex_hull(bm, input=bm.verts)
|
||||||
|
|
||||||
|
return bm.calc_volume()
|
||||||
|
|
||||||
|
|
||||||
|
def deselect_all_objects():
|
||||||
|
try:
|
||||||
|
bpy.ops.object.mode_set(mode='OBJECT')
|
||||||
|
bpy.ops.object.select_all(action='DESELECT')
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def rename_pieces(object_name, name_skiplist=None):
|
||||||
|
if name_skiplist is None:
|
||||||
|
name_skiplist = []
|
||||||
|
|
||||||
|
for duplicate_name, old_index_str, new_index in dupe_name_sequence(object_name, name_skiplist):
|
||||||
|
piece = bpy.data.objects.get(duplicate_name)
|
||||||
|
|
||||||
|
if not piece:
|
||||||
|
break
|
||||||
|
|
||||||
|
old_name = piece.name
|
||||||
|
new_name = re.sub(fr"(?:01)?\.{old_index_str}$", f"{new_index:02d}", piece.name)
|
||||||
|
|
||||||
|
if old_name != new_name:
|
||||||
|
print(f"Renaming piece '{old_name}' to '{new_name}'.")
|
||||||
|
piece.name = new_name
|
||||||
|
|
||||||
|
|
||||||
|
def name_duplicates_of(ob):
|
||||||
|
duplicates = []
|
||||||
|
|
||||||
|
for duplicate_name, _, _ in dupe_name_sequence(ob.name):
|
||||||
|
piece = bpy.data.objects.get(duplicate_name)
|
||||||
|
|
||||||
|
if not piece:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
duplicates.append(piece)
|
||||||
|
|
||||||
|
return duplicates
|
||||||
|
|
||||||
|
|
||||||
|
def dupe_name_sequence(base_name, skiplist=None):
|
||||||
|
if skiplist is None:
|
||||||
|
skiplist = []
|
||||||
|
|
||||||
|
yield base_name, "", 1
|
||||||
|
|
||||||
|
new_index = 1
|
||||||
|
|
||||||
|
for old_name_index in count(start=1):
|
||||||
|
old_index_str = f"{old_name_index:03d}"
|
||||||
|
duplicate_name = f"{base_name}.{old_index_str}"
|
||||||
|
|
||||||
|
if duplicate_name in skiplist:
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
new_index = new_index + 1
|
||||||
|
|
||||||
|
yield duplicate_name, old_index_str, new_index
|
||||||
|
|
||||||
|
|
||||||
|
split_into_convex_pieces(bpy.context.view_layer.objects.active)
|
||||||
|
print("Done!")
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
AssetSources/SFX/Sci-Fi Horror Music Pack Vol. 2/Sci-Fi Horror Music Pack Vol. 2/It Escaped (RT 9.006)/SciFiHorror Vol2 It Escaped Intensity 1.wav (Stored with Git LFS)
Normal file
BIN
AssetSources/SFX/Sci-Fi Horror Music Pack Vol. 2/Sci-Fi Horror Music Pack Vol. 2/It Escaped (RT 9.006)/SciFiHorror Vol2 It Escaped Intensity 1.wav (Stored with Git LFS)
Normal file
Binary file not shown.
BIN
AssetSources/SFX/Sci-Fi Horror Music Pack Vol. 2/Sci-Fi Horror Music Pack Vol. 2/It Escaped (RT 9.006)/SciFiHorror Vol2 It Escaped Intensity 2.wav (Stored with Git LFS)
Normal file
BIN
AssetSources/SFX/Sci-Fi Horror Music Pack Vol. 2/Sci-Fi Horror Music Pack Vol. 2/It Escaped (RT 9.006)/SciFiHorror Vol2 It Escaped Intensity 2.wav (Stored with Git LFS)
Normal file
Binary file not shown.
BIN
AssetSources/SFX/Sci-Fi Horror Music Pack Vol. 2/Sci-Fi Horror Music Pack Vol. 2/It Escaped (RT 9.006)/SciFiHorror Vol2 It Escaped Main.wav (Stored with Git LFS)
Normal file
BIN
AssetSources/SFX/Sci-Fi Horror Music Pack Vol. 2/Sci-Fi Horror Music Pack Vol. 2/It Escaped (RT 9.006)/SciFiHorror Vol2 It Escaped Main.wav (Stored with Git LFS)
Normal file
Binary file not shown.
BIN
AssetSources/SFX/Sci-Fi Horror Music Pack Vol. 2/Sci-Fi Horror Music Pack Vol. 2/New Planet (RT 9.007)/SciFiHorror Vol2 New Planet Intensity 1.wav (Stored with Git LFS)
Normal file
BIN
AssetSources/SFX/Sci-Fi Horror Music Pack Vol. 2/Sci-Fi Horror Music Pack Vol. 2/New Planet (RT 9.007)/SciFiHorror Vol2 New Planet Intensity 1.wav (Stored with Git LFS)
Normal file
Binary file not shown.
BIN
AssetSources/SFX/Sci-Fi Horror Music Pack Vol. 2/Sci-Fi Horror Music Pack Vol. 2/New Planet (RT 9.007)/SciFiHorror Vol2 New Planet Intensity 2.wav (Stored with Git LFS)
Normal file
BIN
AssetSources/SFX/Sci-Fi Horror Music Pack Vol. 2/Sci-Fi Horror Music Pack Vol. 2/New Planet (RT 9.007)/SciFiHorror Vol2 New Planet Intensity 2.wav (Stored with Git LFS)
Normal file
Binary file not shown.
BIN
AssetSources/SFX/Sci-Fi Horror Music Pack Vol. 2/Sci-Fi Horror Music Pack Vol. 2/New Planet (RT 9.007)/SciFiHorror Vol2 New Planet Main.wav (Stored with Git LFS)
Normal file
BIN
AssetSources/SFX/Sci-Fi Horror Music Pack Vol. 2/Sci-Fi Horror Music Pack Vol. 2/New Planet (RT 9.007)/SciFiHorror Vol2 New Planet Main.wav (Stored with Git LFS)
Normal file
Binary file not shown.
BIN
AssetSources/SFX/Sci-Fi Horror Music Pack Vol. 2/Sci-Fi Horror Music Pack Vol. 2/Pressure (RT 15.007)/SciFiHorror Vol2 Pressure Intensity 1.wav (Stored with Git LFS)
Normal file
BIN
AssetSources/SFX/Sci-Fi Horror Music Pack Vol. 2/Sci-Fi Horror Music Pack Vol. 2/Pressure (RT 15.007)/SciFiHorror Vol2 Pressure Intensity 1.wav (Stored with Git LFS)
Normal file
Binary file not shown.
BIN
AssetSources/SFX/Sci-Fi Horror Music Pack Vol. 2/Sci-Fi Horror Music Pack Vol. 2/Pressure (RT 15.007)/SciFiHorror Vol2 Pressure Intensity 2.wav (Stored with Git LFS)
Normal file
BIN
AssetSources/SFX/Sci-Fi Horror Music Pack Vol. 2/Sci-Fi Horror Music Pack Vol. 2/Pressure (RT 15.007)/SciFiHorror Vol2 Pressure Intensity 2.wav (Stored with Git LFS)
Normal file
Binary file not shown.
BIN
AssetSources/SFX/Sci-Fi Horror Music Pack Vol. 2/Sci-Fi Horror Music Pack Vol. 2/Pressure (RT 15.007)/SciFiHorror Vol2 Pressure Main.wav (Stored with Git LFS)
Normal file
BIN
AssetSources/SFX/Sci-Fi Horror Music Pack Vol. 2/Sci-Fi Horror Music Pack Vol. 2/Pressure (RT 15.007)/SciFiHorror Vol2 Pressure Main.wav (Stored with Git LFS)
Normal file
Binary file not shown.
BIN
AssetSources/SFX/Sci-Fi Horror Music Pack Vol. 2/Sci-Fi Horror Music Pack Vol. 2/Ships Leaving (RT 6.217)/SciFiHorror Vol2 Ships Leaving Intensity 1.wav (Stored with Git LFS)
Normal file
BIN
AssetSources/SFX/Sci-Fi Horror Music Pack Vol. 2/Sci-Fi Horror Music Pack Vol. 2/Ships Leaving (RT 6.217)/SciFiHorror Vol2 Ships Leaving Intensity 1.wav (Stored with Git LFS)
Normal file
Binary file not shown.
BIN
AssetSources/SFX/Sci-Fi Horror Music Pack Vol. 2/Sci-Fi Horror Music Pack Vol. 2/Ships Leaving (RT 6.217)/SciFiHorror Vol2 Ships Leaving Intensity 2.wav (Stored with Git LFS)
Normal file
BIN
AssetSources/SFX/Sci-Fi Horror Music Pack Vol. 2/Sci-Fi Horror Music Pack Vol. 2/Ships Leaving (RT 6.217)/SciFiHorror Vol2 Ships Leaving Intensity 2.wav (Stored with Git LFS)
Normal file
Binary file not shown.
BIN
AssetSources/SFX/Sci-Fi Horror Music Pack Vol. 2/Sci-Fi Horror Music Pack Vol. 2/Ships Leaving (RT 6.217)/SciFiHorror Vol2 Ships Leaving Main.wav (Stored with Git LFS)
Normal file
BIN
AssetSources/SFX/Sci-Fi Horror Music Pack Vol. 2/Sci-Fi Horror Music Pack Vol. 2/Ships Leaving (RT 6.217)/SciFiHorror Vol2 Ships Leaving Main.wav (Stored with Git LFS)
Normal file
Binary file not shown.
BIN
AssetSources/SFX/Sci-Fi Horror Music Pack Vol. 2/Sci-Fi Horror Music Pack Vol. 2/Stranded (RT 5.04)/SciFiHorror Vol2 Stranded Intensity 1.wav (Stored with Git LFS)
Normal file
BIN
AssetSources/SFX/Sci-Fi Horror Music Pack Vol. 2/Sci-Fi Horror Music Pack Vol. 2/Stranded (RT 5.04)/SciFiHorror Vol2 Stranded Intensity 1.wav (Stored with Git LFS)
Normal file
Binary file not shown.
BIN
AssetSources/SFX/Sci-Fi Horror Music Pack Vol. 2/Sci-Fi Horror Music Pack Vol. 2/Stranded (RT 5.04)/SciFiHorror Vol2 Stranded Intensity 2.wav (Stored with Git LFS)
Normal file
BIN
AssetSources/SFX/Sci-Fi Horror Music Pack Vol. 2/Sci-Fi Horror Music Pack Vol. 2/Stranded (RT 5.04)/SciFiHorror Vol2 Stranded Intensity 2.wav (Stored with Git LFS)
Normal file
Binary file not shown.
BIN
AssetSources/SFX/Sci-Fi Horror Music Pack Vol. 2/Sci-Fi Horror Music Pack Vol. 2/Stranded (RT 5.04)/SciFiHorror Vol2 Stranded Main.wav (Stored with Git LFS)
Normal file
BIN
AssetSources/SFX/Sci-Fi Horror Music Pack Vol. 2/Sci-Fi Horror Music Pack Vol. 2/Stranded (RT 5.04)/SciFiHorror Vol2 Stranded Main.wav (Stored with Git LFS)
Normal file
Binary file not shown.
BIN
AssetSources/SFX/UI & Menus Sound FX Pack Vol. 4/UI & Menus Sound FX Pack Vol. 4/Miscellaneous/Back/Misc Back Glitch 002.wav (Stored with Git LFS)
Normal file
BIN
AssetSources/SFX/UI & Menus Sound FX Pack Vol. 4/UI & Menus Sound FX Pack Vol. 4/Miscellaneous/Back/Misc Back Glitch 002.wav (Stored with Git LFS)
Normal file
Binary file not shown.
BIN
AssetSources/SFX/UI & Menus Sound FX Pack Vol. 4/UI & Menus Sound FX Pack Vol. 4/Miscellaneous/Back/Misc Back Glitch 005.wav (Stored with Git LFS)
Normal file
BIN
AssetSources/SFX/UI & Menus Sound FX Pack Vol. 4/UI & Menus Sound FX Pack Vol. 4/Miscellaneous/Back/Misc Back Glitch 005.wav (Stored with Git LFS)
Normal file
Binary file not shown.
BIN
AssetSources/SFX/UI & Menus Sound FX Pack Vol. 4/UI & Menus Sound FX Pack Vol. 4/Miscellaneous/Popup/Misc Popup Glitch 002.wav (Stored with Git LFS)
Normal file
BIN
AssetSources/SFX/UI & Menus Sound FX Pack Vol. 4/UI & Menus Sound FX Pack Vol. 4/Miscellaneous/Popup/Misc Popup Glitch 002.wav (Stored with Git LFS)
Normal file
Binary file not shown.
BIN
AssetSources/SFX/UI & Menus Sound FX Pack Vol. 4/UI & Menus Sound FX Pack Vol. 4/Miscellaneous/Popup/Misc Popup Glitch 003.wav (Stored with Git LFS)
Normal file
BIN
AssetSources/SFX/UI & Menus Sound FX Pack Vol. 4/UI & Menus Sound FX Pack Vol. 4/Miscellaneous/Popup/Misc Popup Glitch 003.wav (Stored with Git LFS)
Normal file
Binary file not shown.
BIN
AssetSources/SFX/UI & Menus Sound FX Pack Vol. 4/UI & Menus Sound FX Pack Vol. 4/Miscellaneous/Popup/Misc Popup Glitch 004.wav (Stored with Git LFS)
Normal file
BIN
AssetSources/SFX/UI & Menus Sound FX Pack Vol. 4/UI & Menus Sound FX Pack Vol. 4/Miscellaneous/Popup/Misc Popup Glitch 004.wav (Stored with Git LFS)
Normal file
Binary file not shown.
BIN
AssetSources/SFX/UI & Menus Sound FX Pack Vol. 4/UI & Menus Sound FX Pack Vol. 4/Miscellaneous/Popup/Misc Popup Glitch 005.wav (Stored with Git LFS)
Normal file
BIN
AssetSources/SFX/UI & Menus Sound FX Pack Vol. 4/UI & Menus Sound FX Pack Vol. 4/Miscellaneous/Popup/Misc Popup Glitch 005.wav (Stored with Git LFS)
Normal file
Binary file not shown.
BIN
AssetSources/SFX/UI & Menus Sound FX Pack Vol. 4/UI & Menus Sound FX Pack Vol. 4/Miscellaneous/Popup/Misc Popup Glitch 007.wav (Stored with Git LFS)
Normal file
BIN
AssetSources/SFX/UI & Menus Sound FX Pack Vol. 4/UI & Menus Sound FX Pack Vol. 4/Miscellaneous/Popup/Misc Popup Glitch 007.wav (Stored with Git LFS)
Normal file
Binary file not shown.
BIN
AssetSources/SFX/UI & Menus Sound FX Pack Vol. 4/UI & Menus Sound FX Pack Vol. 4/Miscellaneous/Toggle/Misc Toggle Glitch 003.wav (Stored with Git LFS)
Normal file
BIN
AssetSources/SFX/UI & Menus Sound FX Pack Vol. 4/UI & Menus Sound FX Pack Vol. 4/Miscellaneous/Toggle/Misc Toggle Glitch 003.wav (Stored with Git LFS)
Normal file
Binary file not shown.
BIN
AssetSources/SFX/UI & Menus Sound FX Pack Vol. 4/UI & Menus Sound FX Pack Vol. 4/Mouse/Hover/Hover Glitch 001.wav (Stored with Git LFS)
Normal file
BIN
AssetSources/SFX/UI & Menus Sound FX Pack Vol. 4/UI & Menus Sound FX Pack Vol. 4/Mouse/Hover/Hover Glitch 001.wav (Stored with Git LFS)
Normal file
Binary file not shown.
BIN
AssetSources/SFX/UI & Menus Sound FX Pack Vol. 4/UI & Menus Sound FX Pack Vol. 4/Mouse/Hover/Hover Glitch 002.wav (Stored with Git LFS)
Normal file
BIN
AssetSources/SFX/UI & Menus Sound FX Pack Vol. 4/UI & Menus Sound FX Pack Vol. 4/Mouse/Hover/Hover Glitch 002.wav (Stored with Git LFS)
Normal file
Binary file not shown.
BIN
AssetSources/SFX/UI & Menus Sound FX Pack Vol. 4/UI & Menus Sound FX Pack Vol. 4/Mouse/Hover/Hover Glitch 003.wav (Stored with Git LFS)
Normal file
BIN
AssetSources/SFX/UI & Menus Sound FX Pack Vol. 4/UI & Menus Sound FX Pack Vol. 4/Mouse/Hover/Hover Glitch 003.wav (Stored with Git LFS)
Normal file
Binary file not shown.
BIN
AssetSources/SFX/UI & Menus Sound FX Pack Vol. 4/UI & Menus Sound FX Pack Vol. 4/Signals/Positive/Signals Positive Foley 001.wav (Stored with Git LFS)
Normal file
BIN
AssetSources/SFX/UI & Menus Sound FX Pack Vol. 4/UI & Menus Sound FX Pack Vol. 4/Signals/Positive/Signals Positive Foley 001.wav (Stored with Git LFS)
Normal file
Binary file not shown.
BIN
AssetSources/SFX/UI & Menus Sound FX Pack Vol. 4/UI & Menus Sound FX Pack Vol. 4/Signals/Positive/Signals Positive Glitch 003.wav (Stored with Git LFS)
Normal file
BIN
AssetSources/SFX/UI & Menus Sound FX Pack Vol. 4/UI & Menus Sound FX Pack Vol. 4/Signals/Positive/Signals Positive Glitch 003.wav (Stored with Git LFS)
Normal file
Binary file not shown.
BIN
AssetSources/SFX/UI & Menus Sound FX Pack Vol. 4/UI & Menus Sound FX Pack Vol. 4/Signals/Positive/Signals Positive Glitch 004.wav (Stored with Git LFS)
Normal file
BIN
AssetSources/SFX/UI & Menus Sound FX Pack Vol. 4/UI & Menus Sound FX Pack Vol. 4/Signals/Positive/Signals Positive Glitch 004.wav (Stored with Git LFS)
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
|
@ -1,6 +1,6 @@
|
||||||
[/Script/EngineSettings.GameMapsSettings]
|
[/Script/EngineSettings.GameMapsSettings]
|
||||||
GameDefaultMap=/Game/Maps/LVL_GravityPlanet_XXL.LVL_GravityPlanet_XXL
|
GameDefaultMap=/Game/Maps/LVL_HomeScreenMenu.LVL_HomeScreenMenu
|
||||||
EditorStartupMap=/Game/Maps/LVL_GravityTestWorld.LVL_GravityTestWorld
|
EditorStartupMap=None
|
||||||
GlobalDefaultGameMode=/Game/PawnControl/Player/BP_Gamemode_Gravity.BP_Gamemode_Gravity_C
|
GlobalDefaultGameMode=/Game/PawnControl/Player/BP_Gamemode_Gravity.BP_Gamemode_Gravity_C
|
||||||
|
|
||||||
[/Script/Engine.RendererSettings]
|
[/Script/Engine.RendererSettings]
|
||||||
|
@ -190,6 +190,9 @@ AppliedDefaultGraphicsPerformance=Scalable
|
||||||
+ActiveGameNameRedirects=(OldGameName="/Script/TP_ThirdPerson",NewGameName="/Script/GrapplingGravity")
|
+ActiveGameNameRedirects=(OldGameName="/Script/TP_ThirdPerson",NewGameName="/Script/GrapplingGravity")
|
||||||
+ActiveClassRedirects=(OldClassName="TP_ThirdPersonGameMode",NewClassName="GrapplingGravityGameMode")
|
+ActiveClassRedirects=(OldClassName="TP_ThirdPersonGameMode",NewClassName="GrapplingGravityGameMode")
|
||||||
+ActiveClassRedirects=(OldClassName="TP_ThirdPersonCharacter",NewClassName="GrapplingGravityCharacter")
|
+ActiveClassRedirects=(OldClassName="TP_ThirdPersonCharacter",NewClassName="GrapplingGravityCharacter")
|
||||||
|
bUseFixedFrameRate=False
|
||||||
|
FixedFrameRate=100.000000
|
||||||
|
SmoothedFrameRateRange=(LowerBound=(Type=Inclusive,Value=22.000000),UpperBound=(Type=Exclusive,Value=144.000000))
|
||||||
|
|
||||||
[/Script/AndroidFileServerEditor.AndroidFileServerRuntimeSettings]
|
[/Script/AndroidFileServerEditor.AndroidFileServerRuntimeSettings]
|
||||||
bEnablePlugin=True
|
bEnablePlugin=True
|
||||||
|
@ -212,11 +215,11 @@ ReverbPlugin=
|
||||||
OcclusionPlugin=
|
OcclusionPlugin=
|
||||||
SoundCueCookQualityIndex=-1
|
SoundCueCookQualityIndex=-1
|
||||||
-TargetedRHIs=SF_VULKAN_SM5
|
-TargetedRHIs=SF_VULKAN_SM5
|
||||||
+TargetedRHIs=SF_VULKAN_SM5
|
|
||||||
+TargetedRHIs=SF_VULKAN_SM6
|
+TargetedRHIs=SF_VULKAN_SM6
|
||||||
|
|
||||||
[/Script/Engine.PhysicsSettings]
|
[/Script/Engine.PhysicsSettings]
|
||||||
DefaultGravityZ=0.000000
|
DefaultGravityZ=0.000000
|
||||||
|
bTickPhysicsAsync=True
|
||||||
|
|
||||||
[/Script/Engine.CollisionProfile]
|
[/Script/Engine.CollisionProfile]
|
||||||
-Profiles=(Name="NoCollision",CollisionEnabled=NoCollision,ObjectTypeName="WorldStatic",CustomResponses=((Channel="Visibility",Response=ECR_Ignore),(Channel="Camera",Response=ECR_Ignore)),HelpMessage="No collision",bCanModify=False)
|
-Profiles=(Name="NoCollision",CollisionEnabled=NoCollision,ObjectTypeName="WorldStatic",CustomResponses=((Channel="Visibility",Response=ECR_Ignore),(Channel="Camera",Response=ECR_Ignore)),HelpMessage="No collision",bCanModify=False)
|
||||||
|
@ -256,6 +259,7 @@ DefaultGravityZ=0.000000
|
||||||
+Profiles=(Name="Vehicle",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="Vehicle",CustomResponses=,HelpMessage="Vehicle object that blocks Vehicle, WorldStatic, and WorldDynamic. All other channels will be set to default.")
|
+Profiles=(Name="Vehicle",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="Vehicle",CustomResponses=,HelpMessage="Vehicle object that blocks Vehicle, WorldStatic, and WorldDynamic. All other channels will be set to default.")
|
||||||
+Profiles=(Name="UI",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="WorldStatic",Response=ECR_Overlap),(Channel="Pawn",Response=ECR_Overlap),(Channel="Visibility"),(Channel="WorldDynamic",Response=ECR_Overlap),(Channel="Camera",Response=ECR_Overlap),(Channel="PhysicsBody",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Destructible",Response=ECR_Overlap)),HelpMessage="WorldStatic object that overlaps all actors by default. All new custom channels will use its own default response. ")
|
+Profiles=(Name="UI",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="WorldStatic",Response=ECR_Overlap),(Channel="Pawn",Response=ECR_Overlap),(Channel="Visibility"),(Channel="WorldDynamic",Response=ECR_Overlap),(Channel="Camera",Response=ECR_Overlap),(Channel="PhysicsBody",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Destructible",Response=ECR_Overlap)),HelpMessage="WorldStatic object that overlaps all actors by default. All new custom channels will use its own default response. ")
|
||||||
+DefaultChannelResponses=(Channel=ECC_GameTraceChannel1,DefaultResponse=ECR_Ignore,bTraceType=True,bStaticObject=False,Name="Grappable")
|
+DefaultChannelResponses=(Channel=ECC_GameTraceChannel1,DefaultResponse=ECR_Ignore,bTraceType=True,bStaticObject=False,Name="Grappable")
|
||||||
|
+EditProfiles=(Name="BlockAll",CustomResponses=((Channel="Grappable")))
|
||||||
-ProfileRedirects=(OldName="BlockingVolume",NewName="InvisibleWall")
|
-ProfileRedirects=(OldName="BlockingVolume",NewName="InvisibleWall")
|
||||||
-ProfileRedirects=(OldName="InterpActor",NewName="IgnoreOnlyPawn")
|
-ProfileRedirects=(OldName="InterpActor",NewName="IgnoreOnlyPawn")
|
||||||
-ProfileRedirects=(OldName="StaticMeshComponent",NewName="BlockAllDynamic")
|
-ProfileRedirects=(OldName="StaticMeshComponent",NewName="BlockAllDynamic")
|
||||||
|
|
Binary file not shown.
BIN
Content/Abilities/GrapplingHook/BP_GrapplingHook.uasset (Stored with Git LFS)
BIN
Content/Abilities/GrapplingHook/BP_GrapplingHook.uasset (Stored with Git LFS)
Binary file not shown.
BIN
Content/Abilities/Gravity/BP_GravityObject_Component.uasset (Stored with Git LFS)
BIN
Content/Abilities/Gravity/BP_GravityObject_Component.uasset (Stored with Git LFS)
Binary file not shown.
BIN
Content/Abilities/Gravity/BP_GravityObject_Component_Character.uasset (Stored with Git LFS)
BIN
Content/Abilities/Gravity/BP_GravityObject_Component_Character.uasset (Stored with Git LFS)
Binary file not shown.
BIN
Content/Abilities/Gravity/BP_GravityObject_Component_MoverCharacter.uasset (Stored with Git LFS)
Normal file
BIN
Content/Abilities/Gravity/BP_GravityObject_Component_MoverCharacter.uasset (Stored with Git LFS)
Normal file
Binary file not shown.
Binary file not shown.
BIN
Content/Abilities/Gravity/CRV_SpeedToGroundFrictionFactor.uasset (Stored with Git LFS)
Normal file
BIN
Content/Abilities/Gravity/CRV_SpeedToGroundFrictionFactor.uasset (Stored with Git LFS)
Normal file
Binary file not shown.
Binary file not shown.
BIN
Content/Abilities/Properties/BPC_ActorProperty_GCharges.uasset (Stored with Git LFS)
Normal file
BIN
Content/Abilities/Properties/BPC_ActorProperty_GCharges.uasset (Stored with Git LFS)
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue