Ambient block baking

This commit is contained in:
James Lambert 2023-06-13 07:48:53 -06:00
parent b22dd63100
commit b376316713

View file

@ -1,6 +1,7 @@
import bpy import bpy
import sys import sys
import operator import operator
import math
print("Blender export scene in FBX Format in file "+sys.argv[-1]) print("Blender export scene in FBX Format in file "+sys.argv[-1])
@ -22,6 +23,9 @@ def get_or_make_color_layer(mesh):
def vector_add(a, b): def vector_add(a, b):
return [a[0] + b[0], a[1] + b[1], a[2] + b[2]] return [a[0] + b[0], a[1] + b[1], a[2] + b[2]]
def vector_sub(a, b):
return [a[0] - b[0], a[1] - b[1], a[2] - b[2]]
def vector_min(a, b): def vector_min(a, b):
return [min(a[0], b[0]), min(a[1], b[1]), min(a[2], b[2])] return [min(a[0], b[0]), min(a[1], b[1]), min(a[2], b[2])]
@ -36,7 +40,42 @@ def vector_mul(a, b):
return [x * b for x in a] return [x * b for x in a]
return [a[0] * b[0], a[1] * b[1], a[2] * b[2]] return [a[0] * b[0], a[1] * b[1], a[2] * b[2]]
def vector_div(a, b):
if isinstance(a, float):
return [a / x for x in b]
if isinstance(b, float):
return [x / b for x in a]
return [a[0] / b[0], a[1] / b[1], a[2] / b[2]]
def vector_dot(a, b):
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]
def vector_lerp(a, b, t):
if isinstance(t, float):
t_inv = 1 - t
else:
t_inv = vector_sub([1, 1, 1], t)
t_inv = 1 - t
return vector_add(vector_mul(a, t_inv), vector_mul(b, t))
def vector_unlerp(a, b, pos):
return vector_div(vector_sub(pos, a), vector_sub(b, a))
def color_lerp(a, b, t):
t_inv = 1 - t
return [
a[0] * t_inv + b[0] * t,
a[1] * t_inv + b[1] * t,
a[2] * t_inv + b[2] * t,
a[3] * t_inv + b[3] * t
]
def calc_midpoint(vertices): def calc_midpoint(vertices):
result = [0, 0, 0] result = [0, 0, 0]
@ -62,6 +101,10 @@ def world_space_verts(obj):
return vertices, normals return vertices, normals
class BoundingBox:
def __init__(self, min, max):
self.min = min
self.max = max
class AmbientBlock: class AmbientBlock:
def __init__(self, obj): def __init__(self, obj):
@ -78,9 +121,9 @@ class AmbientBlock:
bb_min = vertices[0] bb_min = vertices[0]
bb_max = vertices[0] bb_max = vertices[0]
for index in range(len(vertices)): for loop in obj.data.loops:
corner_index = 0 corner_index = 0
vertex = vertices[index] vertex = vertices[loop.vertex_index]
bb_min = vector_min(bb_min, vertex) bb_min = vector_min(bb_min, vertex)
bb_max = vector_max(bb_max, vertex) bb_max = vector_max(bb_max, vertex)
@ -94,10 +137,32 @@ class AmbientBlock:
if vertex[2] > midpoint[2]: if vertex[2] > midpoint[2]:
corner_index = corner_index + 4 corner_index = corner_index + 4
corner_colors[corner_index] = colors.data[index].color corner_colors[corner_index] = colors.data[loop.index].color
self.corner_colors = corner_colors self.corner_colors = corner_colors
self.bb = [bb_min, bb_max] self.bb = BoundingBox(bb_min, bb_max)
def determine_distance(self, pos):
closest_point = vector_max(self.bb.min, vector_min(self.bb.max, pos))
diff = vector_sub(closest_point, pos)
distance_sqrd = vector_dot(diff, diff)
return math.sqrt(distance_sqrd)
def determine_color(self, pos):
lerp_values = vector_unlerp(self.bb.min, self.bb.max, pos)
lerp_values = vector_min(lerp_values, [1, 1, 1])
lerp_values = vector_max(lerp_values, [0, 0, 0])
x0 = color_lerp(self.corner_colors[0], self.corner_colors[1], lerp_values[0])
x1 = color_lerp(self.corner_colors[2], self.corner_colors[3], lerp_values[0])
x2 = color_lerp(self.corner_colors[4], self.corner_colors[5], lerp_values[0])
x3 = color_lerp(self.corner_colors[6], self.corner_colors[7], lerp_values[0])
y0 = color_lerp(x0, x1, lerp_values[1])
y1 = color_lerp(x2, x3, lerp_values[1])
return color_lerp(y0, y1, lerp_values[2])
ambient_blocks = [] ambient_blocks = []
@ -106,8 +171,59 @@ for obj in bpy.data.objects:
if obj.name.startswith('@ambient '): if obj.name.startswith('@ambient '):
ambient_blocks.append(AmbientBlock(obj)) ambient_blocks.append(AmbientBlock(obj))
def min_indices(elements, count):
result = []
for index in range(len(elements)):
insert_index = len(result)
curr_value = elements[index]
while insert_index > 0 and elements[insert_index - 1] < curr_value:
insert_index = insert_index - 1
if insert_index < count:
result.insert(insert_index, index)
if len(result) > count:
result.pop()
return result
def determine_ambient_color(pos):
distances = [block.determine_distance(pos) for block in ambient_blocks]
two_closest = min_indices(distances, 2)
if len(two_closest) == 0:
return [1, 1, 1, 1]
if len(two_closest) == 1:
return ambient_blocks[two_closest[0]].determine_color(pos)
total_weight = distances[two_closest[0]] + distances[two_closest[1]]
if total_weight == 0:
return ambient_blocks[two_closest[0]].determine_color(pos)
return color_lerp(
ambient_blocks[two_closest[0]].determine_color(pos),
ambient_blocks[two_closest[1]].determine_color(pos),
distances[two_closest[0]] / total_weight
)
def bake_object(obj):
color_layer = get_or_make_color_layer(obj.data)
vertices, normals = world_space_verts(obj)
for loop in obj.data.loops:
vertex_index = loop.vertex_index
color_layer.data[loop.index].color = determine_ambient_color(vertices[vertex_index])
print("Found ambient_blocks count: " + str(len(ambient_blocks))) print("Found ambient_blocks count: " + str(len(ambient_blocks)))
for obj in bpy.data.objects: for obj in bpy.data.objects:
if should_bake_object(obj): if should_bake_object(obj):
get_or_make_color_layer(obj.data) bake_object(obj)