Continue WIP update PsychoBlend for Blender 3.x.
It exports and renders successfully... except there are no objects. Just a blank background.
This commit is contained in:
parent
6d7b8b280f
commit
69ace90689
|
@ -1,6 +1,6 @@
|
|||
bl_info = {
|
||||
"name": "PsychoBlend",
|
||||
"version": (0, 1),
|
||||
"version": (0, 1, 0),
|
||||
"author": "Nathan Vegdahl",
|
||||
"blender": (3, 1, 0),
|
||||
"description": "Psychopath renderer integration",
|
||||
|
|
|
@ -1,398 +0,0 @@
|
|||
import bpy
|
||||
|
||||
from .util import escape_name, mat2str, needs_def_mb, needs_xform_mb, ExportCancelled
|
||||
|
||||
class Assembly:
|
||||
def __init__(self, render_engine, objects, visible_layers, group_prefix="", translation_offset=(0,0,0)):
|
||||
self.name = group_prefix
|
||||
self.translation_offset = translation_offset
|
||||
self.render_engine = render_engine
|
||||
|
||||
self.materials = []
|
||||
self.objects = []
|
||||
self.instances = []
|
||||
|
||||
self.material_names = set()
|
||||
self.mesh_names = set()
|
||||
self.assembly_names = set()
|
||||
|
||||
# Collect all the objects, materials, instances, etc.
|
||||
for ob in objects:
|
||||
# Check if render is cancelled
|
||||
if render_engine.test_break():
|
||||
raise ExportCancelled()
|
||||
|
||||
# Check if the object is visible for rendering
|
||||
vis_layer = False
|
||||
for i in range(len(ob.layers)):
|
||||
vis_layer = vis_layer or (ob.layers[i] and visible_layers[i])
|
||||
if ob.hide_render or not vis_layer:
|
||||
continue
|
||||
|
||||
# Store object data
|
||||
name = None
|
||||
|
||||
if ob.type == 'EMPTY':
|
||||
if ob.dupli_type == 'GROUP':
|
||||
name = group_prefix + "__" + escape_name(ob.dupli_group.name)
|
||||
if name not in self.assembly_names:
|
||||
self.assembly_names.add(name)
|
||||
self.objects += [Assembly(self.render_engine, ob.dupli_group.objects, ob.dupli_group.layers, name, ob.dupli_group.dupli_offset*-1)]
|
||||
elif ob.type == 'MESH':
|
||||
name = self.get_mesh(ob, group_prefix)
|
||||
elif ob.type == 'LAMP' and ob.data.type == 'POINT':
|
||||
name = self.get_sphere_lamp(ob, group_prefix)
|
||||
elif ob.type == 'LAMP' and ob.data.type == 'AREA':
|
||||
name = self.get_rect_lamp(ob, group_prefix)
|
||||
|
||||
# Store instance
|
||||
if name != None:
|
||||
self.instances += [Instance(render_engine, ob, name)]
|
||||
|
||||
def export(self, render_engine, w):
|
||||
if self.name == "":
|
||||
w.write("Assembly {\n")
|
||||
else:
|
||||
w.write("Assembly $%s {\n" % self.name)
|
||||
w.indent()
|
||||
|
||||
for mat in self.materials:
|
||||
# Check if render is cancelled
|
||||
if render_engine.test_break():
|
||||
raise ExportCancelled()
|
||||
mat.export(render_engine, w)
|
||||
|
||||
for ob in self.objects:
|
||||
# Check if render is cancelled
|
||||
if render_engine.test_break():
|
||||
raise ExportCancelled()
|
||||
ob.export(render_engine, w)
|
||||
|
||||
for inst in self.instances:
|
||||
# Check if render is cancelled
|
||||
if render_engine.test_break():
|
||||
raise ExportCancelled()
|
||||
inst.export(render_engine, w)
|
||||
|
||||
w.unindent()
|
||||
w.write("}\n")
|
||||
|
||||
#----------------
|
||||
|
||||
def take_sample(self, render_engine, scene, time):
|
||||
for mat in self.materials:
|
||||
# Check if render is cancelled
|
||||
if render_engine.test_break():
|
||||
raise ExportCancelled()
|
||||
mat.take_sample(render_engine, scene, time)
|
||||
|
||||
for ob in self.objects:
|
||||
# Check if render is cancelled
|
||||
if render_engine.test_break():
|
||||
raise ExportCancelled()
|
||||
ob.take_sample(render_engine, scene, time)
|
||||
|
||||
for inst in self.instances:
|
||||
# Check if render is cancelled
|
||||
if render_engine.test_break():
|
||||
raise ExportCancelled()
|
||||
inst.take_sample(render_engine, time, self.translation_offset)
|
||||
|
||||
def cleanup(self):
|
||||
for mat in self.materials:
|
||||
mat.cleanup()
|
||||
for ob in self.objects:
|
||||
ob.cleanup()
|
||||
|
||||
def get_mesh(self, ob, group_prefix):
|
||||
# Figure out if we need to export or not and figure out what name to
|
||||
# export with.
|
||||
has_modifiers = len(ob.modifiers) > 0
|
||||
deform_mb = needs_def_mb(ob)
|
||||
if has_modifiers or deform_mb:
|
||||
mesh_name = group_prefix + escape_name("__" + ob.name + "__" + ob.data.name + "_")
|
||||
else:
|
||||
mesh_name = group_prefix + escape_name("__" + ob.data.name + "_")
|
||||
has_faces = len(ob.data.polygons) > 0
|
||||
should_export_mesh = has_faces and (mesh_name not in self.mesh_names)
|
||||
|
||||
# Get mesh
|
||||
if should_export_mesh:
|
||||
self.mesh_names.add(mesh_name)
|
||||
self.objects += [Mesh(self.render_engine, ob, mesh_name)]
|
||||
|
||||
# Get materials
|
||||
for ms in ob.material_slots:
|
||||
if ms != None:
|
||||
if ms.material.name not in self.material_names:
|
||||
self.material_names.add(ms.material.name)
|
||||
self.materials += [Material(self.render_engine, ms.material)]
|
||||
|
||||
return mesh_name
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def get_sphere_lamp(self, ob, group_prefix):
|
||||
name = group_prefix + "__" + escape_name(ob.name)
|
||||
self.objects += [SphereLamp(self.render_engine, ob, name)]
|
||||
return name
|
||||
|
||||
def get_rect_lamp(self, ob, group_prefix):
|
||||
name = group_prefix + "__" + escape_name(ob.name)
|
||||
self.objects += [RectLamp(self.render_engine, ob, name)]
|
||||
return name
|
||||
|
||||
|
||||
#=========================================================================
|
||||
|
||||
|
||||
class Mesh:
|
||||
""" Holds data for a mesh to be exported.
|
||||
"""
|
||||
def __init__(self, render_engine, ob, name):
|
||||
self.ob = ob
|
||||
self.name = name
|
||||
self.needs_mb = needs_def_mb(self.ob)
|
||||
self.time_meshes = []
|
||||
|
||||
def take_sample(self, render_engine, scene, time):
|
||||
if len(self.time_meshes) == 0 or self.needs_mb:
|
||||
render_engine.update_stats("", "Psychopath: Collecting '{}' at time {}".format(self.ob.name, time))
|
||||
self.time_meshes += [self.ob.to_mesh(scene, True, 'RENDER')]
|
||||
|
||||
def cleanup(self):
|
||||
for mesh in self.time_meshes:
|
||||
bpy.data.meshes.remove(mesh)
|
||||
|
||||
def export(self, render_engine, w):
|
||||
render_engine.update_stats("", "Psychopath: Exporting %s" % self.ob.name)
|
||||
|
||||
if self.ob.data.psychopath.is_subdivision_surface == False:
|
||||
# Exporting normal mesh
|
||||
w.write("MeshSurface $%s {\n" % self.name)
|
||||
w.indent()
|
||||
else:
|
||||
# Exporting subdivision surface cage
|
||||
w.write("SubdivisionSurface $%s {\n" % self.name)
|
||||
w.indent()
|
||||
|
||||
# Write vertices and (if it's smooth shaded) normals
|
||||
for ti in range(len(self.time_meshes)):
|
||||
w.write("Vertices [")
|
||||
w.write(" ".join([("%f" % i) for vert in self.time_meshes[ti].vertices for i in vert.co]), False)
|
||||
w.write("]\n", False)
|
||||
if self.time_meshes[0].polygons[0].use_smooth and self.ob.data.psychopath.is_subdivision_surface == False:
|
||||
w.write("Normals [")
|
||||
w.write(" ".join([("%f" % i) for vert in self.time_meshes[ti].vertices for i in vert.normal]), False)
|
||||
w.write("]\n", False)
|
||||
|
||||
# Write face vertex counts
|
||||
w.write("FaceVertCounts [")
|
||||
w.write(" ".join([("%d" % len(p.vertices)) for p in self.time_meshes[0].polygons]), False)
|
||||
w.write("]\n", False)
|
||||
|
||||
# Write face vertex indices
|
||||
w.write("FaceVertIndices [")
|
||||
w.write(" ".join([("%d"%v) for p in self.time_meshes[0].polygons for v in p.vertices]), False)
|
||||
w.write("]\n", False)
|
||||
|
||||
# MeshSurface/SubdivisionSurface section end
|
||||
w.unindent()
|
||||
w.write("}\n")
|
||||
|
||||
|
||||
class SphereLamp:
|
||||
""" Holds data for a sphere light to be exported.
|
||||
"""
|
||||
def __init__(self, render_engine, ob, name):
|
||||
self.ob = ob
|
||||
self.name = name
|
||||
self.time_col = []
|
||||
self.time_rad = []
|
||||
|
||||
def take_sample(self, render_engine, scene, time):
|
||||
render_engine.update_stats("", "Psychopath: Collecting '{}' at time {}".format(self.ob.name, time))
|
||||
|
||||
if self.ob.data.psychopath.color_type == 'Rec709':
|
||||
self.time_col += [('Rec709', self.ob.data.color * self.ob.data.energy)]
|
||||
elif self.ob.data.psychopath.color_type == 'Blackbody':
|
||||
self.time_col += [('Blackbody', self.ob.data.psychopath.color_blackbody_temp, self.ob.data.energy)]
|
||||
elif self.ob.data.psychopath.color_type == 'ColorTemperature':
|
||||
self.time_col += [('ColorTemperature', self.ob.data.psychopath.color_blackbody_temp, self.ob.data.energy)]
|
||||
|
||||
self.time_rad += [self.ob.data.shadow_soft_size]
|
||||
|
||||
def cleanup(self):
|
||||
pass
|
||||
|
||||
def export(self, render_engine, w):
|
||||
render_engine.update_stats("", "Psychopath: Exporting %s" % self.ob.name)
|
||||
|
||||
w.write("SphereLight $%s {\n" % self.name)
|
||||
w.indent()
|
||||
for col in self.time_col:
|
||||
if col[0] == 'Rec709':
|
||||
w.write("Color [rec709, %f %f %f]\n" % (col[1][0], col[1][1], col[1][2]))
|
||||
elif col[0] == 'Blackbody':
|
||||
w.write("Color [blackbody, %f %f]\n" % (col[1], col[2]))
|
||||
elif col[0] == 'ColorTemperature':
|
||||
w.write("Color [color_temperature, %f %f]\n" % (col[1], col[2]))
|
||||
for rad in self.time_rad:
|
||||
w.write("Radius [%f]\n" % rad)
|
||||
|
||||
w.unindent()
|
||||
w.write("}\n")
|
||||
|
||||
|
||||
class RectLamp:
|
||||
""" Holds data for a rectangular light to be exported.
|
||||
"""
|
||||
def __init__(self, render_engine, ob, name):
|
||||
self.ob = ob
|
||||
self.name = name
|
||||
self.time_col = []
|
||||
self.time_dim = []
|
||||
|
||||
def take_sample(self, render_engine, scene, time):
|
||||
render_engine.update_stats("", "Psychopath: Collecting '{}' at time {}".format(self.ob.name, time))
|
||||
|
||||
if self.ob.data.psychopath.color_type == 'Rec709':
|
||||
self.time_col += [('Rec709', self.ob.data.color * self.ob.data.energy)]
|
||||
elif self.ob.data.psychopath.color_type == 'Blackbody':
|
||||
self.time_col += [('Blackbody', self.ob.data.psychopath.color_blackbody_temp, self.ob.data.energy)]
|
||||
elif self.ob.data.psychopath.color_type == 'ColorTemperature':
|
||||
self.time_col += [('ColorTemperature', self.ob.data.psychopath.color_blackbody_temp, self.ob.data.energy)]
|
||||
|
||||
if self.ob.data.shape == 'RECTANGLE':
|
||||
self.time_dim += [(self.ob.data.size, self.ob.data.size_y)]
|
||||
else:
|
||||
self.time_dim += [(self.ob.data.size, self.ob.data.size)]
|
||||
|
||||
def cleanup(self):
|
||||
pass
|
||||
|
||||
def export(self, render_engine, w):
|
||||
render_engine.update_stats("", "Psychopath: Exporting %s" % self.ob.name)
|
||||
|
||||
w.write("RectangleLight $%s {\n" % self.name)
|
||||
w.indent()
|
||||
for col in self.time_col:
|
||||
if col[0] == 'Rec709':
|
||||
w.write("Color [rec709, %f %f %f]\n" % (col[1][0], col[1][1], col[1][2]))
|
||||
elif col[0] == 'Blackbody':
|
||||
w.write("Color [blackbody, %f %f]\n" % (col[1], col[2]))
|
||||
elif col[0] == 'ColorTemperature':
|
||||
w.write("Color [color_temperature, %f %f]\n" % (col[1], col[2]))
|
||||
for dim in self.time_dim:
|
||||
w.write("Dimensions [%f %f]\n" % dim)
|
||||
|
||||
w.unindent()
|
||||
w.write("}\n")
|
||||
|
||||
|
||||
class Instance:
|
||||
def __init__(self, render_engine, ob, data_name):
|
||||
self.ob = ob
|
||||
self.data_name = data_name
|
||||
self.needs_mb = needs_xform_mb(self.ob)
|
||||
self.time_xforms = []
|
||||
|
||||
def take_sample(self, render_engine, time, translation_offset):
|
||||
if len(self.time_xforms) == 0 or self.needs_mb:
|
||||
render_engine.update_stats("", "Psychopath: Collecting '{}' xforms at time {}".format(self.ob.name, time))
|
||||
mat = self.ob.matrix_world.copy()
|
||||
mat[0][3] += translation_offset[0]
|
||||
mat[1][3] += translation_offset[1]
|
||||
mat[2][3] += translation_offset[2]
|
||||
self.time_xforms += [mat]
|
||||
|
||||
def export(self, render_engine, w):
|
||||
render_engine.update_stats("", "Psychopath: Exporting %s" % self.ob.name)
|
||||
|
||||
w.write("Instance {\n")
|
||||
w.indent()
|
||||
w.write("Data [$%s]\n" % self.data_name)
|
||||
for mat in self.time_xforms:
|
||||
w.write("Transform [%s]\n" % mat2str(mat))
|
||||
for ms in self.ob.material_slots:
|
||||
if ms != None:
|
||||
w.write("SurfaceShaderBind [$%s]\n" % escape_name(ms.material.name))
|
||||
break
|
||||
w.unindent()
|
||||
w.write("}\n")
|
||||
|
||||
|
||||
class Material:
|
||||
def __init__(self, render_engine, material):
|
||||
self.mat = material
|
||||
|
||||
def take_sample(self, render_engine, time, translation_offset):
|
||||
# TODO: motion blur of material settings
|
||||
pass
|
||||
|
||||
def export(self, render_engine, w):
|
||||
render_engine.update_stats("", "Psychopath: Exporting %s" % self.mat.name)
|
||||
|
||||
w.write("SurfaceShader $%s {\n" % escape_name(self.mat.name))
|
||||
w.indent()
|
||||
if self.mat.psychopath.surface_shader_type == 'Emit':
|
||||
w.write("Type [Emit]\n")
|
||||
if self.mat.psychopath.color_type == 'Rec709':
|
||||
col = self.mat.psychopath.color
|
||||
w.write("Color [rec709, %f %f %f]\n" % (
|
||||
col[0], col[1], col[2],
|
||||
))
|
||||
elif self.mat.psychopath.color_type == 'Blackbody':
|
||||
w.write("Color [blackbody, %f %f]\n" % (
|
||||
self.mat.psychopath.color_blackbody_temp,
|
||||
1.0,
|
||||
))
|
||||
elif self.mat.psychopath.color_type == 'ColorTemperature':
|
||||
w.write("Color [color_temperature, %f %f]\n" % (
|
||||
self.mat.psychopath.color_blackbody_temp,
|
||||
1.0,
|
||||
))
|
||||
elif self.mat.psychopath.surface_shader_type == 'Lambert':
|
||||
w.write("Type [Lambert]\n")
|
||||
if self.mat.psychopath.color_type == 'Rec709':
|
||||
col = self.mat.psychopath.color
|
||||
w.write("Color [rec709, %f %f %f]\n" % (
|
||||
col[0], col[1], col[2],
|
||||
))
|
||||
elif self.mat.psychopath.color_type == 'Blackbody':
|
||||
w.write("Color [blackbody, %f %f]\n" % (
|
||||
self.mat.psychopath.color_blackbody_temp,
|
||||
1.0,
|
||||
))
|
||||
elif self.mat.psychopath.color_type == 'ColorTemperature':
|
||||
w.write("Color [color_temperature, %f %f]\n" % (
|
||||
self.mat.psychopath.color_blackbody_temp,
|
||||
1.0,
|
||||
))
|
||||
elif self.mat.psychopath.surface_shader_type == 'GGX':
|
||||
w.write("Type [GGX]\n")
|
||||
if self.mat.psychopath.color_type == 'Rec709':
|
||||
col = self.mat.psychopath.color
|
||||
w.write("Color [rec709, %f %f %f]\n" % (
|
||||
col[0], col[1], col[2],
|
||||
))
|
||||
elif self.mat.psychopath.color_type == 'Blackbody':
|
||||
w.write("Color [blackbody, %f %f]\n" % (
|
||||
self.mat.psychopath.color_blackbody_temp,
|
||||
1.0,
|
||||
))
|
||||
elif self.mat.psychopath.color_type == 'ColorTemperature':
|
||||
w.write("Color [color_temperature, %f %f]\n" % (
|
||||
self.mat.psychopath.color_blackbody_temp,
|
||||
1.0,
|
||||
))
|
||||
w.write("Roughness [%f]\n" % self.mat.psychopath.roughness)
|
||||
w.write("Fresnel [%f]\n" % self.mat.psychopath.fresnel)
|
||||
else:
|
||||
raise "Unsupported surface shader type '%s'" % self.mat.psychopath.surface_shader_type
|
||||
w.unindent()
|
||||
w.write("}\n")
|
||||
|
||||
def cleanup(self):
|
||||
pass
|
77
psychoblend/material.py
Normal file
77
psychoblend/material.py
Normal file
|
@ -0,0 +1,77 @@
|
|||
import bpy
|
||||
|
||||
from .util import escape_name, mat2str, needs_def_mb, needs_xform_mb, ExportCancelled
|
||||
|
||||
class Material:
|
||||
def __init__(self, render_engine, depsgraph, material):
|
||||
self.mat = material
|
||||
|
||||
def take_sample(self, render_engine, depsgraph, time):
|
||||
# TODO: motion blur of material settings
|
||||
pass
|
||||
|
||||
def export(self, render_engine, w):
|
||||
render_engine.update_stats("", "Psychopath: Exporting %s" % self.mat.name)
|
||||
|
||||
w.write("SurfaceShader $%s {\n" % escape_name(self.mat.name))
|
||||
w.indent()
|
||||
if self.mat.psychopath.surface_shader_type == 'Emit':
|
||||
w.write("Type [Emit]\n")
|
||||
if self.mat.psychopath.color_type == 'Rec709':
|
||||
col = self.mat.psychopath.color
|
||||
w.write("Color [rec709, %f %f %f]\n" % (
|
||||
col[0], col[1], col[2],
|
||||
))
|
||||
elif self.mat.psychopath.color_type == 'Blackbody':
|
||||
w.write("Color [blackbody, %f %f]\n" % (
|
||||
self.mat.psychopath.color_blackbody_temp,
|
||||
1.0,
|
||||
))
|
||||
elif self.mat.psychopath.color_type == 'ColorTemperature':
|
||||
w.write("Color [color_temperature, %f %f]\n" % (
|
||||
self.mat.psychopath.color_blackbody_temp,
|
||||
1.0,
|
||||
))
|
||||
elif self.mat.psychopath.surface_shader_type == 'Lambert':
|
||||
w.write("Type [Lambert]\n")
|
||||
if self.mat.psychopath.color_type == 'Rec709':
|
||||
col = self.mat.psychopath.color
|
||||
w.write("Color [rec709, %f %f %f]\n" % (
|
||||
col[0], col[1], col[2],
|
||||
))
|
||||
elif self.mat.psychopath.color_type == 'Blackbody':
|
||||
w.write("Color [blackbody, %f %f]\n" % (
|
||||
self.mat.psychopath.color_blackbody_temp,
|
||||
1.0,
|
||||
))
|
||||
elif self.mat.psychopath.color_type == 'ColorTemperature':
|
||||
w.write("Color [color_temperature, %f %f]\n" % (
|
||||
self.mat.psychopath.color_blackbody_temp,
|
||||
1.0,
|
||||
))
|
||||
elif self.mat.psychopath.surface_shader_type == 'GGX':
|
||||
w.write("Type [GGX]\n")
|
||||
if self.mat.psychopath.color_type == 'Rec709':
|
||||
col = self.mat.psychopath.color
|
||||
w.write("Color [rec709, %f %f %f]\n" % (
|
||||
col[0], col[1], col[2],
|
||||
))
|
||||
elif self.mat.psychopath.color_type == 'Blackbody':
|
||||
w.write("Color [blackbody, %f %f]\n" % (
|
||||
self.mat.psychopath.color_blackbody_temp,
|
||||
1.0,
|
||||
))
|
||||
elif self.mat.psychopath.color_type == 'ColorTemperature':
|
||||
w.write("Color [color_temperature, %f %f]\n" % (
|
||||
self.mat.psychopath.color_blackbody_temp,
|
||||
1.0,
|
||||
))
|
||||
w.write("Roughness [%f]\n" % self.mat.psychopath.roughness)
|
||||
w.write("Fresnel [%f]\n" % self.mat.psychopath.fresnel)
|
||||
else:
|
||||
raise "Unsupported surface shader type '%s'" % self.mat.psychopath.surface_shader_type
|
||||
w.unindent()
|
||||
w.write("}\n")
|
||||
|
||||
def cleanup(self):
|
||||
pass
|
227
psychoblend/objects.py
Normal file
227
psychoblend/objects.py
Normal file
|
@ -0,0 +1,227 @@
|
|||
import bpy
|
||||
|
||||
from .util import escape_name, mat2str, needs_def_mb, needs_xform_mb, ExportCancelled
|
||||
|
||||
def make_object_data_cache(render_engine, depsgraph, ob, name):
|
||||
if ob.type == 'MESH':
|
||||
return Mesh(render_engine, depsgraph, ob, name)
|
||||
elif ob.type == 'LIGHT':
|
||||
if ob.data.type == 'POINT':
|
||||
return SphereLamp(render_engine, depsgraph, ob, name)
|
||||
elif ob.data.type == 'AREA':
|
||||
return RectLamp(render_engine, depsgraph, ob, name)
|
||||
elif ob.data.type == 'AREA':
|
||||
return RectLamp(render_engine, depsgraph, ob, name)
|
||||
|
||||
class Mesh:
|
||||
""" Holds data for a mesh to be exported.
|
||||
"""
|
||||
def __init__(self, render_engine, depsgraph, ob, name):
|
||||
self.name = name
|
||||
self.is_subdiv = ob.data.psychopath.is_subdivision_surface
|
||||
self.needs_mb = needs_def_mb(ob)
|
||||
self.time_meshes = []
|
||||
|
||||
def take_sample(self, render_engine, depsgraph, ob, time):
|
||||
if len(self.time_meshes) == 0 or self.needs_mb:
|
||||
render_engine.update_stats("", "Psychopath: Collecting '{}' at time {}".format(self.name, time))
|
||||
self.time_meshes += [ob.to_mesh(depsgraph=depsgraph).copy()]
|
||||
|
||||
def cleanup(self):
|
||||
for mesh in self.time_meshes:
|
||||
bpy.data.meshes.remove(mesh)
|
||||
|
||||
def export(self, render_engine, w):
|
||||
render_engine.update_stats("", "Psychopath: Exporting %s" % self.name)
|
||||
|
||||
if self.is_subdiv == False:
|
||||
# Exporting normal mesh
|
||||
w.write("MeshSurface $%s {\n" % self.name)
|
||||
w.indent()
|
||||
else:
|
||||
# Exporting subdivision surface cage
|
||||
w.write("SubdivisionSurface $%s {\n" % self.name)
|
||||
w.indent()
|
||||
|
||||
# Write vertices and (if it's smooth shaded) normals
|
||||
for ti in range(len(self.time_meshes)):
|
||||
w.write("Vertices [")
|
||||
w.write(" ".join([("%f" % i) for vert in self.time_meshes[ti].vertices for i in vert.co]), False)
|
||||
w.write("]\n", False)
|
||||
if self.time_meshes[0].polygons[0].use_smooth and self.is_subdiv == False:
|
||||
w.write("Normals [")
|
||||
w.write(" ".join([("%f" % i) for vert in self.time_meshes[ti].vertices for i in vert.normal]), False)
|
||||
w.write("]\n", False)
|
||||
|
||||
# Write face vertex counts
|
||||
w.write("FaceVertCounts [")
|
||||
w.write(" ".join([("%d" % len(p.vertices)) for p in self.time_meshes[0].polygons]), False)
|
||||
w.write("]\n", False)
|
||||
|
||||
# Write face vertex indices
|
||||
w.write("FaceVertIndices [")
|
||||
w.write(" ".join([("%d"%v) for p in self.time_meshes[0].polygons for v in p.vertices]), False)
|
||||
w.write("]\n", False)
|
||||
|
||||
# MeshSurface/SubdivisionSurface section end
|
||||
w.unindent()
|
||||
w.write("}\n")
|
||||
|
||||
|
||||
class SphereLamp:
|
||||
""" Holds data for a sphere light to be exported.
|
||||
"""
|
||||
def __init__(self, render_engine, depsgraph, ob, name):
|
||||
self.name = name
|
||||
self.time_col = []
|
||||
self.time_rad = []
|
||||
|
||||
def take_sample(self, render_engine, depsgraph, ob, time):
|
||||
render_engine.update_stats("", "Psychopath: Collecting '{}' at time {}".format(ob.name, time))
|
||||
|
||||
if ob.data.psychopath.color_type == 'Rec709':
|
||||
self.time_col += [('Rec709', ob.data.color * ob.data.energy)]
|
||||
elif ob.data.psychopath.color_type == 'Blackbody':
|
||||
self.time_col += [('Blackbody', ob.data.psychopath.color_blackbody_temp, ob.data.energy)]
|
||||
elif ob.data.psychopath.color_type == 'ColorTemperature':
|
||||
self.time_col += [('ColorTemperature', ob.data.psychopath.color_blackbody_temp, ob.data.energy)]
|
||||
|
||||
self.time_rad += [ob.data.shadow_soft_size]
|
||||
|
||||
def cleanup(self):
|
||||
pass
|
||||
|
||||
def export(self, render_engine, w):
|
||||
render_engine.update_stats("", "Psychopath: Exporting %s" % self.name)
|
||||
|
||||
w.write("SphereLight $%s {\n" % self.name)
|
||||
w.indent()
|
||||
for col in self.time_col:
|
||||
if col[0] == 'Rec709':
|
||||
w.write("Color [rec709, %f %f %f]\n" % (col[1][0], col[1][1], col[1][2]))
|
||||
elif col[0] == 'Blackbody':
|
||||
w.write("Color [blackbody, %f %f]\n" % (col[1], col[2]))
|
||||
elif col[0] == 'ColorTemperature':
|
||||
w.write("Color [color_temperature, %f %f]\n" % (col[1], col[2]))
|
||||
for rad in self.time_rad:
|
||||
w.write("Radius [%f]\n" % rad)
|
||||
|
||||
w.unindent()
|
||||
w.write("}\n")
|
||||
|
||||
|
||||
class RectLamp:
|
||||
""" Holds data for a rectangular light to be exported.
|
||||
"""
|
||||
def __init__(self, render_engine, depsgraph, ob, name):
|
||||
self.name = name
|
||||
self.time_col = []
|
||||
self.time_dim = []
|
||||
|
||||
def take_sample(self, render_engine, depsgraph, ob, time):
|
||||
render_engine.update_stats("", "Psychopath: Collecting '{}' at time {}".format(self.name, time))
|
||||
|
||||
if ob.data.psychopath.color_type == 'Rec709':
|
||||
self.time_col += [('Rec709', ob.data.color * ob.data.energy)]
|
||||
elif ob.data.psychopath.color_type == 'Blackbody':
|
||||
self.time_col += [('Blackbody', ob.data.psychopath.color_blackbody_temp, ob.data.energy)]
|
||||
elif ob.data.psychopath.color_type == 'ColorTemperature':
|
||||
self.time_col += [('ColorTemperature', ob.data.psychopath.color_blackbody_temp, ob.data.energy)]
|
||||
|
||||
if ob.data.shape == 'RECTANGLE':
|
||||
self.time_dim += [(ob.data.size, ob.data.size_y)]
|
||||
else:
|
||||
self.time_dim += [(ob.data.size, ob.data.size)]
|
||||
|
||||
def cleanup(self):
|
||||
pass
|
||||
|
||||
def export(self, render_engine, w):
|
||||
render_engine.update_stats("", "Psychopath: Exporting %s" % self.ob.name)
|
||||
|
||||
w.write("RectangleLight $%s {\n" % self.name)
|
||||
w.indent()
|
||||
for col in self.time_col:
|
||||
if col[0] == 'Rec709':
|
||||
w.write("Color [rec709, %f %f %f]\n" % (col[1][0], col[1][1], col[1][2]))
|
||||
elif col[0] == 'Blackbody':
|
||||
w.write("Color [blackbody, %f %f]\n" % (col[1], col[2]))
|
||||
elif col[0] == 'ColorTemperature':
|
||||
w.write("Color [color_temperature, %f %f]\n" % (col[1], col[2]))
|
||||
for dim in self.time_dim:
|
||||
w.write("Dimensions [%f %f]\n" % dim)
|
||||
|
||||
w.unindent()
|
||||
w.write("}\n")
|
||||
|
||||
|
||||
class DistantDiskLamp:
|
||||
def __init__(self, render_engine, depsgraph, ob, name):
|
||||
self.name = name
|
||||
self.time_col = []
|
||||
self.time_dir = []
|
||||
self.time_rad = []
|
||||
|
||||
def take_sample(self, render_engine, depsgraph, ob, time):
|
||||
render_engine.update_stats("", "Psychopath: Collecting '{}' at time {}".format(self.name, time))
|
||||
self.time_dir += [tuple(ob.matrix_world.to_3x3() @ Vector((0, 0, -1)))]
|
||||
|
||||
if ob.data.psychopath.color_type == 'Rec709':
|
||||
self.time_col += [('Rec709', ob.data.color * ob.data.energy)]
|
||||
elif ob.data.psychopath.color_type == 'Blackbody':
|
||||
self.time_col += [('Blackbody', ob.data.psychopath.color_blackbody_temp, ob.data.energy)]
|
||||
elif ob.data.psychopath.color_type == 'ColorTemperature':
|
||||
self.time_col += [('ColorTemperature', ob.data.psychopath.color_blackbody_temp, ob.data.energy)]
|
||||
|
||||
self.time_rad += [ob.data.shadow_soft_size]
|
||||
|
||||
def export(self, render_engine, w):
|
||||
render_engine.update_stats("", "Psychopath: Exporting %s" % self.ob.name)
|
||||
w.write("DistantDiskLight $%s {\n" % self.name)
|
||||
w.indent()
|
||||
for direc in self.time_dir:
|
||||
w.write("Direction [%f %f %f]\n" % (direc[0], direc[1], direc[2]))
|
||||
for col in self.time_col:
|
||||
if col[0] == 'Rec709':
|
||||
w.write("Color [rec709, %f %f %f]\n" % (col[1][0], col[1][1], col[1][2]))
|
||||
elif col[0] == 'Blackbody':
|
||||
w.write("Color [blackbody, %f %f]\n" % (col[1], col[2]))
|
||||
elif col[0] == 'ColorTemperature':
|
||||
w.write("Color [color_temperature, %f %f]\n" % (col[1], col[2]))
|
||||
for rad in self.time_rad:
|
||||
w.write("Radius [%f]\n" % rad)
|
||||
|
||||
w.unindent()
|
||||
w.write("}\n")
|
||||
|
||||
|
||||
# class Instance:
|
||||
# def __init__(self, render_engine, depsgraph, ob, data_name):
|
||||
# self.ob = ob
|
||||
# self.data_name = data_name
|
||||
# self.needs_mb = needs_xform_mb(self.ob)
|
||||
# self.time_xforms = []
|
||||
|
||||
# def take_sample(self, render_engine, time, translation_offset):
|
||||
# if len(self.time_xforms) == 0 or self.needs_mb:
|
||||
# render_engine.update_stats("", "Psychopath: Collecting '{}' xforms at time {}".format(self.ob.name, time))
|
||||
# mat = self.ob.matrix_world.copy()
|
||||
# mat[0][3] += translation_offset[0]
|
||||
# mat[1][3] += translation_offset[1]
|
||||
# mat[2][3] += translation_offset[2]
|
||||
# self.time_xforms += [mat]
|
||||
|
||||
# def export(self, render_engine, w):
|
||||
# render_engine.update_stats("", "Psychopath: Exporting %s" % self.ob.name)
|
||||
|
||||
# w.write("Instance {\n")
|
||||
# w.indent()
|
||||
# w.write("Data [$%s]\n" % self.data_name)
|
||||
# for mat in self.time_xforms:
|
||||
# w.write("Transform [%s]\n" % mat2str(mat))
|
||||
# for ms in self.ob.material_slots:
|
||||
# if ms != None:
|
||||
# w.write("SurfaceShaderBind [$%s]\n" % escape_name(ms.material.name))
|
||||
# break
|
||||
# w.unindent()
|
||||
# w.write("}\n")
|
|
@ -2,9 +2,10 @@ import bpy
|
|||
|
||||
from math import log
|
||||
|
||||
from .assembly import Assembly
|
||||
from .objects import make_object_data_cache, Mesh, DistantDiskLamp
|
||||
from .util import escape_name, mat2str, ExportCancelled
|
||||
from .world import World
|
||||
from .world import World, Camera
|
||||
from . import bl_info
|
||||
|
||||
|
||||
class IndentedWriter:
|
||||
|
@ -29,25 +30,40 @@ class IndentedWriter:
|
|||
|
||||
|
||||
class PsychoExporter:
|
||||
def __init__(self, f, render_engine, scene):
|
||||
def __init__(self, f, render_engine, depsgraph):
|
||||
self.w = IndentedWriter(f)
|
||||
self.render_engine = render_engine
|
||||
self.scene = scene
|
||||
self.depsgraph = depsgraph
|
||||
self.scene = depsgraph.scene
|
||||
self.view_layer = depsgraph.view_layer
|
||||
|
||||
self.mesh_names = {}
|
||||
self.group_names = {}
|
||||
# For camera data.
|
||||
res_x = int(self.scene.render.resolution_x * (self.scene.render.resolution_percentage / 100))
|
||||
res_y = int(self.scene.render.resolution_y * (self.scene.render.resolution_percentage / 100))
|
||||
self.camera = Camera(render_engine, depsgraph.scene.camera, float(res_x) / float(res_y))
|
||||
|
||||
# Motion blur segments are rounded down to a power of two
|
||||
if scene.psychopath.motion_blur_segments > 0:
|
||||
self.time_samples = (2**int(log(scene.psychopath.motion_blur_segments, 2))) + 1
|
||||
# For world data.
|
||||
self.world = World(render_engine, depsgraph)
|
||||
|
||||
# For all objects except sun lamps.
|
||||
self.object_data = {} # name -> cached_data
|
||||
self.instances = {} # instance_id -> [object_data_name, transform_list]
|
||||
|
||||
# For all sun lamps.
|
||||
self.sun_lamp_data = {} # name -> cached_data
|
||||
self.sun_lamp_instances = {} # instance_id -> [sun_lamp_data_name, transform_list]
|
||||
|
||||
# Motion blur segments are rounded down to a power of two.
|
||||
if self.scene.psychopath.motion_blur_segments > 0:
|
||||
self.time_samples = (2**int(log(self.scene.psychopath.motion_blur_segments, 2))) + 1
|
||||
else:
|
||||
self.time_samples = 1
|
||||
|
||||
# pre-calculate useful values for exporting motion blur
|
||||
self.shutter_start = scene.psychopath.shutter_start
|
||||
self.shutter_diff = (scene.psychopath.shutter_end - scene.psychopath.shutter_start) / max(1, (self.time_samples-1))
|
||||
# pre-calculate useful values for exporting motion blur.
|
||||
self.shutter_start = self.scene.psychopath.shutter_start
|
||||
self.shutter_diff = (self.scene.psychopath.shutter_end - self.scene.psychopath.shutter_start) / max(1, (self.time_samples-1))
|
||||
|
||||
self.fr = scene.frame_current
|
||||
self.fr = self.scene.frame_current
|
||||
|
||||
|
||||
def set_frame(self, frame, fraction):
|
||||
|
@ -70,25 +86,31 @@ class PsychoExporter:
|
|||
|
||||
def _export_psy(self):
|
||||
# Info
|
||||
self.w.write("# Exported from Blender 2.7x\n")
|
||||
self.w.write("# Exported from Blender {} with PsychoBlend {}.{}.{}\n".format(
|
||||
bpy.app.version_string,
|
||||
bl_info["version"][0],
|
||||
bl_info["version"][1],
|
||||
bl_info["version"][2],
|
||||
))
|
||||
|
||||
# Scene begin
|
||||
self.w.write("\n\nScene $%s_fr%d {\n" % (escape_name(self.scene.name), self.fr))
|
||||
self.w.indent()
|
||||
|
||||
#######################
|
||||
# Output section begin
|
||||
#------------------------------------------------------
|
||||
# Output section.
|
||||
|
||||
self.w.write("Output {\n")
|
||||
self.w.indent()
|
||||
|
||||
self.w.write('Path [""]\n')
|
||||
|
||||
# Output section end
|
||||
self.w.unindent()
|
||||
self.w.write("}\n")
|
||||
|
||||
###############################
|
||||
# RenderSettings section begin
|
||||
#------------------------------------------------------
|
||||
# RenderSettings section.
|
||||
|
||||
self.w.write("RenderSettings {\n")
|
||||
self.w.indent()
|
||||
|
||||
|
@ -99,34 +121,94 @@ class PsychoExporter:
|
|||
self.w.write("DicingRate [%f]\n" % self.scene.psychopath.dicing_rate)
|
||||
self.w.write('Seed [%d]\n' % self.fr)
|
||||
|
||||
# RenderSettings section end
|
||||
self.w.unindent()
|
||||
self.w.write("}\n")
|
||||
|
||||
###############################
|
||||
# Export world and object data
|
||||
world = None
|
||||
root_assembly = None
|
||||
#------------------------------------------------------
|
||||
# Collect world and object data.
|
||||
|
||||
try:
|
||||
# Prep for data collection
|
||||
world = World(self.render_engine, self.scene, self.scene.layers, float(res_x) / float(res_y))
|
||||
root_assembly = Assembly(self.render_engine, self.scene.objects, self.scene.layers)
|
||||
|
||||
# Collect data for each time sample
|
||||
for i in range(self.time_samples):
|
||||
time = self.fr + self.shutter_start + (self.shutter_diff*i)
|
||||
self.set_frame(self.fr, self.shutter_start + (self.shutter_diff*i))
|
||||
world.take_sample(self.render_engine, self.scene, time)
|
||||
root_assembly.take_sample(self.render_engine, self.scene, time)
|
||||
# Check if render is cancelled
|
||||
if self.render_engine.test_break():
|
||||
raise ExportCancelled()
|
||||
|
||||
# Export collected data
|
||||
world.export(self.render_engine, self.w)
|
||||
root_assembly.export(self.render_engine, self.w)
|
||||
finally:
|
||||
if world != None:
|
||||
world.cleanup()
|
||||
if root_assembly != None:
|
||||
root_assembly.cleanup()
|
||||
time = self.fr + self.shutter_start + (self.shutter_diff*i)
|
||||
|
||||
# Collect camera and world data.
|
||||
self.camera.take_sample(self.render_engine, self.depsgraph, time)
|
||||
self.world.take_sample(self.render_engine, self.depsgraph, time)
|
||||
|
||||
# Collect renderable objects.
|
||||
collected_objs = set() # Names of the objects whose data has already been collected.
|
||||
for inst in self.depsgraph.object_instances:
|
||||
# Check if render is cancelled
|
||||
if self.render_engine.test_break():
|
||||
raise ExportCancelled()
|
||||
|
||||
if inst.object.type not in ['MESH', 'LIGHT']:
|
||||
continue
|
||||
|
||||
# We use this a couple of times, so make a shorthand.
|
||||
is_sun_lamp = inst.object.type == 'LIGHT' and inst.object.data.type == 'SUN'
|
||||
|
||||
# Get a unique id for the instance. This is surprisingly
|
||||
# tricky, because the instance's "persistent_id" property
|
||||
# isn't globally unique, as I would have expected from
|
||||
# the documentation.
|
||||
id = None
|
||||
if inst.is_instance:
|
||||
id = (hash((inst.object.name, inst.parent.name)), inst.persistent_id)
|
||||
else:
|
||||
id = inst.object.name
|
||||
|
||||
# Save the instance transforms.
|
||||
if is_sun_lamp:
|
||||
if id not in self.sun_lamp_instances:
|
||||
self.sun_lamp_instances[id] = [inst.object.name, [inst.matrix_world.copy()]]
|
||||
else:
|
||||
self.sun_lamp_instances[id][1] += [inst.matrix_world.copy()]
|
||||
else:
|
||||
if id not in self.instances:
|
||||
self.instances[id] = [inst.object.name, [inst.matrix_world.copy()]]
|
||||
else:
|
||||
self.instances[id][1] += [inst.matrix_world.copy()]
|
||||
|
||||
# Save the object data if it hasn't already been saved.
|
||||
if inst.object.name not in collected_objs:
|
||||
collected_objs.add(inst.object.name)
|
||||
if is_sun_lamp:
|
||||
if inst.object.name not in self.sun_lamp_data:
|
||||
self.sun_lamp_data[inst.object.name] = DistantDiskLamp(self.render_engine, self.depsgraph, inst.object, inst.object.name)
|
||||
self.sun_lamp_data[inst.object.name].take_sample(self.render_engine, self.depsgraph, inst.object, time)
|
||||
else:
|
||||
if inst.object.name not in self.object_data:
|
||||
self.object_data[inst.object.name] = make_object_data_cache(self.render_engine, self.depsgraph, inst.object, inst.object.name)
|
||||
self.object_data[inst.object.name].take_sample(self.render_engine, self.depsgraph, inst.object, time)
|
||||
|
||||
#------------------------------------------------------
|
||||
# Export world and object data.
|
||||
|
||||
self.camera.export(self.render_engine, self.w)
|
||||
self.world.export(self.render_engine, self.w)
|
||||
|
||||
self.w.write("Assembly {\n")
|
||||
self.w.indent()
|
||||
|
||||
self.w.unindent()
|
||||
self.w.write("}\n")
|
||||
finally:
|
||||
#------------------------------------------------------
|
||||
# Cleanup collected data.
|
||||
|
||||
self.camera.cleanup()
|
||||
self.world.cleanup()
|
||||
|
||||
for data in self.sun_lamp_data:
|
||||
self.sun_lamp_data[data].cleanup()
|
||||
|
||||
for data in self.object_data:
|
||||
self.object_data[data].cleanup()
|
||||
|
||||
# Scene end
|
||||
self.w.unindent()
|
||||
|
|
|
@ -18,31 +18,16 @@ class PsychopathRender(bpy.types.RenderEngine):
|
|||
pass
|
||||
|
||||
def update(self, data, depsgraph):
|
||||
print("Psychopath scene update!")
|
||||
pass
|
||||
|
||||
def render(self, depsgraph):
|
||||
print("Psychopath render!")
|
||||
scene = depsgraph.scene
|
||||
scale = scene.render.resolution_percentage / 100.0
|
||||
self.size_x = int(scene.render.resolution_x * scale)
|
||||
self.size_y = int(scene.render.resolution_y * scale)
|
||||
|
||||
# Fill the render result with a flat color. The framebuffer is
|
||||
# defined as a list of pixels, each pixel itself being a list of
|
||||
# R,G,B,A values.
|
||||
if self.is_preview:
|
||||
color = [0.1, 0.2, 0.1, 1.0]
|
||||
else:
|
||||
color = [0.2, 0.1, 0.1, 1.0]
|
||||
|
||||
pixel_count = self.size_x * self.size_y
|
||||
rect = [color] * pixel_count
|
||||
|
||||
# Here we write the pixel values to the RenderResult
|
||||
result = self.begin_result(0, 0, self.size_x, self.size_y)
|
||||
layer = result.layers[0].passes["Combined"]
|
||||
layer.rect = rect
|
||||
self.end_result(result)
|
||||
self._process = None
|
||||
try:
|
||||
self._render(depsgraph)
|
||||
except:
|
||||
if self._process != None:
|
||||
self._process.terminate()
|
||||
raise
|
||||
|
||||
def view_update(self, context, depsgraph):
|
||||
pass
|
||||
|
@ -54,7 +39,7 @@ class PsychopathRender(bpy.types.RenderEngine):
|
|||
|
||||
@staticmethod
|
||||
def _locate_binary():
|
||||
addon_prefs = bpy.context.user_preferences.addons[__package__].preferences
|
||||
addon_prefs = bpy.context.preferences.addons[__package__].preferences
|
||||
|
||||
# Use the system preference if its set.
|
||||
psy_binary = addon_prefs.filepath_psychopath
|
||||
|
@ -126,16 +111,9 @@ class PsychopathRender(bpy.types.RenderEngine):
|
|||
lay.rect = pixels_flipped
|
||||
self.end_result(result)
|
||||
|
||||
def render(self, scene):
|
||||
self._process = None
|
||||
try:
|
||||
self._render(scene)
|
||||
except:
|
||||
if self._process != None:
|
||||
self._process.terminate()
|
||||
raise
|
||||
def _render(self, depsgraph):
|
||||
scene = depsgraph.scene
|
||||
|
||||
def _render(self, scene):
|
||||
# has to be called to update the frame on exporting animations
|
||||
scene.frame_set(scene.frame_current)
|
||||
|
||||
|
@ -171,8 +149,8 @@ class PsychopathRender(bpy.types.RenderEngine):
|
|||
return
|
||||
|
||||
self.update_stats("", "Psychopath: Collecting...")
|
||||
# Export to Psychopath's stdin
|
||||
if not psy_export.PsychoExporter(self._process.stdin, self, scene).export_psy():
|
||||
# Export to Psychopath's stdin.
|
||||
if not psy_export.PsychoExporter(self._process.stdin, self, depsgraph).export_psy():
|
||||
# Render cancelled in the middle of exporting,
|
||||
# so just return.
|
||||
self._process.terminate()
|
||||
|
@ -183,7 +161,7 @@ class PsychopathRender(bpy.types.RenderEngine):
|
|||
# Export to file
|
||||
self.update_stats("", "Psychopath: Exporting data from Blender")
|
||||
with open(export_path, 'w+b') as f:
|
||||
if not psy_export.PsychoExporter(f, self, scene).export_psy():
|
||||
if not psy_export.PsychoExporter(f, self, depsgraph).export_psy():
|
||||
# Render cancelled in the middle of exporting,
|
||||
# so just return.
|
||||
return
|
||||
|
@ -224,7 +202,7 @@ class PsychopathRender(bpy.types.RenderEngine):
|
|||
# Get render output from stdin
|
||||
tmp = self._process.stdout.read1(2**16)
|
||||
if len(tmp) == 0:
|
||||
time.sleep(0.0001) # Don't spin on the CPU
|
||||
time.sleep(0.001) # Don't spin on the CPU
|
||||
if render_process_finished:
|
||||
all_output_consumed = True
|
||||
continue
|
||||
|
|
|
@ -6,47 +6,28 @@ from mathutils import Vector, Matrix
|
|||
from .util import escape_name, mat2str, ExportCancelled
|
||||
|
||||
class World:
|
||||
def __init__(self, render_engine, scene, visible_layers, aspect_ratio):
|
||||
def __init__(self, render_engine, depsgraph):
|
||||
scene = depsgraph.scene
|
||||
self.background_shader = BackgroundShader(render_engine, scene.world)
|
||||
self.camera = Camera(render_engine, scene.camera, aspect_ratio)
|
||||
self.lights = []
|
||||
|
||||
# Collect infinite-extent light sources.
|
||||
# TODO: also get sun lamps inside group instances.
|
||||
for ob in scene.objects:
|
||||
if ob.type == 'LAMP' and ob.data.type == 'SUN':
|
||||
name = escape_name(ob.name)
|
||||
self.lights += [DistantDiskLamp(ob, name)]
|
||||
|
||||
def take_sample(self, render_engine, scene, time):
|
||||
self.camera.take_sample(render_engine, scene, time)
|
||||
def take_sample(self, render_engine, depsgraph, time):
|
||||
if render_engine.test_break():
|
||||
raise ExportCancelled()
|
||||
self.background_shader.take_sample(render_engine, depsgraph, time)
|
||||
|
||||
for light in self.lights:
|
||||
# Check if render is cancelled
|
||||
if render_engine.test_break():
|
||||
raise ExportCancelled()
|
||||
light.take_sample(render_engine, scene, time)
|
||||
def cleanup(self):
|
||||
pass
|
||||
|
||||
def export(self, render_engine, w):
|
||||
self.camera.export(render_engine, w)
|
||||
|
||||
w.write("World {\n")
|
||||
w.indent()
|
||||
|
||||
self.background_shader.export(render_engine, w)
|
||||
|
||||
for light in self.lights:
|
||||
light.export(render_engine, w)
|
||||
|
||||
w.unindent()
|
||||
w.write("}\n")
|
||||
|
||||
def cleanup(self):
|
||||
# For future use. This is run by the calling code when finished,
|
||||
# even if export did not succeed.
|
||||
pass
|
||||
|
||||
#================================================================
|
||||
|
||||
class Camera:
|
||||
def __init__(self, render_engine, ob, aspect_ratio):
|
||||
|
@ -58,25 +39,27 @@ class Camera:
|
|||
self.focal_distances = []
|
||||
self.xforms = []
|
||||
|
||||
def take_sample(self, render_engine, scene, time):
|
||||
def take_sample(self, render_engine, depsgraph, time):
|
||||
render_engine.update_stats("", "Psychopath: Collecting '{}' at time {}".format(self.ob.name, time))
|
||||
|
||||
# Fov
|
||||
if self.aspect_ratio >= 1.0:
|
||||
self.fovs += [degrees(self.ob.data.angle)]
|
||||
else:
|
||||
self.fovs += [degrees(2.0 * atan(tan(self.ob.data.angle * 0.5) * self.aspect_ratio))]
|
||||
self.fovs += [degrees(self.ob.data.angle_x)]
|
||||
|
||||
# Aperture radius
|
||||
self.aperture_radii += [self.ob.data.psychopath.aperture_radius]
|
||||
if self.ob.data.dof.use_dof:
|
||||
# TODO
|
||||
# # Aperture radius
|
||||
# self.aperture_radii += [self.ob.data.psychopath.aperture_radius]
|
||||
|
||||
# Dof distance
|
||||
if self.ob.data.dof_object == None:
|
||||
self.focal_distances += [self.ob.data.dof_distance]
|
||||
# Dof distance
|
||||
if self.ob.data.dof_object == None:
|
||||
self.focal_distances += [self.ob.data.dof_distance]
|
||||
else:
|
||||
# TODO: implement DoF object tracking here
|
||||
self.focal_distances += [0.0]
|
||||
print("WARNING: DoF object tracking not yet implemented.")
|
||||
else:
|
||||
# TODO: implement DoF object tracking here
|
||||
self.focal_distances += [0.0]
|
||||
print("WARNING: DoF object tracking not yet implemented.")
|
||||
self.aperture_radii += [0.0]
|
||||
self.focal_distances += [1.0]
|
||||
|
||||
# Transform
|
||||
mat = self.ob.matrix_world.copy()
|
||||
|
@ -84,6 +67,9 @@ class Camera:
|
|||
matz[2][2] = -1
|
||||
self.xforms += [(mat * matz).inverted()]
|
||||
|
||||
def cleanup(self):
|
||||
pass
|
||||
|
||||
def export(self, render_engine, w):
|
||||
render_engine.update_stats("", "Psychopath: Exporting %s" % self.ob.name)
|
||||
w.write("Camera {\n")
|
||||
|
@ -108,55 +94,24 @@ class Camera:
|
|||
class BackgroundShader:
|
||||
def __init__(self, render_engine, world):
|
||||
self.world = world
|
||||
self.color = []
|
||||
|
||||
def take_sample(self, render_engine, depsgraph, time):
|
||||
if self.world != None:
|
||||
self.color = (world.horizon_color[0], world.horizon_color[1], world.horizon_color[2])
|
||||
self.color += [(
|
||||
self.world.psychopath.background_color[0],
|
||||
self.world.psychopath.background_color[1],
|
||||
self.world.psychopath.background_color[2],
|
||||
)]
|
||||
|
||||
def export(self, render_engine, w):
|
||||
if self.world != None:
|
||||
w.write("BackgroundShader {\n")
|
||||
w.indent();
|
||||
w.write("Type [Color]\n")
|
||||
w.write("Color [rec709, %f %f %f]\n" % self.color)
|
||||
for c in self.color:
|
||||
w.write("Color [rec709, %f %f %f]\n" % c)
|
||||
w.unindent()
|
||||
w.write("}\n")
|
||||
|
||||
|
||||
class DistantDiskLamp:
|
||||
def __init__(self, ob, name):
|
||||
self.ob = ob
|
||||
self.name = name
|
||||
self.time_col = []
|
||||
self.time_dir = []
|
||||
self.time_rad = []
|
||||
|
||||
def take_sample(self, render_engine, scene, time):
|
||||
render_engine.update_stats("", "Psychopath: Collecting '{}' at time {}".format(self.ob.name, time))
|
||||
self.time_dir += [tuple(self.ob.matrix_world.to_3x3() * Vector((0, 0, -1)))]
|
||||
|
||||
if self.ob.data.psychopath.color_type == 'Rec709':
|
||||
self.time_col += [('Rec709', self.ob.data.color * self.ob.data.energy)]
|
||||
elif self.ob.data.psychopath.color_type == 'Blackbody':
|
||||
self.time_col += [('Blackbody', self.ob.data.psychopath.color_blackbody_temp, self.ob.data.energy)]
|
||||
elif self.ob.data.psychopath.color_type == 'ColorTemperature':
|
||||
self.time_col += [('ColorTemperature', self.ob.data.psychopath.color_blackbody_temp, self.ob.data.energy)]
|
||||
|
||||
self.time_rad += [self.ob.data.shadow_soft_size]
|
||||
|
||||
def export(self, render_engine, w):
|
||||
render_engine.update_stats("", "Psychopath: Exporting %s" % self.ob.name)
|
||||
w.write("DistantDiskLight $%s {\n" % self.name)
|
||||
w.indent()
|
||||
for direc in self.time_dir:
|
||||
w.write("Direction [%f %f %f]\n" % (direc[0], direc[1], direc[2]))
|
||||
for col in self.time_col:
|
||||
if col[0] == 'Rec709':
|
||||
w.write("Color [rec709, %f %f %f]\n" % (col[1][0], col[1][1], col[1][2]))
|
||||
elif col[0] == 'Blackbody':
|
||||
w.write("Color [blackbody, %f %f]\n" % (col[1], col[2]))
|
||||
elif col[0] == 'ColorTemperature':
|
||||
w.write("Color [color_temperature, %f %f]\n" % (col[1], col[2]))
|
||||
for rad in self.time_rad:
|
||||
w.write("Radius [%f]\n" % rad)
|
||||
|
||||
w.unindent()
|
||||
w.write("}\n")
|
||||
|
|
Loading…
Reference in New Issue
Block a user