void LightSampler::collect_emitting_triangles( const Scene& scene, const AssemblyInstance& assembly_instance) { // Loop over the object instances of the assembly. const Assembly& assembly = assembly_instance.get_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(Matrix4d::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]; const size_t pa_index = static_cast<size_t>(triangle.m_pa); // Fetch the materials assigned to this triangle. 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_edf() == 0) && (back_material == 0 || back_material->get_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 light-emitting material. if (material == 0 || material->get_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 = material->get_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; } } } } }
void CameraController::update_camera_transform() { // Moving the camera kills camera motion blur. m_camera->transform_sequence().clear(); m_camera->transform_sequence().set_transform(0.0, Transformd(m_controller.get_transform())); }
bool AnimationPath::load(const char* filename, const Format format) { m_keyframes.clear(); AutoClosingFile file(filename, "rt"); if (file == 0) { LOG_ERROR(m_logger, "could not read animation path file %s.", filename); return false; } char header[1000]; if (fgets(header, sizeof(header), file) == 0) { LOG_ERROR(m_logger, "could not read animation path file %s.", filename); return false; } if (strcmp(header, "frame pos_x pos_y pos_z rot_x rot_y rot_z rot_w\n")) { LOG_ERROR(m_logger, "%s is not a valid animation path file.", filename); return false; } int line = 2; while (!feof(file)) { int frame; Vector3d position; Quaterniond orientation; const int fields_read = fscanf( file, "%d %lf %lf %lf %lf %lf %lf %lf\n", &frame, &position.x, &position.y, &position.z, &orientation.v.x, &orientation.v.y, &orientation.v.z, &orientation.s); if (fields_read != 8) { LOG_ERROR( m_logger, "while reading animation path file %s: at line %d: parse error.", filename, line); return false; } const int expected_frame = line - 2; if (frame != expected_frame) { LOG_ERROR( m_logger, "while reading animation path file %s: at line %d: expected frame %d, got frame %d.", filename, line, expected_frame, frame); return false; } if (!feq(norm(orientation), 1.0, 1.0e-4)) { LOG_ERROR( m_logger, "while reading animation path file %s: at line %d: invalid rotation.", filename, line); return false; } orientation = normalize(orientation); if (format == Autodesk3dsMax) { position = from_3ds_max(position); orientation.v = from_3ds_max(orientation.v); m_keyframes.push_back( Transformd( Matrix4d::translation(position) * Matrix4d::rotation(orientation) * Matrix4d::rotation(Vector3d(1.0, 0.0, 0.0), -HalfPi))); } else { m_keyframes.push_back( Transformd( Matrix4d::translation(position) * Matrix4d::rotation(orientation))); } ++line; } LOG_INFO( m_logger, "read %d keyframe%s from animation path file %s.", m_keyframes.size(), m_keyframes.size() > 1 ? "s" : "", filename); return true; }
// Create a new instance of the default project. auto_release_ptr<Project> DefaultProjectFactory::create() { // Create a project. auto_release_ptr<Project> project(ProjectFactory::create("default")); // Add default configurations to the project. project->add_default_configurations(); // Create a scene. auto_release_ptr<Scene> scene(SceneFactory::create()); // Create an assembly. auto_release_ptr<Assembly> assembly( AssemblyFactory::create("assembly", ParamArray())); // Create an instance of the assembly and insert it into the scene. scene->assembly_instances().insert( AssemblyInstanceFactory::create( "assembly_inst", ParamArray(), *assembly, Transformd(Matrix4d::identity()))); // Insert the assembly into the scene. scene->assemblies().insert(assembly); // // Camera. // { // Create a pinhole camera. // Film dimensions are 0.980 in × 0.735 in (24.892 mm x 18.669 mm). // Reference: http://en.wikipedia.org/wiki/Aspect_ratio_(image). ParamArray params; params.insert("film_dimensions", "0.024892 0.018669"); params.insert("focal_length", "0.035"); auto_release_ptr<Camera> camera( PinholeCameraFactory().create("camera", params)); // Attach the camera to the scene. scene->set_camera(camera); } // // Frame. // { // Create a frame. ParamArray params; params.insert("camera", scene->get_camera()->get_name()); params.insert("resolution", "640 480"); params.insert("color_space", "srgb"); auto_release_ptr<Frame> frame(FrameFactory::create("beauty", params)); // Attach the frame to the project. project->set_frame(frame); } // Attach the scene to the project. project->set_scene(scene); // Return the newly created project. return project; }