void InputBinder::build_assembly_symbol_table( const Assembly& assembly, SymbolTable& symbols) { try { insert_entities(symbols, assembly.colors(), SymbolTable::SymbolColor); insert_entities(symbols, assembly.textures(), SymbolTable::SymbolTexture); insert_entities(symbols, assembly.texture_instances(), SymbolTable::SymbolTextureInstance); insert_entities(symbols, assembly.bsdfs(), SymbolTable::SymbolBSDF); insert_entities(symbols, assembly.bssrdfs(), SymbolTable::SymbolBSSRDF); insert_entities(symbols, assembly.edfs(), SymbolTable::SymbolEDF); #ifdef APPLESEED_WITH_OSL insert_entities(symbols, assembly.shader_groups(), SymbolTable::SymbolShaderGroup); #endif insert_entities(symbols, assembly.surface_shaders(), SymbolTable::SymbolSurfaceShader); insert_entities(symbols, assembly.materials(), SymbolTable::SymbolMaterial); insert_entities(symbols, assembly.lights(), SymbolTable::SymbolLight); insert_entities(symbols, assembly.objects(), SymbolTable::SymbolObject); insert_entities(symbols, assembly.object_instances(), SymbolTable::SymbolObjectInstance); } catch (const SymbolTable::ExceptionDuplicateSymbol& e) { RENDERER_LOG_ERROR("duplicate entity \"%s\".", e.string()); ++m_error_count; } }
AssemblyItem::AssemblyItem( Assembly& assembly, BaseGroup& parent, BaseGroupItem* parent_item, ProjectBuilder& project_builder, ParamArray& settings) : BaseGroupItem(g_class_uid, assembly, project_builder, settings) , m_assembly(assembly) , m_parent(parent) , m_parent_item(parent_item) , m_project_builder(project_builder) { set_title(QString::fromAscii(assembly.get_name())); set_allow_edition(false); insertChild( 3, m_bsdf_collection_item = add_multi_model_collection_item<BSDF>(assembly.bsdfs())); insertChild( 4, m_edf_collection_item = add_multi_model_collection_item<EDF>(assembly.edfs())); insertChild( 5, m_surface_shader_collection_item = add_multi_model_collection_item<SurfaceShader>(assembly.surface_shaders())); insertChild( 6, m_material_collection_item = add_multi_model_collection_item<Material>(assembly.materials())); insertChild( 7, m_light_collection_item = add_multi_model_collection_item<Light>(assembly.lights())); insertChild( 8, m_object_collection_item = new ObjectCollectionItem( assembly.objects(), assembly, this, project_builder, settings)); insertChild( 9, m_object_instance_collection_item = new ObjectInstanceCollectionItem( new_guid(), EntityTraits<ObjectInstance>::get_human_readable_collection_type_name(), assembly, project_builder)); m_object_instance_collection_item->add_items(assembly.object_instances()); }
void collect_relations_from_assembly(Assembly& assembly) { collect_relations_from(assembly.colors()); collect_relations_from(assembly.textures()); collect_relations_from(assembly.texture_instances()); collect_relations_from(assembly.shader_groups()); collect_relations_from(assembly.assembly_instances()); collect_relations_from(assembly.bsdfs()); collect_relations_from(assembly.bssrdfs()); collect_relations_from(assembly.edfs()); collect_relations_from(assembly.surface_shaders()); collect_relations_from(assembly.materials()); collect_relations_from(assembly.lights()); collect_relations_from(assembly.objects()); collect_relations_from(assembly.object_instances()); collect_relations_from(assembly.volumes()); for (auto& child_assembly : assembly.assemblies()) collect_relations_from_assembly(child_assembly); // Lights are implicitly referenced by their parent assembly. for (auto& light : assembly.lights()) { const InputBinder::ReferencedEntity referenced_entity(assembly.lights(), &light); insert_relation(referenced_entity, assembly); } // Object instances are implicitly referenced by their parent assembly. for (auto& object_instance : assembly.object_instances()) { const InputBinder::ReferencedEntity referenced_entity(assembly.object_instances(), &object_instance); insert_relation(referenced_entity, assembly); } // Assembly instances are implicitly referenced by their parent assembly. for (auto& assembly_instance : assembly.assembly_instances()) { const InputBinder::ReferencedEntity referenced_entity(assembly.assembly_instances(), &assembly_instance); insert_relation(referenced_entity, assembly); } }
void finalize_assembly(Assembly& assembly) override { // Insert the baked mesh object into the assembly. assembly.objects().insert(auto_release_ptr<Object>(m_mesh)); // Instantiate the baked mesh object. assembly.object_instances().insert( ObjectInstanceFactory::create( "cubes_instance", ParamArray(), "cubes", Transformd::identity(), StringDictionary() .insert("default", "cubes_material"))); }
void remove_unused_entities_from_assembly(Assembly& assembly) { remove_unused_entities_from(assembly.colors()); remove_unused_entities_from(assembly.textures()); remove_unused_entities_from(assembly.texture_instances()); remove_unused_entities_from(assembly.shader_groups()); remove_unused_entities_from(assembly.assembly_instances()); remove_unused_entities_from(assembly.bsdfs()); remove_unused_entities_from(assembly.bssrdfs()); remove_unused_entities_from(assembly.edfs()); remove_unused_entities_from(assembly.surface_shaders()); remove_unused_entities_from(assembly.materials()); remove_unused_entities_from(assembly.lights()); remove_unused_entities_from(assembly.objects()); remove_unused_entities_from(assembly.object_instances()); remove_unused_entities_from(assembly.volumes()); for (auto& child_assembly : assembly.assemblies()) remove_unused_entities_from_assembly(child_assembly); }
void AssemblyTree::collect_regions(const Assembly& assembly, RegionInfoVector& regions) const { assert(regions.empty()); const ObjectInstanceContainer& object_instances = assembly.object_instances(); const size_t object_instance_count = object_instances.size(); // Collect all regions of all object instances of this assembly. for (size_t obj_inst_index = 0; obj_inst_index < object_instance_count; ++obj_inst_index) { // Retrieve the object instance and its transformation. const ObjectInstance* object_instance = object_instances.get_by_index(obj_inst_index); assert(object_instance); const Transformd& transform = object_instance->get_transform(); // Retrieve the object. Object& object = object_instance->get_object(); // Retrieve the region kit of the object. Access<RegionKit> region_kit(&object.get_region_kit()); // Collect all regions of the object. for (size_t region_index = 0; region_index < region_kit->size(); ++region_index) { // Retrieve the region. const IRegion* region = (*region_kit)[region_index]; // Compute the assembly space bounding box of the region. const GAABB3 region_bbox = transform.transform_to_parent(region->get_local_bbox()); regions.push_back( RegionInfo( obj_inst_index, region_index, region_bbox)); } } }
void LightSampler::collect_emitting_triangles( const Assembly& assembly, const AssemblyInstance& assembly_instance) { // Loop over the object instances of the assembly. const size_t object_instance_count = assembly.object_instances().size(); for (size_t object_instance_index = 0; object_instance_index < object_instance_count; ++object_instance_index) { // Retrieve the object instance. const ObjectInstance* object_instance = assembly.object_instances().get_by_index(object_instance_index); // Retrieve the materials of the object instance. const MaterialArray& front_materials = object_instance->get_front_materials(); const MaterialArray& back_materials = object_instance->get_back_materials(); // Skip object instances without light-emitting materials. if (!has_emitting_materials(front_materials) && !has_emitting_materials(back_materials)) continue; // Compute the object space to world space transformation. // todo: add support for moving light-emitters. const Transformd& object_instance_transform = object_instance->get_transform(); const Transformd assembly_instance_transform = assembly_instance.transform_sequence().empty() ? Transformd::identity() : assembly_instance.transform_sequence().earliest_transform(); const Transformd global_transform = assembly_instance_transform * object_instance_transform; // Retrieve the object. Object& object = object_instance->get_object(); // Retrieve the region kit of the object. Access<RegionKit> region_kit(&object.get_region_kit()); // Loop over the regions of the object. const size_t region_count = region_kit->size(); for (size_t region_index = 0; region_index < region_count; ++region_index) { // Retrieve the region. const IRegion* region = (*region_kit)[region_index]; // Retrieve the tessellation of the region. Access<StaticTriangleTess> tess(®ion->get_static_triangle_tess()); // Loop over the triangles of the region. const size_t triangle_count = tess->m_primitives.size(); for (size_t triangle_index = 0; triangle_index < triangle_count; ++triangle_index) { // Fetch the triangle. const Triangle& triangle = tess->m_primitives[triangle_index]; // Skip triangles without a material. if (triangle.m_pa == Triangle::None) continue; // Fetch the materials assigned to this triangle. const size_t pa_index = static_cast<size_t>(triangle.m_pa); const Material* front_material = pa_index < front_materials.size() ? front_materials[pa_index] : 0; const Material* back_material = pa_index < back_materials.size() ? back_materials[pa_index] : 0; // Skip triangles that don't emit light. if ((front_material == 0 || front_material->get_uncached_edf() == 0) && (back_material == 0 || back_material->get_uncached_edf() == 0)) continue; // Retrieve object instance space vertices of the triangle. const GVector3& v0_os = tess->m_vertices[triangle.m_v0]; const GVector3& v1_os = tess->m_vertices[triangle.m_v1]; const GVector3& v2_os = tess->m_vertices[triangle.m_v2]; // Transform triangle vertices to assembly space. const GVector3 v0_as = object_instance_transform.point_to_parent(v0_os); const GVector3 v1_as = object_instance_transform.point_to_parent(v1_os); const GVector3 v2_as = object_instance_transform.point_to_parent(v2_os); // Compute the support plane of the hit triangle in assembly space. const GTriangleType triangle_geometry(v0_as, v1_as, v2_as); TriangleSupportPlaneType triangle_support_plane; triangle_support_plane.initialize(TriangleType(triangle_geometry)); // Transform triangle vertices to world space. const Vector3d v0(assembly_instance_transform.point_to_parent(v0_as)); const Vector3d v1(assembly_instance_transform.point_to_parent(v1_as)); const Vector3d v2(assembly_instance_transform.point_to_parent(v2_as)); // Compute the geometric normal to the triangle and the area of the triangle. Vector3d geometric_normal = cross(v1 - v0, v2 - v0); const double geometric_normal_norm = norm(geometric_normal); if (geometric_normal_norm == 0.0) continue; const double rcp_geometric_normal_norm = 1.0 / geometric_normal_norm; const double rcp_area = 2.0 * rcp_geometric_normal_norm; const double area = 0.5 * geometric_normal_norm; geometric_normal *= rcp_geometric_normal_norm; assert(is_normalized(geometric_normal)); // Retrieve object instance space vertex normals. const GVector3& n0_os = tess->m_vertex_normals[triangle.m_n0]; const GVector3& n1_os = tess->m_vertex_normals[triangle.m_n1]; const GVector3& n2_os = tess->m_vertex_normals[triangle.m_n2]; // Transform vertex normals to world space. const Vector3d n0(normalize(global_transform.normal_to_parent(n0_os))); const Vector3d n1(normalize(global_transform.normal_to_parent(n1_os))); const Vector3d n2(normalize(global_transform.normal_to_parent(n2_os))); for (size_t side = 0; side < 2; ++side) { const Material* material = side == 0 ? front_material : back_material; const Vector3d side_geometric_normal = side == 0 ? geometric_normal : -geometric_normal; const Vector3d side_n0 = side == 0 ? n0 : -n0; const Vector3d side_n1 = side == 0 ? n1 : -n1; const Vector3d side_n2 = side == 0 ? n2 : -n2; // Skip sides without a material. if (material == 0) continue; const EDF* edf = material->get_uncached_edf(); // Skip sides without a light-emitting material. if (edf == 0) continue; // Create a light-emitting triangle. EmittingTriangle emitting_triangle; emitting_triangle.m_assembly_instance = &assembly_instance; emitting_triangle.m_object_instance_index = object_instance_index; emitting_triangle.m_region_index = region_index; emitting_triangle.m_triangle_index = triangle_index; emitting_triangle.m_v0 = v0; emitting_triangle.m_v1 = v1; emitting_triangle.m_v2 = v2; emitting_triangle.m_n0 = side_n0; emitting_triangle.m_n1 = side_n1; emitting_triangle.m_n2 = side_n2; emitting_triangle.m_geometric_normal = side_geometric_normal; emitting_triangle.m_triangle_support_plane = triangle_support_plane; emitting_triangle.m_rcp_area = rcp_area; emitting_triangle.m_edf = edf; // Store the light-emitting triangle. const size_t emitting_triangle_index = m_emitting_triangles.size(); m_emitting_triangles.push_back(emitting_triangle); // Insert the light-emitting triangle into the CDFs. m_emitter_cdf.insert(emitting_triangle_index + m_lights.size(), area); m_emitting_triangle_cdf.insert(emitting_triangle_index, area); // Keep track of the total area of the light-emitting triangles. m_total_emissive_area += area; } } } } }
bool InputBinder::try_bind_assembly_entity_to_input( const Scene& scene, const SymbolTable& scene_symbols, const Assembly& assembly, const SymbolTable& assembly_symbols, const char* entity_type, const char* entity_name, const char* param_value, InputArray::iterator& input) { if (input.format() == InputFormatEntity) { #define BIND(symbol, collection) \ case symbol: \ input.bind(collection.get_by_name(param_value)); \ return true switch (assembly_symbols.lookup(param_value)) { BIND(SymbolTable::SymbolColor, assembly.colors()); BIND(SymbolTable::SymbolTexture, assembly.textures()); BIND(SymbolTable::SymbolTextureInstance, assembly.texture_instances()); BIND(SymbolTable::SymbolBSDF, assembly.bsdfs()); BIND(SymbolTable::SymbolBSSRDF, assembly.bssrdfs()); BIND(SymbolTable::SymbolEDF, assembly.edfs()); #ifdef APPLESEED_WITH_OSL BIND(SymbolTable::SymbolShaderGroup, assembly.shader_groups()); #endif BIND(SymbolTable::SymbolSurfaceShader, assembly.surface_shaders()); BIND(SymbolTable::SymbolMaterial, assembly.materials()); BIND(SymbolTable::SymbolLight, assembly.lights()); BIND(SymbolTable::SymbolObject, assembly.objects()); BIND(SymbolTable::SymbolObjectInstance, assembly.object_instances()); } #undef BIND } else { switch (assembly_symbols.lookup(param_value)) { case SymbolTable::SymbolColor: bind_color_to_input( assembly.colors(), param_value, input); return true; case SymbolTable::SymbolTextureInstance: bind_texture_instance_to_input( assembly.texture_instances(), assembly.get_uid(), entity_type, entity_name, param_value, input); return true; } } return false; }
void InputBinder::bind_assembly_entities_inputs( const Scene& scene, const SymbolTable& scene_symbols, const Assembly& assembly) { // Build the symbol table of the assembly. SymbolTable assembly_symbols; build_assembly_symbol_table(assembly, assembly_symbols); // Push the assembly and its symbol table to the stack. AssemblyInfo info; info.m_assembly = &assembly; info.m_assembly_symbols = &assembly_symbols; m_assembly_info.push_back(info); // Bind textures to texture instances. // Other entities might need to access the textures bound to texture instances, // so binding of textures to texture instances must come first. for (each<TextureInstanceContainer> i = assembly.texture_instances(); i; ++i) { i->unbind_texture(); for (AssemblyInfoIt j = m_assembly_info.rbegin(); j != m_assembly_info.rend(); ++j) i->bind_texture(j->m_assembly->textures()); i->bind_texture(scene.textures()); i->check_texture(); } // Bind BSDFs inputs. for (each<BSDFContainer> i = assembly.bsdfs(); i; ++i) { bind_assembly_entity_inputs( scene, scene_symbols, SymbolTable::symbol_name(SymbolTable::SymbolBSDF), *i); } // Bind BSSRDFs inputs. for (each<BSSRDFContainer> i = assembly.bssrdfs(); i; ++i) { bind_assembly_entity_inputs( scene, scene_symbols, SymbolTable::symbol_name(SymbolTable::SymbolBSSRDF), *i); } // Bind EDFs inputs. for (each<EDFContainer> i = assembly.edfs(); i; ++i) { bind_assembly_entity_inputs( scene, scene_symbols, SymbolTable::symbol_name(SymbolTable::SymbolEDF), *i); } #ifdef APPLESEED_WITH_OSL // Bind ShaderGroups inputs. for (each<ShaderGroupContainer> i = assembly.shader_groups(); i; ++i) { bind_assembly_entity_inputs( scene, scene_symbols, SymbolTable::symbol_name(SymbolTable::SymbolShaderGroup), *i); } #endif // Bind surface shaders inputs. for (each<SurfaceShaderContainer> i = assembly.surface_shaders(); i; ++i) { bind_assembly_entity_inputs( scene, scene_symbols, SymbolTable::symbol_name(SymbolTable::SymbolSurfaceShader), *i); } // Bind materials inputs. for (each<MaterialContainer> i = assembly.materials(); i; ++i) { bind_assembly_entity_inputs( scene, scene_symbols, SymbolTable::symbol_name(SymbolTable::SymbolMaterial), *i); } // Bind lights inputs. for (each<LightContainer> i = assembly.lights(); i; ++i) { bind_assembly_entity_inputs( scene, scene_symbols, SymbolTable::symbol_name(SymbolTable::SymbolLight), *i); } // Bind objects inputs. for (each<ObjectContainer> i = assembly.objects(); i; ++i) { bind_assembly_entity_inputs( scene, scene_symbols, SymbolTable::symbol_name(SymbolTable::SymbolObject), *i); } // Bind objects to object instances. This must be done before binding materials. for (each<ObjectInstanceContainer> i = assembly.object_instances(); i; ++i) { i->unbind_object(); for (AssemblyInfoIt j = m_assembly_info.rbegin(); j != m_assembly_info.rend(); ++j) i->bind_object(j->m_assembly->objects()); i->check_object(); } // Bind materials to object instances. for (each<ObjectInstanceContainer> i = assembly.object_instances(); i; ++i) { i->unbind_materials(); for (AssemblyInfoIt j = m_assembly_info.rbegin(); j != m_assembly_info.rend(); ++j) i->bind_materials(j->m_assembly->materials()); i->check_materials(); } // Bind assemblies to assembly instances. for (each<AssemblyInstanceContainer> i = assembly.assembly_instances(); i; ++i) { i->unbind_assembly(); for (AssemblyInfoIt j = m_assembly_info.rbegin(); j != m_assembly_info.rend(); ++j) i->bind_assembly(j->m_assembly->assemblies()); i->bind_assembly(scene.assemblies()); i->check_assembly(); } // Recurse into child assemblies. for (const_each<AssemblyContainer> i = assembly.assemblies(); i; ++i) bind_assembly_entities_inputs(scene, scene_symbols, *i); // Pop the information about this assembly from the stack. m_assembly_info.pop_back(); }
void InputBinder::bind_assembly_entities_inputs( const Scene& scene, const SymbolTable& scene_symbols, const Assembly& assembly, const SymbolTable& assembly_symbols) { // Bind BSDFs inputs. for (each<BSDFContainer> i = assembly.bsdfs(); i; ++i) { bind_assembly_entity_inputs( scene, scene_symbols, assembly, assembly_symbols, SymbolTable::symbol_name(SymbolTable::SymbolBSDF), i->get_name(), i->get_parameters(), i->get_inputs()); } // Bind EDFs inputs. for (each<EDFContainer> i = assembly.edfs(); i; ++i) { bind_assembly_entity_inputs( scene, scene_symbols, assembly, assembly_symbols, SymbolTable::symbol_name(SymbolTable::SymbolEDF), i->get_name(), i->get_parameters(), i->get_inputs()); } // Bind surface shaders inputs. for (each<SurfaceShaderContainer> i = assembly.surface_shaders(); i; ++i) { bind_assembly_entity_inputs( scene, scene_symbols, assembly, assembly_symbols, SymbolTable::symbol_name(SymbolTable::SymbolSurfaceShader), i->get_name(), i->get_parameters(), i->get_inputs()); } // Bind materials inputs. for (each<MaterialContainer> i = assembly.materials(); i; ++i) { bind_assembly_entity_inputs( scene, scene_symbols, assembly, assembly_symbols, SymbolTable::symbol_name(SymbolTable::SymbolMaterial), i->get_name(), i->get_parameters(), i->get_inputs()); i->bind_entities( assembly.surface_shaders(), assembly.bsdfs(), assembly.edfs()); } // Bind lights inputs. for (each<LightContainer> i = assembly.lights(); i; ++i) { bind_assembly_entity_inputs( scene, scene_symbols, assembly, assembly_symbols, SymbolTable::symbol_name(SymbolTable::SymbolLight), i->get_name(), i->get_parameters(), i->get_inputs()); } // Bind object instances inputs. for (each<ObjectInstanceContainer> i = assembly.object_instances(); i; ++i) i->bind_entities(assembly.materials()); }
AssemblyItem::AssemblyItem( EntityEditorContext& editor_context, Assembly& assembly, BaseGroup& parent, BaseGroupItem* parent_item) : BaseGroupItem(editor_context, g_class_uid, assembly) , m_assembly(assembly) , m_assembly_uid(assembly.get_uid()) , m_parent(parent) , m_parent_item(parent_item) { set_title(QString::fromAscii(assembly.get_name())); set_allow_edition(false); insertChild( 3, m_bsdf_collection_item = add_multi_model_collection_item<BSDF>(assembly.bsdfs())); insertChild( 4, m_bssrdf_collection_item = add_multi_model_collection_item<BSSRDF>(assembly.bssrdfs())); insertChild( 5, m_edf_collection_item = add_multi_model_collection_item<EDF>(assembly.edfs())); insertChild( 6, m_surface_shader_collection_item = add_multi_model_collection_item<SurfaceShader>(assembly.surface_shaders())); insertChild( 7, m_material_collection_item = new MaterialCollectionItem( m_editor_context, assembly.materials(), assembly, this)); insertChild( 8, m_light_collection_item = add_multi_model_collection_item<Light>(assembly.lights())); insertChild( 9, m_object_collection_item = new ObjectCollectionItem( m_editor_context, assembly.objects(), assembly, this)); insertChild( 10, m_object_instance_collection_item = new ObjectInstanceCollectionItem( m_editor_context, new_guid(), EntityTraits<ObjectInstance>::get_human_readable_collection_type_name(), assembly)); m_object_instance_collection_item->add_items(assembly.object_instances()); insertChild( 11, m_volume_collection_item = add_multi_model_collection_item<Volume>(assembly.volumes())); m_editor_context.m_item_registry.insert(m_assembly, this); }
void LightSampler::collect_emitting_triangles( const Assembly& assembly, const AssemblyInstance& assembly_instance, const TransformSequence& transform_sequence) { // Loop over the object instances of the assembly. const size_t object_instance_count = assembly.object_instances().size(); for (size_t object_instance_index = 0; object_instance_index < object_instance_count; ++object_instance_index) { // Retrieve the object instance. const ObjectInstance* object_instance = assembly.object_instances().get_by_index(object_instance_index); // Retrieve the materials of the object instance. const MaterialArray& front_materials = object_instance->get_front_materials(); const MaterialArray& back_materials = object_instance->get_back_materials(); // Skip object instances without light-emitting materials. if (!has_emitting_materials(front_materials) && !has_emitting_materials(back_materials)) continue; double object_area = 0.0; // Compute the object space to world space transformation. // todo: add support for moving light-emitters. const Transformd& object_instance_transform = object_instance->get_transform(); const Transformd& assembly_instance_transform = transform_sequence.get_earliest_transform(); const Transformd global_transform = assembly_instance_transform * object_instance_transform; // Retrieve the object. Object& object = object_instance->get_object(); // Retrieve the region kit of the object. Access<RegionKit> region_kit(&object.get_region_kit()); // Loop over the regions of the object. const size_t region_count = region_kit->size(); for (size_t region_index = 0; region_index < region_count; ++region_index) { // Retrieve the region. const IRegion* region = (*region_kit)[region_index]; // Retrieve the tessellation of the region. Access<StaticTriangleTess> tess(®ion->get_static_triangle_tess()); // Loop over the triangles of the region. const size_t triangle_count = tess->m_primitives.size(); for (size_t triangle_index = 0; triangle_index < triangle_count; ++triangle_index) { // Fetch the triangle. const Triangle& triangle = tess->m_primitives[triangle_index]; // Skip triangles without a material. if (triangle.m_pa == Triangle::None) continue; // Fetch the materials assigned to this triangle. const size_t pa_index = static_cast<size_t>(triangle.m_pa); const Material* front_material = pa_index < front_materials.size() ? front_materials[pa_index] : 0; const Material* back_material = pa_index < back_materials.size() ? back_materials[pa_index] : 0; // Skip triangles that don't emit light. if ((front_material == 0 || front_material->has_emission() == false) && (back_material == 0 || back_material->has_emission() == false)) continue; // Retrieve object instance space vertices of the triangle. const GVector3& v0_os = tess->m_vertices[triangle.m_v0]; const GVector3& v1_os = tess->m_vertices[triangle.m_v1]; const GVector3& v2_os = tess->m_vertices[triangle.m_v2]; // Transform triangle vertices to assembly space. const GVector3 v0_as = object_instance_transform.point_to_parent(v0_os); const GVector3 v1_as = object_instance_transform.point_to_parent(v1_os); const GVector3 v2_as = object_instance_transform.point_to_parent(v2_os); // Compute the support plane of the hit triangle in assembly space. const GTriangleType triangle_geometry(v0_as, v1_as, v2_as); TriangleSupportPlaneType triangle_support_plane; triangle_support_plane.initialize(TriangleType(triangle_geometry)); // Transform triangle vertices to world space. const Vector3d v0(assembly_instance_transform.point_to_parent(v0_as)); const Vector3d v1(assembly_instance_transform.point_to_parent(v1_as)); const Vector3d v2(assembly_instance_transform.point_to_parent(v2_as)); // Compute the geometric normal to the triangle and the area of the triangle. Vector3d geometric_normal = cross(v1 - v0, v2 - v0); const double geometric_normal_norm = norm(geometric_normal); if (geometric_normal_norm == 0.0) continue; const double rcp_geometric_normal_norm = 1.0 / geometric_normal_norm; const double rcp_area = 2.0 * rcp_geometric_normal_norm; const double area = 0.5 * geometric_normal_norm; geometric_normal *= rcp_geometric_normal_norm; assert(is_normalized(geometric_normal)); // Retrieve object instance space vertex normals. Vector3d n0_os, n1_os, n2_os; if (triangle.m_n0 != Triangle::None && triangle.m_n1 != Triangle::None && triangle.m_n2 != Triangle::None) { n0_os = Vector3d(tess->m_vertex_normals[triangle.m_n0]); n1_os = Vector3d(tess->m_vertex_normals[triangle.m_n1]); n2_os = Vector3d(tess->m_vertex_normals[triangle.m_n2]); } else n0_os = n1_os = n2_os = geometric_normal; // Transform vertex normals to world space. const Vector3d n0(normalize(global_transform.normal_to_parent(n0_os))); const Vector3d n1(normalize(global_transform.normal_to_parent(n1_os))); const Vector3d n2(normalize(global_transform.normal_to_parent(n2_os))); for (size_t side = 0; side < 2; ++side) { // Retrieve the material; skip sides without a material or without emission. const Material* material = side == 0 ? front_material : back_material; if (material == 0 || material->has_emission() == false) continue; // Retrieve the EDF and get the importance multiplier. double importance_multiplier = 1.0; if (const EDF* edf = material->get_uncached_edf()) importance_multiplier = edf->get_uncached_importance_multiplier(); // Accumulate the object area for OSL shaders. object_area += area; // Compute the probability density of this triangle. const double triangle_importance = m_params.m_importance_sampling ? area : 1.0; const double triangle_prob = triangle_importance * importance_multiplier; // Create a light-emitting triangle. EmittingTriangle emitting_triangle; emitting_triangle.m_assembly_instance = &assembly_instance; emitting_triangle.m_object_instance_index = object_instance_index; emitting_triangle.m_region_index = region_index; emitting_triangle.m_triangle_index = triangle_index; emitting_triangle.m_v0 = v0; emitting_triangle.m_v1 = v1; emitting_triangle.m_v2 = v2; emitting_triangle.m_n0 = side == 0 ? n0 : -n0; emitting_triangle.m_n1 = side == 0 ? n1 : -n1; emitting_triangle.m_n2 = side == 0 ? n2 : -n2; emitting_triangle.m_geometric_normal = side == 0 ? geometric_normal : -geometric_normal; emitting_triangle.m_triangle_support_plane = triangle_support_plane; emitting_triangle.m_rcp_area = rcp_area; emitting_triangle.m_triangle_prob = 0.0; // will be initialized once the emitting triangle CDF is built emitting_triangle.m_material = material; // Store the light-emitting triangle. const size_t emitting_triangle_index = m_emitting_triangles.size(); m_emitting_triangles.push_back(emitting_triangle); // Insert the light-emitting triangle into the CDF. m_emitting_triangles_cdf.insert(emitting_triangle_index, triangle_prob); } } } #ifdef APPLESEED_WITH_OSL store_object_area_in_shadergroups( &assembly_instance, object_instance, object_area, front_materials); store_object_area_in_shadergroups( &assembly_instance, object_instance, object_area, back_materials); #endif } }