PsychoBlend: implement object and material export.
Material bindings don't work, since they're now on the objects themselves rather than the instances, and I haven't updated Psychopath itself for that yet.
This commit is contained in:
parent
d132e6a015
commit
1c801ee605
|
@ -1,6 +1,7 @@
|
||||||
import bpy
|
import bpy
|
||||||
|
|
||||||
from .util import escape_name, mat2str, needs_def_mb, needs_xform_mb, ExportCancelled
|
from .util import escape_name, mat2str, needs_def_mb, needs_xform_mb, ExportCancelled
|
||||||
|
from mathutils import Vector, Matrix
|
||||||
|
|
||||||
def make_object_data_cache(render_engine, depsgraph, ob, name):
|
def make_object_data_cache(render_engine, depsgraph, ob, name):
|
||||||
if ob.type == 'MESH':
|
if ob.type == 'MESH':
|
||||||
|
@ -18,6 +19,9 @@ class Mesh:
|
||||||
"""
|
"""
|
||||||
def __init__(self, render_engine, depsgraph, ob, name):
|
def __init__(self, render_engine, depsgraph, ob, name):
|
||||||
self.name = name
|
self.name = name
|
||||||
|
self.material_name = None
|
||||||
|
if len(ob.material_slots) >= 1 and ob.material_slots[0].material != None:
|
||||||
|
self.material_name = ob.material_slots[0].material.name
|
||||||
self.is_subdiv = ob.data.psychopath.is_subdivision_surface
|
self.is_subdiv = ob.data.psychopath.is_subdivision_surface
|
||||||
self.needs_mb = needs_def_mb(ob)
|
self.needs_mb = needs_def_mb(ob)
|
||||||
self.time_meshes = []
|
self.time_meshes = []
|
||||||
|
@ -43,6 +47,10 @@ class Mesh:
|
||||||
w.write("SubdivisionSurface $%s {\n" % self.name)
|
w.write("SubdivisionSurface $%s {\n" % self.name)
|
||||||
w.indent()
|
w.indent()
|
||||||
|
|
||||||
|
# Material bindings.
|
||||||
|
if self.material_name != None:
|
||||||
|
w.write("SurfaceShaderBind [${}]\n".format(self.material_name))
|
||||||
|
|
||||||
# Write vertices and (if it's smooth shaded) normals
|
# Write vertices and (if it's smooth shaded) normals
|
||||||
for ti in range(len(self.time_meshes)):
|
for ti in range(len(self.time_meshes)):
|
||||||
w.write("Vertices [")
|
w.write("Vertices [")
|
||||||
|
@ -132,12 +140,12 @@ class RectLamp:
|
||||||
self.time_dim += [(ob.data.size, ob.data.size_y)]
|
self.time_dim += [(ob.data.size, ob.data.size_y)]
|
||||||
else:
|
else:
|
||||||
self.time_dim += [(ob.data.size, ob.data.size)]
|
self.time_dim += [(ob.data.size, ob.data.size)]
|
||||||
|
|
||||||
def cleanup(self):
|
def cleanup(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def export(self, render_engine, w):
|
def export(self, render_engine, w):
|
||||||
render_engine.update_stats("", "Psychopath: Exporting %s" % self.ob.name)
|
render_engine.update_stats("", "Psychopath: Exporting %s" % self.name)
|
||||||
|
|
||||||
w.write("RectangleLight $%s {\n" % self.name)
|
w.write("RectangleLight $%s {\n" % self.name)
|
||||||
w.indent()
|
w.indent()
|
||||||
|
@ -175,8 +183,11 @@ class DistantDiskLamp:
|
||||||
|
|
||||||
self.time_rad += [ob.data.shadow_soft_size]
|
self.time_rad += [ob.data.shadow_soft_size]
|
||||||
|
|
||||||
|
def cleanup(self):
|
||||||
|
pass
|
||||||
|
|
||||||
def export(self, render_engine, w):
|
def export(self, render_engine, w):
|
||||||
render_engine.update_stats("", "Psychopath: Exporting %s" % self.ob.name)
|
render_engine.update_stats("", "Psychopath: Exporting %s" % self.name)
|
||||||
w.write("DistantDiskLight $%s {\n" % self.name)
|
w.write("DistantDiskLight $%s {\n" % self.name)
|
||||||
w.indent()
|
w.indent()
|
||||||
for direc in self.time_dir:
|
for direc in self.time_dir:
|
||||||
|
@ -197,7 +208,6 @@ class DistantDiskLamp:
|
||||||
|
|
||||||
# class Instance:
|
# class Instance:
|
||||||
# def __init__(self, render_engine, depsgraph, ob, data_name):
|
# def __init__(self, render_engine, depsgraph, ob, data_name):
|
||||||
# self.ob = ob
|
|
||||||
# self.data_name = data_name
|
# self.data_name = data_name
|
||||||
# self.needs_mb = needs_xform_mb(self.ob)
|
# self.needs_mb = needs_xform_mb(self.ob)
|
||||||
# self.time_xforms = []
|
# self.time_xforms = []
|
||||||
|
|
|
@ -2,6 +2,7 @@ import bpy
|
||||||
|
|
||||||
from math import log
|
from math import log
|
||||||
|
|
||||||
|
from .material import Material
|
||||||
from .objects import make_object_data_cache, Mesh, DistantDiskLamp
|
from .objects import make_object_data_cache, Mesh, DistantDiskLamp
|
||||||
from .util import escape_name, mat2str, ExportCancelled
|
from .util import escape_name, mat2str, ExportCancelled
|
||||||
from .world import World, Camera
|
from .world import World, Camera
|
||||||
|
@ -53,6 +54,9 @@ class PsychoExporter:
|
||||||
self.sun_lamp_data = {} # name -> cached_data
|
self.sun_lamp_data = {} # name -> cached_data
|
||||||
self.sun_lamp_instances = {} # instance_id -> [sun_lamp_data_name, transform_list]
|
self.sun_lamp_instances = {} # instance_id -> [sun_lamp_data_name, transform_list]
|
||||||
|
|
||||||
|
# For all materials.
|
||||||
|
self.materials = {} # name -> cached_data
|
||||||
|
|
||||||
# Motion blur segments are rounded down to a power of two.
|
# Motion blur segments are rounded down to a power of two.
|
||||||
if self.scene.psychopath.motion_blur_segments > 0:
|
if self.scene.psychopath.motion_blur_segments > 0:
|
||||||
self.time_samples = (2**int(log(self.scene.psychopath.motion_blur_segments, 2))) + 1
|
self.time_samples = (2**int(log(self.scene.psychopath.motion_blur_segments, 2))) + 1
|
||||||
|
@ -124,6 +128,21 @@ class PsychoExporter:
|
||||||
self.w.unindent()
|
self.w.unindent()
|
||||||
self.w.write("}\n")
|
self.w.write("}\n")
|
||||||
|
|
||||||
|
#------------------------------------------------------
|
||||||
|
# Collect materials.
|
||||||
|
|
||||||
|
# TODO: handle situations where there are more than one
|
||||||
|
# material with the same name. This can happen through
|
||||||
|
# library linking.
|
||||||
|
|
||||||
|
for inst in self.depsgraph.object_instances:
|
||||||
|
ob = inst.object
|
||||||
|
if ob.type in ['MESH']:
|
||||||
|
for ms in ob.material_slots:
|
||||||
|
if ms.material != None:
|
||||||
|
if ms.material.name not in self.materials:
|
||||||
|
self.materials[ms.material.name] = Material(self.render_engine, self.depsgraph, ms.material)
|
||||||
|
|
||||||
#------------------------------------------------------
|
#------------------------------------------------------
|
||||||
# Collect world and object data.
|
# Collect world and object data.
|
||||||
|
|
||||||
|
@ -133,7 +152,10 @@ class PsychoExporter:
|
||||||
if self.render_engine.test_break():
|
if self.render_engine.test_break():
|
||||||
raise ExportCancelled()
|
raise ExportCancelled()
|
||||||
|
|
||||||
time = self.fr + self.shutter_start + (self.shutter_diff*i)
|
subframe = self.shutter_start + (self.shutter_diff*i)
|
||||||
|
time = self.fr + subframe
|
||||||
|
self.depsgraph.scene.frame_set(self.fr, subframe=subframe)
|
||||||
|
self.depsgraph.update()
|
||||||
|
|
||||||
# Collect camera and world data.
|
# Collect camera and world data.
|
||||||
self.camera.take_sample(self.render_engine, self.depsgraph, time)
|
self.camera.take_sample(self.render_engine, self.depsgraph, time)
|
||||||
|
@ -152,13 +174,22 @@ class PsychoExporter:
|
||||||
# We use this a couple of times, so make a shorthand.
|
# We use this a couple of times, so make a shorthand.
|
||||||
is_sun_lamp = inst.object.type == 'LIGHT' and inst.object.data.type == 'SUN'
|
is_sun_lamp = inst.object.type == 'LIGHT' and inst.object.data.type == 'SUN'
|
||||||
|
|
||||||
|
# TODO: handle situations where there are more than one
|
||||||
|
# object with the same name. This can happen through
|
||||||
|
# library linking.
|
||||||
|
|
||||||
# Get a unique id for the instance. This is surprisingly
|
# Get a unique id for the instance. This is surprisingly
|
||||||
# tricky, because the instance's "persistent_id" property
|
# tricky, because the instance's "persistent_id" property
|
||||||
# isn't globally unique, as I would have expected from
|
# isn't globally unique, as I would have expected from
|
||||||
# the documentation.
|
# the documentation.
|
||||||
id = None
|
id = None
|
||||||
if inst.is_instance:
|
if inst.is_instance:
|
||||||
id = (hash((inst.object.name, inst.parent.name)), inst.persistent_id)
|
id = (
|
||||||
|
hash((inst.object.name, inst.parent.name)),
|
||||||
|
# Has to be turned into a tuple, otherwise it doesn't
|
||||||
|
# work as part of the ID for some reason.
|
||||||
|
tuple(inst.persistent_id),
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
id = inst.object.name
|
id = inst.object.name
|
||||||
|
|
||||||
|
@ -195,6 +226,30 @@ class PsychoExporter:
|
||||||
self.w.write("Assembly {\n")
|
self.w.write("Assembly {\n")
|
||||||
self.w.indent()
|
self.w.indent()
|
||||||
|
|
||||||
|
# Export materials.
|
||||||
|
for name in self.materials:
|
||||||
|
self.materials[name].export(self.render_engine, self.w)
|
||||||
|
|
||||||
|
# Export objects.
|
||||||
|
for name in self.object_data:
|
||||||
|
self.object_data[name].export(self.render_engine, self.w)
|
||||||
|
|
||||||
|
# Export instances.
|
||||||
|
for id in self.instances:
|
||||||
|
[obj_name, xforms] = self.instances[id]
|
||||||
|
self.render_engine.update_stats("", "Psychopath: Exporting %s instance" % obj_name)
|
||||||
|
|
||||||
|
prefix = str(hex(hash(id)))
|
||||||
|
name = "inst_{}__{}".format(prefix, obj_name)
|
||||||
|
|
||||||
|
self.w.write("Instance {\n")
|
||||||
|
self.w.indent()
|
||||||
|
self.w.write("Data [${}]\n".format(obj_name))
|
||||||
|
for mat in xforms:
|
||||||
|
self.w.write("Transform [{}]\n".format(mat2str(mat)))
|
||||||
|
self.w.unindent()
|
||||||
|
self.w.write("}\n")
|
||||||
|
|
||||||
self.w.unindent()
|
self.w.unindent()
|
||||||
self.w.write("}\n")
|
self.w.write("}\n")
|
||||||
finally:
|
finally:
|
||||||
|
|
|
@ -65,7 +65,7 @@ class Camera:
|
||||||
mat = self.ob.matrix_world.copy()
|
mat = self.ob.matrix_world.copy()
|
||||||
matz = Matrix()
|
matz = Matrix()
|
||||||
matz[2][2] = -1
|
matz[2][2] = -1
|
||||||
self.xforms += [(mat * matz).inverted()]
|
self.xforms += [(mat @ matz).inverted()]
|
||||||
|
|
||||||
def cleanup(self):
|
def cleanup(self):
|
||||||
pass
|
pass
|
||||||
|
|
Loading…
Reference in New Issue
Block a user