Made samples per bucket configurable.

This commit is contained in:
Nathan Vegdahl 2016-10-16 14:55:00 -07:00
parent bb4e57795f
commit 0e8d708ff0
5 changed files with 54 additions and 40 deletions

View File

@ -40,6 +40,11 @@ class RenderPsychopathSettingsScene(PropertyGroup):
min=1, max=65536, default=16 min=1, max=65536, default=16
) )
max_samples_per_bucket = IntProperty(
name="Max Samples Per Bucket", description="How many samples to simultaneously calculate per thread; indirectly determines bucket size",
min=1, max=2**28, soft_max=2**16, default=4096
)
dicing_rate = FloatProperty( dicing_rate = FloatProperty(
name="Dicing Rate", description="The target microgeometry width in pixels", name="Dicing Rate", description="The target microgeometry width in pixels",
min=0.0001, max=100.0, soft_min=0.125, soft_max=1.0, default=0.25 min=0.0001, max=100.0, soft_min=0.125, soft_max=1.0, default=0.25
@ -86,24 +91,24 @@ class PsychopathMaterial(bpy.types.PropertyGroup):
items=[('Emit', 'Emit', ""), ('Lambert', 'Lambert', ""), ('GTR', 'GTR', "")], items=[('Emit', 'Emit', ""), ('Lambert', 'Lambert', ""), ('GTR', 'GTR', "")],
default="Lambert" default="Lambert"
) )
color = FloatVectorProperty( color = FloatVectorProperty(
name="Color", description="", name="Color", description="",
subtype='COLOR', subtype='COLOR',
min=0.0, soft_min=0.0, soft_max = 1.0, min=0.0, soft_min=0.0, soft_max = 1.0,
default=[0.8,0.8,0.8] default=[0.8,0.8,0.8]
) )
roughness = FloatProperty( roughness = FloatProperty(
name="Roughness", description="", name="Roughness", description="",
min=-1.0, max=1.0, soft_min=0.0, soft_max=1.0, default=0.1 min=-1.0, max=1.0, soft_min=0.0, soft_max=1.0, default=0.1
) )
tail_shape = FloatProperty( tail_shape = FloatProperty(
name="Tail Shape", description="", name="Tail Shape", description="",
min=0.0, max=8.0, soft_min=1.0, soft_max=3.0, default=2.0 min=0.0, max=8.0, soft_min=1.0, soft_max=3.0, default=2.0
) )
fresnel = FloatProperty( fresnel = FloatProperty(
name="Fresnel", description="", name="Fresnel", description="",
min=0.0, max=1.0, soft_min=0.0, soft_max=1.0, default=0.9 min=0.0, max=1.0, soft_min=0.0, soft_max=1.0, default=0.9

View File

@ -49,7 +49,7 @@ class PsychopathRender(bpy.types.RenderEngine):
return False return False
# TODO: figure out command line options # TODO: figure out command line options
args = ["-i", psy_filepath] args = ["--spb", str(scene.psychopath.max_samples_per_bucket), "-i", psy_filepath]
# Start Rendering! # Start Rendering!
try: try:

View File

@ -46,6 +46,9 @@ class RENDER_PT_psychopath_render_settings(PsychopathPanel, bpy.types.Panel):
col.prop(scene.psychopath, "shutter_start") col.prop(scene.psychopath, "shutter_start")
col.prop(scene.psychopath, "shutter_end") col.prop(scene.psychopath, "shutter_end")
col.label(text="Performance")
col.prop(scene.psychopath, "max_samples_per_bucket")
class RENDER_PT_psychopath_export_settings(PsychopathPanel, bpy.types.Panel): class RENDER_PT_psychopath_export_settings(PsychopathPanel, bpy.types.Panel):
bl_label = "Export Settings" bl_label = "Export Settings"
@ -66,14 +69,14 @@ class WORLD_PT_psychopath_background(PsychopathPanel, bpy.types.Panel):
bl_space_type = 'PROPERTIES' bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW' bl_region_type = 'WINDOW'
bl_context = "world" bl_context = "world"
@classmethod @classmethod
def poll(cls, context): def poll(cls, context):
return context.world and PsychopathPanel.poll(context) return context.world and PsychopathPanel.poll(context)
def draw(self, context): def draw(self, context):
layout = self.layout layout = self.layout
world = context.world world = context.world
layout.prop(world, "horizon_color", text="Color") layout.prop(world, "horizon_color", text="Color")
@ -131,22 +134,22 @@ class DATA_PT_psychopath_area_lamp(PsychopathPanel, bpy.types.Panel):
bl_space_type = 'PROPERTIES' bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW' bl_region_type = 'WINDOW'
bl_context = "data" bl_context = "data"
@classmethod @classmethod
def poll(cls, context): def poll(cls, context):
lamp = context.lamp lamp = context.lamp
engine = context.scene.render.engine engine = context.scene.render.engine
return (lamp and lamp.type == 'AREA') and (engine in cls.COMPAT_ENGINES) return (lamp and lamp.type == 'AREA') and (engine in cls.COMPAT_ENGINES)
def draw(self, context): def draw(self, context):
layout = self.layout layout = self.layout
lamp = context.lamp lamp = context.lamp
col = layout.column() col = layout.column()
col.row().prop(lamp, "shape", expand=True) col.row().prop(lamp, "shape", expand=True)
sub = col.row(align=True) sub = col.row(align=True)
if lamp.shape == 'SQUARE': if lamp.shape == 'SQUARE':
sub.prop(lamp, "size") sub.prop(lamp, "size")
elif lamp.shape == 'RECTANGLE': elif lamp.shape == 'RECTANGLE':
@ -159,19 +162,19 @@ class DATA_PT_psychopath_mesh(PsychopathPanel, bpy.types.Panel):
bl_space_type = 'PROPERTIES' bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW' bl_region_type = 'WINDOW'
bl_context = "data" bl_context = "data"
@classmethod @classmethod
def poll(cls, context): def poll(cls, context):
engine = context.scene.render.engine engine = context.scene.render.engine
return context.mesh and (engine in cls.COMPAT_ENGINES) return context.mesh and (engine in cls.COMPAT_ENGINES)
def draw(self, context): def draw(self, context):
layout = self.layout layout = self.layout
mesh = context.mesh mesh = context.mesh
layout.row().prop(mesh.psychopath, "is_subdivision_surface") layout.row().prop(mesh.psychopath, "is_subdivision_surface")
class MATERIAL_PT_psychopath_context_material(PsychopathPanel, bpy.types.Panel): class MATERIAL_PT_psychopath_context_material(PsychopathPanel, bpy.types.Panel):
bl_label = "" bl_label = ""
@ -179,42 +182,42 @@ class MATERIAL_PT_psychopath_context_material(PsychopathPanel, bpy.types.Panel):
bl_region_type = "WINDOW" bl_region_type = "WINDOW"
bl_context = "material" bl_context = "material"
bl_options = {'HIDE_HEADER'} bl_options = {'HIDE_HEADER'}
@classmethod @classmethod
def poll(cls, context): def poll(cls, context):
return (context.material or context.object) and PsychopathPanel.poll(context) return (context.material or context.object) and PsychopathPanel.poll(context)
def draw(self, context): def draw(self, context):
layout = self.layout layout = self.layout
mat = context.material mat = context.material
ob = context.object ob = context.object
slot = context.material_slot slot = context.material_slot
space = context.space_data space = context.space_data
if ob: if ob:
row = layout.row() row = layout.row()
row.template_list("MATERIAL_UL_matslots", "", ob, "material_slots", ob, "active_material_index", rows=1) row.template_list("MATERIAL_UL_matslots", "", ob, "material_slots", ob, "active_material_index", rows=1)
col = row.column(align=True) col = row.column(align=True)
col.operator("object.material_slot_add", icon='ZOOMIN', text="") col.operator("object.material_slot_add", icon='ZOOMIN', text="")
col.operator("object.material_slot_remove", icon='ZOOMOUT', text="") col.operator("object.material_slot_remove", icon='ZOOMOUT', text="")
col.menu("MATERIAL_MT_specials", icon='DOWNARROW_HLT', text="") col.menu("MATERIAL_MT_specials", icon='DOWNARROW_HLT', text="")
if ob.mode == 'EDIT': if ob.mode == 'EDIT':
row = layout.row(align=True) row = layout.row(align=True)
row.operator("object.material_slot_assign", text="Assign") row.operator("object.material_slot_assign", text="Assign")
row.operator("object.material_slot_select", text="Select") row.operator("object.material_slot_select", text="Select")
row.operator("object.material_slot_deselect", text="Deselect") row.operator("object.material_slot_deselect", text="Deselect")
split = layout.split(percentage=0.65) split = layout.split(percentage=0.65)
if ob: if ob:
split.template_ID(ob, "active_material", new="material.new") split.template_ID(ob, "active_material", new="material.new")
row = split.row() row = split.row()
if slot: if slot:
row.prop(slot, "link", text="") row.prop(slot, "link", text="")
else: else:
@ -229,18 +232,18 @@ class MATERIAL_PT_psychopath_surface(PsychopathPanel, bpy.types.Panel):
bl_space_type = "PROPERTIES" bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW" bl_region_type = "WINDOW"
bl_context = "material" bl_context = "material"
@classmethod @classmethod
def poll(cls, context): def poll(cls, context):
return context.material and PsychopathPanel.poll(context) return context.material and PsychopathPanel.poll(context)
def draw(self, context): def draw(self, context):
layout = self.layout layout = self.layout
mat = context.material mat = context.material
layout.prop(mat.psychopath, "surface_shader_type") layout.prop(mat.psychopath, "surface_shader_type")
layout.prop(mat.psychopath, "color") layout.prop(mat.psychopath, "color")
if mat.psychopath.surface_shader_type == 'GTR': if mat.psychopath.surface_shader_type == 'GTR':
layout.prop(mat.psychopath, "roughness") layout.prop(mat.psychopath, "roughness")
layout.prop(mat.psychopath, "tail_shape") layout.prop(mat.psychopath, "tail_shape")

View File

@ -72,6 +72,7 @@ Usage:
Options: Options:
-i <file>, --input <file> Input .psy file. -i <file>, --input <file> Input .psy file.
-s <n>, --spp <n> Number of samples per pixel. -s <n>, --spp <n> Number of samples per pixel.
-b <n>, --spb <n> Maxmimum number of samples per bucket (determines bucket size).
-t <n>, --threads <n> Number of threads to render with. Defaults -t <n>, --threads <n> Number of threads to render with. Defaults
to the number of logical cores on the system. to the number of logical cores on the system.
--dev Show useful dev/debug info. --dev Show useful dev/debug info.
@ -83,6 +84,7 @@ Options:
struct Args { struct Args {
flag_input: Option<String>, flag_input: Option<String>,
flag_spp: Option<usize>, flag_spp: Option<usize>,
flag_spb: Option<usize>,
flag_threads: Option<usize>, flag_threads: Option<usize>,
flag_dev: bool, flag_dev: bool,
flag_version: bool, flag_version: bool,
@ -141,6 +143,12 @@ fn main() {
r.spp = spp; r.spp = spp;
} }
let max_samples_per_bucket = if let Some(max_samples_per_bucket) = args.flag_spb {
max_samples_per_bucket as u32
} else {
4096
};
let thread_count = if let Some(threads) = args.flag_threads { let thread_count = if let Some(threads) = args.flag_threads {
threads as u32 threads as u32
} else { } else {
@ -150,7 +158,7 @@ fn main() {
println!("\tBuilt scene in {:.3}s", t.tick()); println!("\tBuilt scene in {:.3}s", t.tick());
println!("Rendering scene with {} threads...", thread_count); println!("Rendering scene with {} threads...", thread_count);
let mut image = r.render(thread_count); let mut image = r.render(max_samples_per_bucket, thread_count);
println!("\tRendered scene in {:.3}s", t.tick()); println!("\tRendered scene in {:.3}s", t.tick());
println!("Writing image to disk..."); println!("Writing image to disk...");

View File

@ -31,7 +31,7 @@ pub struct Renderer {
} }
impl Renderer { impl Renderer {
pub fn render(&self, thread_count: u32) -> Image { pub fn render(&self, max_samples_per_bucket: u32, thread_count: u32) -> Image {
let mut tpool = Pool::new(thread_count); let mut tpool = Pool::new(thread_count);
let image = Image::new(self.resolution.0, self.resolution.1); let image = Image::new(self.resolution.0, self.resolution.1);
@ -174,12 +174,10 @@ impl Renderer {
print!("0.00%"); print!("0.00%");
let _ = io::stdout().flush(); let _ = io::stdout().flush();
// Determine bucket size based on a target number of samples // Determine bucket size based on the per-thread maximum number of samples to
// per bucket. // calculate at a time.
// TODO: make target samples per bucket configurable
let target_samples_per_bucket = 1usize << 12;
let (bucket_w, bucket_h) = { let (bucket_w, bucket_h) = {
let target_pixels_per_bucket = target_samples_per_bucket as f64 / self.spp as f64; let target_pixels_per_bucket = max_samples_per_bucket as f64 / self.spp as f64;
let target_bucket_dim = if target_pixels_per_bucket.sqrt() < 1.0 { let target_bucket_dim = if target_pixels_per_bucket.sqrt() < 1.0 {
1usize 1usize
} else { } else {