class Material: def __init__(self): path = os.path.dirname(__file__) path = os.path.join(path, 'mat_shaders') self._loader = Loader([path]) self._bsdf_shader = None self._sampling_shader = None self._shader_name = None def is_emissive(self): if self._shader_name is None: return False return self._loader.exist(self._shader_name, 'emission.py') def _func_args(self, spectrum): func_args = [ StructArgPtr('hitpoint', HitPoint.factory()), StructArgPtr('shadepoint', ShadePoint.factory(spectrum)) ] return func_args def _load_args(self): args = [] text = self._loader.load(self._shader_name, 'props.txt') if text is not None: args = parse_args(text, self._color_mgr, image_factory=self._image_factory) return args def load(self, shader_name, color_mgr, image_factory=None): self._color_mgr = color_mgr self._shader_name = shader_name self._image_factory = image_factory code = self._loader.load(shader_name, 'bsdf.py') if code is None: raise ValueError("bsdf.py in %s doesnt exist!" % shader_name) args = self._load_args() name = 'material_%i' % id(args) s = color_mgr.zero() func_args = self._func_args(s) self._bsdf_shader = Shader(code=code, args=args, name=name, func_args=func_args, is_func=True) #Sampling shader code = self._loader.load(self._shader_name, 'sample.py') if code is None: code = self._default_sampling() args = self._load_args() ptr_mat_bsdf = PointerArg('ptr_mat_bsdf', 0) ptr_mat_pdf = PointerArg('ptr_mat_pdf', 0) ptr_bsdf = ArgList('ptr_mat_bsdf', [ptr_mat_bsdf]) ptr_pdf = ArgList('ptr_mat_pdf', [ptr_mat_pdf]) args.append(ptr_bsdf) args.append(ptr_pdf) name = 'material_sampling_%i' % id(args) func_args = self._func_args(s) self._sampling_shader = Shader(code=code, args=args, name=name, func_args=func_args, is_func=True) #material pdf code = self._loader.load(self._shader_name, 'pdf.py') if code is None: code = self._default_pdf() args = self._load_args() name = 'material_pdf_%i' % id(args) func_args = self._func_args(s) self._pdf_shader = Shader(code=code, args=args, name=name, func_args=func_args, is_func=True) def _default_sampling(self): code = """ r1 = random() r2 = random() e = 1.0 phi = 2.0 * 3.14159 * r1 exponent = 1.0 / (e + 1.0) cos_theta = pow(r2, exponent) tmp = 1.0 - cos_theta * cos_theta sin_theta = sqrt(tmp) sin_phi = sin(phi) cos_phi = cos(phi) pu = sin_theta * cos_phi pv = sin_theta * sin_phi pw = cos_theta w = hitpoint.normal tv = (0.0034, 1.0, 0.0071) v = cross(tv, w) v = normalize(v) u = cross(v, w) ndir = u * pu + v * pv + w * pw shadepoint.wi = normalize(ndir) __material_pdf(hitpoint, shadepoint, ptr_mat_pdf) __material_reflectance(hitpoint, shadepoint, ptr_mat_bsdf) """ return code def _default_pdf(self): code = """ shadepoint.pdf = dot(hitpoint.normal, shadepoint.wi) * 0.318309886 """ return code def compile(self, shaders=[]): self._bsdf_shader.compile(shaders, color_mgr=self._color_mgr) self._sampling_shader.compile(shaders, color_mgr=self._color_mgr) self._pdf_shader.compile(shaders, color_mgr=self._color_mgr) def prepare(self, runtimes): self._bsdf_shader.prepare(runtimes) self._pdf_shader.prepare(runtimes) ptrs = self._bsdf_shader.get_ptrs() args = [PointerArg('ptr_mat_bsdf', p) for p in ptrs] ptr_bsdf = self._sampling_shader._get_arg('ptr_mat_bsdf') ptr_bsdf.resize(args) ptrs = self._pdf_shader.get_ptrs() args = [PointerArg('ptr_mat_pdf', p) for p in ptrs] ptr_pdf = self._sampling_shader._get_arg('ptr_mat_pdf') ptr_pdf.resize(args) self._sampling_shader.prepare(runtimes) def emission_shader(self, shaders=[]): args = self._load_args() code = self._loader.load(self._shader_name, 'emission.py') if code is None: raise ValueError("emission.py in %s dont exist!" % self._shader_name) name = 'material_emission_%i' % id(args) s = self._color_mgr.zero() func_args = self._func_args(s) emission_shader = Shader(code=code, args=args, name=name, func_args=func_args, is_func=True) return emission_shader def sync_shader_props(self, shader): for arg in shader.args: val = self.get_value(arg.name) shader.set_value(arg.name, val) def set_value(self, name, val): if self._bsdf_shader is None: raise ValueError("Material shader is not loaded!") if isinstance(val, (RGBSpectrum, SampledSpectrum)): val = self._color_mgr.convert_spectrum(val) self._bsdf_shader.set_value(name, val) self._sampling_shader.set_value(name, val) self._pdf_shader.set_value(name, val) def get_value(self, name): if self._bsdf_shader is None: raise ValueError("Material shader is not loaded!") return self._bsdf_shader.get_value(name) def output(self, name): txt = 'Material\n' txt += 'type = %s\n' % self._shader_name txt += 'name = %s\n' % name args = self._load_args() for arg in args: value = self.get_value(arg.name) txt += output_arg(arg.name, value) txt += 'End\n' return txt
class AreaLight(Light): def __init__(self, shape, material): path = os.path.dirname(__file__) path = os.path.join(path, 'area_light_shaders') self._loader = Loader([path]) self.shape = shape self.material = material self.shader = None def _func_args(self, spectrum): func_args = [ StructArgPtr('hitpoint', HitPoint.factory()), StructArgPtr('shadepoint', ShadePoint.factory(spectrum)) ] return func_args def _load_args(self): args = [] text = self._loader.load(self._shader_name, 'props.txt') if text is not None: args = parse_args(text, self._color_mgr) return args def load(self, shader_name, color_mgr): self._color_mgr = color_mgr self._shader_name = shader_name args = self._load_args() ptr_lgt_sample = PointerArg('ptr_light_sample', 0) lgt_sample = ArgList('ptr_light_sample', [ptr_lgt_sample]) args.append(lgt_sample) ptr_mat_emission = PointerArg('ptr_mat_emission', 0) mat_emission = ArgList('ptr_mat_emission', [ptr_mat_emission]) args.append(mat_emission) code = self._loader.load(shader_name, 'code.py') if code is None: raise ValueError("code.py in %s shader dont exist!" % shader_name) name = 'light_%i' % id(args) func_args = self._func_args(color_mgr.zero()) self.shader = Shader(code=code, args=args, name=name, func_args=func_args, is_func=True) # area light emission shader name = 'light_emission%i' % id(args) func_args = self._func_args(color_mgr.zero()) args = [] ptr_lgt_pdf = PointerArg('ptr_light_pdf', 0) lgt_pdf = ArgList('ptr_light_pdf', [ptr_lgt_pdf]) args.append(lgt_pdf) ptr_mat_emission = PointerArg('ptr_mat_emission', 0) mat_emission = ArgList('ptr_mat_emission', [ptr_mat_emission]) args.append(mat_emission) code = """ __light_pdf(hitpoint, shadepoint, ptr_light_pdf) __material_emission(hitpoint, shadepoint, ptr_mat_emission) """ self.emission_shader = Shader(code=code, args=args, name=name, func_args=func_args, is_func=True) def compile(self, shaders=[]): self.shader.compile(shaders, color_mgr=self._color_mgr) self.emission_shader.compile(shaders, color_mgr=self._color_mgr) spec = self._color_mgr.zero() self.light_sample_shader = self.shape.light_sample(spec) self.light_sample_shader.compile(shaders, color_mgr=self._color_mgr) self.light_pdf_shader = self.shape.light_pdf(spec) self.light_pdf_shader.compile(shaders, color_mgr=self._color_mgr) self._emission_shader = self.material.emission_shader() self._emission_shader.compile(shaders, color_mgr=self._color_mgr) def prepare(self, runtimes): self.light_sample_shader.prepare(runtimes) ptrs = self.light_sample_shader.get_ptrs() args = [PointerArg('ptr_light_sample', p) for p in ptrs] lgt_sample = self.shader._get_arg('ptr_light_sample') lgt_sample.resize(args) self.light_pdf_shader.prepare(runtimes) ptrs = self.light_pdf_shader.get_ptrs() args = [PointerArg('ptr_light_pdf', p) for p in ptrs] lgt_pdf = self.emission_shader._get_arg('ptr_light_pdf') lgt_pdf.resize(args) self._emission_shader.prepare(runtimes) self.material.sync_shader_props(self._emission_shader) ptrs = self._emission_shader.get_ptrs() args = [PointerArg('ptr_mat_emission', p) for p in ptrs] ptr_emission = self.shader._get_arg('ptr_mat_emission') ptr_emission.resize(args) args = [PointerArg('ptr_mat_emission', p) for p in ptrs] ptr_emission = self.emission_shader._get_arg('ptr_mat_emission') ptr_emission.resize(args) self.shader.prepare(runtimes) self.emission_shader.prepare(runtimes) def get_value(self, name): if self.shader is None: raise ValueError("Light shader is not loaded!") return self.shader.get_value(name) def set_value(self, name, val): if self.shader is None: raise ValueError("Light shader is not loaded!") if isinstance(val, (RGBSpectrum, SampledSpectrum)): val = self._color_mgr.convert_spectrum(val, illum=True) self.shader.set_value(name, val)
class MaterialManager: def __init__(self): self._materials = [] self._materials_d = {} self._materials_idx = {} def add(self, name, material): if name in self._materials_d: raise ValueError("Material %s allready exist!" % name) if not isinstance(material, Material): raise ValueError("Type error. Material is expected!", material) self._materials_idx[len(self._materials)] = name self._materials.append(material) self._materials_d[name] = material def _func_args(self, spectrum): func_args = [ StructArgPtr('hitpoint', HitPoint.factory()), StructArgPtr('shadepoint', ShadePoint.factory(spectrum)), IntArg('mat_idx', 0) ] return func_args def _mtl_reflectance(self, color_mgr): code = """ ptr_func = mtl_ptrs[mat_idx] __material_reflectance(hitpoint, shadepoint, ptr_func) """ ref_ptrs = ArrayArg('mtl_ptrs', PtrsArray()) al = ArgList('mtl_ptrs', [ref_ptrs]) func_args = self._func_args(color_mgr.zero()) args = [al] self.ref_shader = Shader(code=code, args=args, name='material_reflectance', func_args=func_args, is_func=True) def _mtl_sampling(self, color_mgr): code = """ ptr_func = mtl_sampling_ptrs[mat_idx] __material_sampling(hitpoint, shadepoint, ptr_func) """ sampling_ptrs = ArrayArg('mtl_sampling_ptrs', PtrsArray()) al = ArgList('mtl_sampling_ptrs', [sampling_ptrs]) func_args = self._func_args(color_mgr.zero()) args = [al] self.sampling_shader = Shader(code=code, args=args, name='material_sampling', func_args=func_args, is_func=True) def _mtl_pdf(self, color_mgr): code = """ ptr_func = mtl_pdf_ptrs[mat_idx] __material_pdf(hitpoint, shadepoint, ptr_func) """ pdf_ptrs = ArrayArg('mtl_pdf_ptrs', PtrsArray()) al = ArgList('mtl_pdf_ptrs', [pdf_ptrs]) func_args = self._func_args(color_mgr.zero()) args = [al] self.pdf_shader = Shader(code=code, args=args, name='material_pdf', func_args=func_args, is_func=True) def compile_shaders(self, color_mgr, shaders=[]): for m in self._materials: m.compile(shaders) self._mtl_reflectance(color_mgr) self.ref_shader.compile(shaders, color_mgr=color_mgr) self._mtl_sampling(color_mgr) self.sampling_shader.compile(shaders, color_mgr=color_mgr) self._mtl_pdf(color_mgr) self.pdf_shader.compile(shaders, color_mgr=color_mgr) def prepare_shaders(self, runtimes): for m in self._materials: m.prepare(runtimes) args = self._pointer_args('_bsdf_shader', 'mtl_ptrs', runtimes) aal = self.ref_shader._get_arg('mtl_ptrs') aal.resize(args) self.ref_shader.prepare(runtimes) args = self._pointer_args('_sampling_shader', 'mtl_sampling_ptrs', runtimes) aal = self.sampling_shader._get_arg('mtl_sampling_ptrs') aal.resize(args) self.sampling_shader.prepare(runtimes) args = self._pointer_args('_pdf_shader', 'mtl_pdf_ptrs', runtimes) aal = self.pdf_shader._get_arg('mtl_pdf_ptrs') aal.resize(args) self.pdf_shader.prepare(runtimes) def _pointer_args(self, shader_name, arg_name, runtimes): ptrs = [] for m in self._materials: shader = getattr(m, shader_name) p = shader.get_ptrs() ptrs.append(p) args = [] for i in range(len(runtimes)): pa = PtrsArray() for v in ptrs: pa.append(v[i]) args.append(ArrayArg(arg_name, pa)) return args def index(self, name): if name not in self._materials_d: raise ValueError("Material %s doesn't exist!" % name) m = self._materials_d[name] return self._materials.index(m) def material(self, index=None, name=None): if index is None and name is None: raise ValueError("Index or Name of material is required") if name is not None: return self._materials_d[name] return self._materials[index] def name(self, index): return self._materials_idx[index] def output(self): txt = '' for index, mat in enumerate(self._materials): txt += mat.output(self.name(index)) + '\n' return txt
class LightManager: def __init__(self): self._lights = [] self._lights_d = {} self._env_light = None self.env_shader = None def add(self, name, light): if name in self._lights_d: raise ValueError("Light %s allready exist!" % name) if not isinstance(light, Light): raise ValueError("Type error. Light is expected!", light) #TODO -- implement check not to add environment light more than once if isinstance(light, EnvironmentLight): self._env_light = light else: self._lights.append(light) self._lights_d[name] = light def remove(self, name=None, light=None): if name is None and light is None: raise ValueError("Name or Light argument is required") if name is not None and name not in self._lights_d: raise ValueError("Light %s doesn't exist!" % name) if name is not None: light = self._lights_d[name] del self._lights_d[name] self._lights.remove(light) elif light is not None: for name in self._lights_d.keys(): if light is self._lights_d[name]: del self._lights_d[name] self._lights.remove(light) def light_idx(self, name): if name not in self._lights_d: raise ValueError("Light %s doesn't exist!" % name) light = self._lights_d[name] return self._lights.index(light) def _func_args(self, spectrum): func_args = [ StructArgPtr('hitpoint', HitPoint.factory()), StructArgPtr('shadepoint', ShadePoint.factory(spectrum)), IntArg('mat_idx', 0) ] return func_args def _lgt_radiance(self, color_mgr): code = """ ptr_func = lgt_ptrs[mat_idx] __light_radiance(hitpoint, shadepoint, ptr_func) """ lgt_ptrs = ArrayArg('lgt_ptrs', PtrsArray()) al = ArgList('lgt_ptrs', [lgt_ptrs]) func_args = self._func_args(color_mgr.zero()) args = [al] self.rad_shader = Shader(code=code, args=args, name='light_radiance', func_args=func_args, is_func=True) def _lgt_emission(self, color_mgr): code = """ if light_id < 0: shadepoint.light_intensity = Spectrum(0.0) shadepoint.light_pdf = 1.0 else: ptr_func = lgt_ptrs[light_id] __light_emission(hitpoint, shadepoint, ptr_func) """ lgt_ptrs = ArrayArg('lgt_ptrs', PtrsArray()) al = ArgList('lgt_ptrs', [lgt_ptrs]) spec = color_mgr.zero() func_args = [ StructArgPtr('hitpoint', HitPoint.factory()), StructArgPtr('shadepoint', ShadePoint.factory(spec)), IntArg('light_id', -1) ] args = [al] self.emission_shader = Shader(code=code, args=args, name='light_emission', func_args=func_args, is_func=True) def compile_shaders(self, color_mgr, shaders=[]): for l in self._lights: l.compile(shaders) self._lgt_radiance(color_mgr) self.rad_shader.compile(shaders, color_mgr=color_mgr) self._lgt_emission(color_mgr) self.emission_shader.compile(shaders, color_mgr=color_mgr) code = "return %i\n" % len(self._lights) self.nlights_shader = Shader(code=code, name='number_of_lights', is_func=True) self.nlights_shader.compile() self._compile_environment(color_mgr, shaders) def _compile_environment(self, color_mgr, shaders=[]): if self._env_light is not None: self.env_shader = self._env_light.env_shader self.env_shader.compile(shaders, color_mgr=color_mgr) return # We create dummy shader for environment emission code = ''' shadepoint.light_intensity = Spectrum(0.0) shadepoint.light_pdf = 1.0 ''' spec = color_mgr.zero() func_args = [ StructArgPtr('hitpoint', HitPoint.factory()), StructArgPtr('shadepoint', ShadePoint.factory(spec)) ] self.env_shader = Shader(code=code, name='environment_emission', func_args=func_args, is_func=True) self.env_shader.compile(shaders, color_mgr=color_mgr) def prepare_shaders(self, runtimes): for l in self._lights: l.prepare(runtimes) ptrs = [] for l in self._lights: p = l.shader.get_ptrs() ptrs.append(p) args = [] for i in range(len(runtimes)): pa = PtrsArray() for v in ptrs: pa.append(v[i]) args.append(ArrayArg('lgt_ptrs', pa)) aal = self.rad_shader._get_arg('lgt_ptrs') aal.resize(args) self.rad_shader.prepare(runtimes) self.nlights_shader.prepare(runtimes) self.env_shader.prepare(runtimes) ##### emission shader ptrs = [] for l in self._lights: if isinstance(l, AreaLight): p = l.emission_shader.get_ptrs() ptrs.append(p) args = [] for i in range(len(runtimes)): pa = PtrsArray() for v in ptrs: pa.append(v[i]) args.append(ArrayArg('lgt_ptrs', pa)) aal = self.emission_shader._get_arg('lgt_ptrs') aal.resize(args) self.emission_shader.prepare(runtimes) self.update_light_ids() def update_light_ids(self): idx = 0 for l in self._lights: if isinstance(l, AreaLight): l.shape.light_id = idx idx += 1 def shapes_to_update(self): shapes = [] for l in self._lights: if isinstance(l, AreaLight): shapes.append(l.shape) return shapes def arealight(self, shape): for light in self._lights: if isinstance(light, AreaLight) and light.shape is shape: return light return None def output(self): txt = '' for name, light in self._lights_d.items(): if isinstance(light, AreaLight): continue txt += light.output(name) + '\n' return txt
class Material: def __init__(self): path = os.path.dirname(__file__) path = os.path.join(path, 'mat_shaders') self._loader = Loader([path]) self._bsdf_shader = None self._sampling_shader = None self._shader_name = None def is_emissive(self): if self._shader_name is None: return False return self._loader.exist(self._shader_name, 'emission.py') def _func_args(self, spectrum): func_args = [StructArgPtr('hitpoint', HitPoint.factory()), StructArgPtr('shadepoint', ShadePoint.factory(spectrum))] return func_args def _load_args(self): args = [] text = self._loader.load(self._shader_name, 'props.txt') if text is not None: args = parse_args(text, self._color_mgr, image_factory=self._image_factory) return args def load(self, shader_name, color_mgr, image_factory=None): self._color_mgr = color_mgr self._shader_name = shader_name self._image_factory = image_factory code = self._loader.load(shader_name, 'bsdf.py') if code is None: raise ValueError("bsdf.py in %s doesnt exist!" % shader_name) args = self._load_args() name = 'material_%i' % id(args) s = color_mgr.zero() func_args = self._func_args(s) self._bsdf_shader = Shader(code=code, args=args, name=name, func_args=func_args, is_func=True) #Sampling shader code = self._loader.load(self._shader_name, 'sample.py') if code is None: code = self._default_sampling() args = self._load_args() ptr_mat_bsdf = PointerArg('ptr_mat_bsdf', 0) ptr_mat_pdf = PointerArg('ptr_mat_pdf', 0) ptr_bsdf = ArgList('ptr_mat_bsdf', [ptr_mat_bsdf]) ptr_pdf = ArgList('ptr_mat_pdf', [ptr_mat_pdf]) args.append(ptr_bsdf) args.append(ptr_pdf) name = 'material_sampling_%i' % id(args) func_args = self._func_args(s) self._sampling_shader = Shader(code=code, args=args, name=name, func_args=func_args, is_func=True) #material pdf code = self._loader.load(self._shader_name, 'pdf.py') if code is None: code = self._default_pdf() args = self._load_args() name = 'material_pdf_%i' % id(args) func_args = self._func_args(s) self._pdf_shader = Shader(code=code, args=args, name=name, func_args=func_args, is_func=True) def _default_sampling(self): code = """ r1 = random() r2 = random() e = 1.0 phi = 2.0 * 3.14159 * r1 exponent = 1.0 / (e + 1.0) cos_theta = pow(r2, exponent) tmp = 1.0 - cos_theta * cos_theta sin_theta = sqrt(tmp) sin_phi = sin(phi) cos_phi = cos(phi) pu = sin_theta * cos_phi pv = sin_theta * sin_phi pw = cos_theta w = hitpoint.normal tv = (0.0034, 1.0, 0.0071) v = cross(tv, w) v = normalize(v) u = cross(v, w) ndir = u * pu + v * pv + w * pw shadepoint.wi = normalize(ndir) __material_pdf(hitpoint, shadepoint, ptr_mat_pdf) __material_reflectance(hitpoint, shadepoint, ptr_mat_bsdf) """ return code def _default_pdf(self): code = """ shadepoint.pdf = dot(hitpoint.normal, shadepoint.wi) * 0.318309886 """ return code def compile(self, shaders=[]): self._bsdf_shader.compile(shaders, color_mgr=self._color_mgr) self._sampling_shader.compile(shaders, color_mgr=self._color_mgr) self._pdf_shader.compile(shaders, color_mgr=self._color_mgr) def prepare(self, runtimes): self._bsdf_shader.prepare(runtimes) self._pdf_shader.prepare(runtimes) ptrs = self._bsdf_shader.get_ptrs() args = [PointerArg('ptr_mat_bsdf', p) for p in ptrs] ptr_bsdf = self._sampling_shader._get_arg('ptr_mat_bsdf') ptr_bsdf.resize(args) ptrs = self._pdf_shader.get_ptrs() args = [PointerArg('ptr_mat_pdf', p) for p in ptrs] ptr_pdf = self._sampling_shader._get_arg('ptr_mat_pdf') ptr_pdf.resize(args) self._sampling_shader.prepare(runtimes) def emission_shader(self, shaders=[]): args = self._load_args() code = self._loader.load(self._shader_name, 'emission.py') if code is None: raise ValueError("emission.py in %s dont exist!" % self._shader_name) name = 'material_emission_%i' % id(args) s = self._color_mgr.zero() func_args = self._func_args(s) emission_shader = Shader(code=code, args=args, name=name, func_args=func_args, is_func=True) return emission_shader def sync_shader_props(self, shader): for arg in shader.args: val = self.get_value(arg.name) shader.set_value(arg.name, val) def set_value(self, name, val): if self._bsdf_shader is None: raise ValueError("Material shader is not loaded!") if isinstance(val, (RGBSpectrum, SampledSpectrum)): val = self._color_mgr.convert_spectrum(val) self._bsdf_shader.set_value(name, val) self._sampling_shader.set_value(name, val) self._pdf_shader.set_value(name, val) def get_value(self, name): if self._bsdf_shader is None: raise ValueError("Material shader is not loaded!") return self._bsdf_shader.get_value(name) def output(self, name): txt = 'Material\n' txt += 'type = %s\n' % self._shader_name txt += 'name = %s\n' % name args = self._load_args() for arg in args: value = self.get_value(arg.name) txt += output_arg(arg.name, value) txt += 'End\n' return txt
class MaterialManager: def __init__(self): self._materials = [] self._materials_d = {} self._materials_idx = {} def add(self, name, material): if name in self._materials_d: raise ValueError("Material %s allready exist!" % name) if not isinstance(material, Material): raise ValueError("Type error. Material is expected!", material) self._materials_idx[len(self._materials)] = name self._materials.append(material) self._materials_d[name] = material def _func_args(self, spectrum): func_args = [StructArgPtr('hitpoint', HitPoint.factory()), StructArgPtr('shadepoint', ShadePoint.factory(spectrum)), IntArg('mat_idx', 0)] return func_args def _mtl_reflectance(self, color_mgr): code = """ ptr_func = mtl_ptrs[mat_idx] __material_reflectance(hitpoint, shadepoint, ptr_func) """ ref_ptrs = ArrayArg('mtl_ptrs', PtrsArray()) al = ArgList('mtl_ptrs', [ref_ptrs]) func_args = self._func_args(color_mgr.zero()) args = [al] self.ref_shader = Shader(code=code, args=args, name='material_reflectance', func_args=func_args, is_func=True) def _mtl_sampling(self, color_mgr): code = """ ptr_func = mtl_sampling_ptrs[mat_idx] __material_sampling(hitpoint, shadepoint, ptr_func) """ sampling_ptrs = ArrayArg('mtl_sampling_ptrs', PtrsArray()) al = ArgList('mtl_sampling_ptrs', [sampling_ptrs]) func_args = self._func_args(color_mgr.zero()) args = [al] self.sampling_shader = Shader(code=code, args=args, name='material_sampling', func_args=func_args, is_func=True) def _mtl_pdf(self, color_mgr): code = """ ptr_func = mtl_pdf_ptrs[mat_idx] __material_pdf(hitpoint, shadepoint, ptr_func) """ pdf_ptrs = ArrayArg('mtl_pdf_ptrs', PtrsArray()) al = ArgList('mtl_pdf_ptrs', [pdf_ptrs]) func_args = self._func_args(color_mgr.zero()) args = [al] self.pdf_shader = Shader(code=code, args=args, name='material_pdf', func_args=func_args, is_func=True) def compile_shaders(self, color_mgr, shaders=[]): for m in self._materials: m.compile(shaders) self._mtl_reflectance(color_mgr) self.ref_shader.compile(shaders, color_mgr=color_mgr) self._mtl_sampling(color_mgr) self.sampling_shader.compile(shaders, color_mgr=color_mgr) self._mtl_pdf(color_mgr) self.pdf_shader.compile(shaders, color_mgr=color_mgr) def prepare_shaders(self, runtimes): for m in self._materials: m.prepare(runtimes) args = self._pointer_args('_bsdf_shader', 'mtl_ptrs', runtimes) aal = self.ref_shader._get_arg('mtl_ptrs') aal.resize(args) self.ref_shader.prepare(runtimes) args = self._pointer_args('_sampling_shader', 'mtl_sampling_ptrs', runtimes) aal = self.sampling_shader._get_arg('mtl_sampling_ptrs') aal.resize(args) self.sampling_shader.prepare(runtimes) args = self._pointer_args('_pdf_shader', 'mtl_pdf_ptrs', runtimes) aal = self.pdf_shader._get_arg('mtl_pdf_ptrs') aal.resize(args) self.pdf_shader.prepare(runtimes) def _pointer_args(self, shader_name, arg_name, runtimes): ptrs = [] for m in self._materials: shader = getattr(m, shader_name) p = shader.get_ptrs() ptrs.append(p) args = [] for i in range(len(runtimes)): pa = PtrsArray() for v in ptrs: pa.append(v[i]) args.append(ArrayArg(arg_name, pa)) return args def index(self, name): if name not in self._materials_d: raise ValueError("Material %s doesn't exist!" % name) m = self._materials_d[name] return self._materials.index(m) def material(self, index=None, name=None): if index is None and name is None: raise ValueError("Index or Name of material is required") if name is not None: return self._materials_d[name] return self._materials[index] def name(self, index): return self._materials_idx[index] def output(self): txt = '' for index, mat in enumerate(self._materials): txt += mat.output(self.name(index)) + '\n' return txt
class AreaLight(Light): def __init__(self, shape, material): path = os.path.dirname(__file__) path = os.path.join(path, 'area_light_shaders') self._loader = Loader([path]) self.shape = shape self.material = material self.shader = None def _func_args(self, spectrum): func_args = [StructArgPtr('hitpoint', HitPoint.factory()), StructArgPtr('shadepoint', ShadePoint.factory(spectrum))] return func_args def _load_args(self): args = [] text = self._loader.load(self._shader_name, 'props.txt') if text is not None: args = parse_args(text, self._color_mgr) return args def load(self, shader_name, color_mgr): self._color_mgr = color_mgr self._shader_name = shader_name args = self._load_args() ptr_lgt_sample = PointerArg('ptr_light_sample', 0) lgt_sample = ArgList('ptr_light_sample', [ptr_lgt_sample]) args.append(lgt_sample) ptr_mat_emission = PointerArg('ptr_mat_emission', 0) mat_emission = ArgList('ptr_mat_emission', [ptr_mat_emission]) args.append(mat_emission) code = self._loader.load(shader_name, 'code.py') if code is None: raise ValueError("code.py in %s shader dont exist!" % shader_name) name = 'light_%i' % id(args) func_args = self._func_args(color_mgr.zero()) self.shader = Shader(code=code, args=args, name=name, func_args=func_args, is_func=True) # area light emission shader name = 'light_emission%i' % id(args) func_args = self._func_args(color_mgr.zero()) args = [] ptr_lgt_pdf = PointerArg('ptr_light_pdf', 0) lgt_pdf = ArgList('ptr_light_pdf', [ptr_lgt_pdf]) args.append(lgt_pdf) ptr_mat_emission = PointerArg('ptr_mat_emission', 0) mat_emission = ArgList('ptr_mat_emission', [ptr_mat_emission]) args.append(mat_emission) code = """ __light_pdf(hitpoint, shadepoint, ptr_light_pdf) __material_emission(hitpoint, shadepoint, ptr_mat_emission) """ self.emission_shader = Shader(code=code, args=args, name=name, func_args=func_args, is_func=True) def compile(self, shaders=[]): self.shader.compile(shaders, color_mgr=self._color_mgr) self.emission_shader.compile(shaders, color_mgr=self._color_mgr) spec = self._color_mgr.zero() self.light_sample_shader = self.shape.light_sample(spec) self.light_sample_shader.compile(shaders, color_mgr=self._color_mgr) self.light_pdf_shader = self.shape.light_pdf(spec) self.light_pdf_shader.compile(shaders, color_mgr=self._color_mgr) self._emission_shader = self.material.emission_shader() self._emission_shader.compile(shaders, color_mgr=self._color_mgr) def prepare(self, runtimes): self.light_sample_shader.prepare(runtimes) ptrs = self.light_sample_shader.get_ptrs() args = [PointerArg('ptr_light_sample', p) for p in ptrs] lgt_sample = self.shader._get_arg('ptr_light_sample') lgt_sample.resize(args) self.light_pdf_shader.prepare(runtimes) ptrs = self.light_pdf_shader.get_ptrs() args = [PointerArg('ptr_light_pdf', p) for p in ptrs] lgt_pdf = self.emission_shader._get_arg('ptr_light_pdf') lgt_pdf.resize(args) self._emission_shader.prepare(runtimes) self.material.sync_shader_props(self._emission_shader) ptrs = self._emission_shader.get_ptrs() args = [PointerArg('ptr_mat_emission', p) for p in ptrs] ptr_emission = self.shader._get_arg('ptr_mat_emission') ptr_emission.resize(args) args = [PointerArg('ptr_mat_emission', p) for p in ptrs] ptr_emission = self.emission_shader._get_arg('ptr_mat_emission') ptr_emission.resize(args) self.shader.prepare(runtimes) self.emission_shader.prepare(runtimes) def get_value(self, name): if self.shader is None: raise ValueError("Light shader is not loaded!") return self.shader.get_value(name) def set_value(self, name, val): if self.shader is None: raise ValueError("Light shader is not loaded!") if isinstance(val, (RGBSpectrum, SampledSpectrum)): val = self._color_mgr.convert_spectrum(val, illum=True) self.shader.set_value(name, val)
class LightManager: def __init__(self): self._lights = [] self._lights_d = {} self._env_light = None self.env_shader = None def add(self, name, light): if name in self._lights_d: raise ValueError("Light %s allready exist!" % name) if not isinstance(light, Light): raise ValueError("Type error. Light is expected!", light) #TODO -- implement check not to add environment light more than once if isinstance(light, EnvironmentLight): self._env_light = light else: self._lights.append(light) self._lights_d[name] = light def remove(self, name=None, light=None): if name is None and light is None: raise ValueError("Name or Light argument is required") if name is not None and name not in self._lights_d: raise ValueError("Light %s doesn't exist!" % name) if name is not None: light = self._lights_d[name] del self._lights_d[name] self._lights.remove(light) elif light is not None: for name in self._lights_d.keys(): if light is self._lights_d[name]: del self._lights_d[name] self._lights.remove(light) def light_idx(self, name): if name not in self._lights_d: raise ValueError("Light %s doesn't exist!" % name) light = self._lights_d[name] return self._lights.index(light) def _func_args(self, spectrum): func_args = [StructArgPtr('hitpoint', HitPoint.factory()), StructArgPtr('shadepoint', ShadePoint.factory(spectrum)), IntArg('mat_idx', 0)] return func_args def _lgt_radiance(self, color_mgr): code = """ ptr_func = lgt_ptrs[mat_idx] __light_radiance(hitpoint, shadepoint, ptr_func) """ lgt_ptrs = ArrayArg('lgt_ptrs', PtrsArray()) al = ArgList('lgt_ptrs', [lgt_ptrs]) func_args = self._func_args(color_mgr.zero()) args = [al] self.rad_shader = Shader(code=code, args=args, name='light_radiance', func_args=func_args, is_func=True) def _lgt_emission(self, color_mgr): code = """ if light_id < 0: shadepoint.light_intensity = Spectrum(0.0) shadepoint.light_pdf = 1.0 else: ptr_func = lgt_ptrs[light_id] __light_emission(hitpoint, shadepoint, ptr_func) """ lgt_ptrs = ArrayArg('lgt_ptrs', PtrsArray()) al = ArgList('lgt_ptrs', [lgt_ptrs]) spec = color_mgr.zero() func_args = [StructArgPtr('hitpoint', HitPoint.factory()), StructArgPtr('shadepoint', ShadePoint.factory(spec)), IntArg('light_id', -1)] args = [al] self.emission_shader = Shader(code=code, args=args, name='light_emission', func_args=func_args, is_func=True) def compile_shaders(self, color_mgr, shaders=[]): for l in self._lights: l.compile(shaders) self._lgt_radiance(color_mgr) self.rad_shader.compile(shaders, color_mgr=color_mgr) self._lgt_emission(color_mgr) self.emission_shader.compile(shaders, color_mgr=color_mgr) code = "return %i\n" % len(self._lights) self.nlights_shader = Shader(code=code, name='number_of_lights', is_func=True) self.nlights_shader.compile() self._compile_environment(color_mgr, shaders) def _compile_environment(self, color_mgr, shaders=[]): if self._env_light is not None: self.env_shader = self._env_light.env_shader self.env_shader.compile(shaders, color_mgr=color_mgr) return # We create dummy shader for environment emission code = ''' shadepoint.light_intensity = Spectrum(0.0) shadepoint.light_pdf = 1.0 ''' spec = color_mgr.zero() func_args = [StructArgPtr('hitpoint', HitPoint.factory()), StructArgPtr('shadepoint', ShadePoint.factory(spec))] self.env_shader = Shader(code=code, name='environment_emission', func_args=func_args, is_func=True) self.env_shader.compile(shaders, color_mgr=color_mgr) def prepare_shaders(self, runtimes): for l in self._lights: l.prepare(runtimes) ptrs = [] for l in self._lights: p = l.shader.get_ptrs() ptrs.append(p) args = [] for i in range(len(runtimes)): pa = PtrsArray() for v in ptrs: pa.append(v[i]) args.append(ArrayArg('lgt_ptrs', pa)) aal = self.rad_shader._get_arg('lgt_ptrs') aal.resize(args) self.rad_shader.prepare(runtimes) self.nlights_shader.prepare(runtimes) self.env_shader.prepare(runtimes) ##### emission shader ptrs = [] for l in self._lights: if isinstance(l, AreaLight): p = l.emission_shader.get_ptrs() ptrs.append(p) args = [] for i in range(len(runtimes)): pa = PtrsArray() for v in ptrs: pa.append(v[i]) args.append(ArrayArg('lgt_ptrs', pa)) aal = self.emission_shader._get_arg('lgt_ptrs') aal.resize(args) self.emission_shader.prepare(runtimes) self.update_light_ids() def update_light_ids(self): idx = 0 for l in self._lights: if isinstance(l, AreaLight): l.shape.light_id = idx idx += 1 def shapes_to_update(self): shapes = [] for l in self._lights: if isinstance(l, AreaLight): shapes.append(l.shape) return shapes def arealight(self, shape): for light in self._lights: if isinstance(light, AreaLight) and light.shape is shape: return light return None def output(self): txt = '' for name, light in self._lights_d.items(): if isinstance(light, AreaLight): continue txt += light.output(name) + '\n' return txt