void PatchInspector::emitTesselation() { UndoableCommand setFixedTessCmd("patchSetFixedTesselation"); wxSpinCtrl* fixedSubdivX = findNamedObject<wxSpinCtrl>(this, "PatchInspectorSubdivisionsX"); wxSpinCtrl* fixedSubdivY = findNamedObject<wxSpinCtrl>(this, "PatchInspectorSubdivisionsY"); Subdivisions tess( fixedSubdivX->GetValue(), fixedSubdivY->GetValue() ); bool fixed = findNamedObject<wxCheckBox>(this, "PatchInspectorFixedSubdivisions")->GetValue(); // Save the setting into the selected patch(es) GlobalSelectionSystem().foreachPatch([&] (Patch& patch) { patch.setFixedSubdivisions(fixed, tess); }); fixedSubdivX->Enable(fixed); fixedSubdivY->Enable(fixed); findNamedObject<wxStaticText>(this, "PatchInspectorSubdivisionsXLabel")->Enable(fixed); findNamedObject<wxStaticText>(this, "PatchInspectorSubdivisionsYLabel")->Enable(fixed); GlobalMainFrame().updateAllWindows(); }
void WRATHTessGLU:: end_polygon(void) { WRATHassert(m_private_data!=NULL); wrath_GLUtesselator *tess(static_cast<wrath_GLUtesselator*>(m_private_data)); wrath_gluTessEndPolygon(tess); }
void WRATHTessGLU:: begin_contour(void) { WRATHassert(m_private_data!=NULL); wrath_GLUtesselator *tess(static_cast<wrath_GLUtesselator*>(m_private_data)); WRATHassert(!m_polygons.empty()); wrath_gluTessBeginContour(tess); }
void WRATHTessGLU:: begin_polygon(void *polygon_data) { WRATHassert(m_private_data!=NULL); wrath_GLUtesselator *tess(static_cast<wrath_GLUtesselator*>(m_private_data)); /* create and save a polygon object. */ m_polygons.push_back( WRATHTessGLUPrivate::polygon_element(this, polygon_data)); wrath_gluTessBeginPolygon(tess, &m_polygons.back()); }
void WRATHTessGLU:: add_vertex(vec2 position, void *vertex_data) { WRATHassert(m_private_data!=NULL); double values[3]; wrath_GLUtesselator *tess(static_cast<wrath_GLUtesselator*>(m_private_data)); values[0]=position.x(); values[1]=position.y(); values[2]=0.0; wrath_gluTessVertex(tess, values, vertex_data); }
WRATHTessGLU:: WRATHTessGLU(enum tessellation_type ptype) { m_private_data=wrath_gluNewTess(); /* register call backs: */ wrath_GLUtesselator *tess(static_cast<wrath_GLUtesselator*>(m_private_data)); wrath_gluTessCallbackBegin(tess, &begin_callBack); //WRATH_GLU_TESS_BEGIN_DATA wrath_gluTessCallbackVertex(tess, &vertex_callBack); //WRATH_GLU_TESS_VERTEX_DATA wrath_gluTessCallbackEnd(tess, &end_callBack); //WRATH_GLU_TESS_END_DATA wrath_gluTessCallbackError(tess, &error_callBack); //WRATH_GLU_TESS_ERROR_DATA wrath_gluTessCallbackCombine(tess, &combine_callBack); //WRATH_GLU_TESS_COMBINE_DATA wrath_gluTessCallbackFillRule(tess, &winding_callBack); //WRATH_GLU_TESS_COMBINE_DATA switch(ptype) { default: WRATHwarning("\nBad tessellation_type: " << static_cast<unsigned int>(ptype) << " reevaluated as tessellate_triangles_only\n"); case tessellate_triangles_only: wrath_gluTessCallbackEdgeFlag(tess, &edgeflag_callBack); //WRATH_GLU_TESS_EDGE_FLAG_DATA wrath_gluTessPropertyBoundaryOnly(tess, WRATH_GLU_FALSE); break; case tessellate_any_triangles_type: { wrath_glu_tess_function_edge_data no_edge_function(NULL); wrath_gluTessCallbackEdgeFlag(tess, no_edge_function); wrath_gluTessPropertyBoundaryOnly(tess, WRATH_GLU_FALSE); } break; case tessellate_boundary_only: wrath_gluTessCallbackEdgeFlag(tess, &edgeflag_callBack); //WRATH_GLU_TESS_EDGE_FLAG_DATA wrath_gluTessPropertyBoundaryOnly(tess, WRATH_GLU_TRUE); break; } }
int window_maker(const sf::Vector2f& windims, const std::string& program_name) { const sf::Color black{sf::Color(0, 0, 0)}; const sf::Color light_red{sf::Color(191, 63, 63)}; const sf::Vector2f left_start_rel{0.2f, 0.9f}; square tess(windims, left_start_rel, light_red); sf::RenderWindow window(sf::VideoMode(windims.x, windims.y), program_name, sf::Style::Default); while (window.isOpen()) { sf::Event event; window.clear(black); tess.show_square(window); window.display(); if (sf::Keyboard::isKeyPressed(sf::Keyboard::Escape)) { window.close(); return 0; } while (window.pollEvent(event)) { if (event.type == sf::Event::Closed) { window.close(); return 0; } } } return 1; }
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; } } } } }
/*! Generates the convexified data. FIXME: doc */ void SoConvexDataCache::generate(const SoCoordinateElement * const coords, const SbMatrix & matrix, const int32_t *vind, const int numv, const int32_t *mind, const int32_t *nind, const int32_t *tind, const Binding matbind, const Binding normbind, const Binding texbind) { #if COIN_DEBUG && 0 SoDebugError::postInfo("SoConvexDataCache::generate", "generating convex data"); #endif SbBool identity = matrix == SbMatrix::identity(); // remove old data PRIVATE(this)->coordIndices.truncate(0); PRIVATE(this)->materialIndices.truncate(0); PRIVATE(this)->normalIndices.truncate(0); PRIVATE(this)->texIndices.truncate(0); int matnr = 0; int texnr = 0; int normnr = 0; // initialize the struct with data needed during tessellation tTessData tessdata; tessdata.matbind = matbind; tessdata.normbind = normbind; tessdata.texbind = texbind; tessdata.numvertexind = 0; tessdata.nummatind = 0; tessdata.numnormind = 0; tessdata.numtexind = 0; // FIXME: stupid to have a separate struct for each coordIndex // should only allocate enough to hold the largest polygon tessdata.vertexInfo = new tVertexInfo[numv]; tessdata.vertexIndex = NULL; tessdata.matIndex = NULL; tessdata.normIndex = NULL; tessdata.texIndex = NULL; tessdata.firstvertex = TRUE; // create tessellator SbGLUTessellator glutess(do_triangle, &tessdata); SbTesselator tess(do_triangle, &tessdata); const SbBool gt = SbGLUTessellator::preferred(); // if PER_FACE binding, the binding must change to PER_FACE_INDEXED // if convexify data is used. tessdata.vertexIndex = &PRIVATE(this)->coordIndices; if (matbind != NONE) tessdata.matIndex = &PRIVATE(this)->materialIndices; if (normbind != NONE) tessdata.normIndex = &PRIVATE(this)->normalIndices; if (texbind != NONE) tessdata.texIndex = &PRIVATE(this)->texIndices; if (gt) { glutess.beginPolygon(); } else { tess.beginPolygon(); } for (int i = 0; i < numv; i++) { if (vind[i] < 0) { if (gt) { glutess.endPolygon(); } else { tess.endPolygon(); } if (matbind == PER_VERTEX_INDEXED || matbind == PER_FACE || matbind == PER_FACE_INDEXED) matnr++; if (normbind == PER_VERTEX_INDEXED || normbind == PER_FACE || normbind == PER_FACE_INDEXED) normnr++; if (texbind == PER_VERTEX_INDEXED) texnr++; if (i < numv - 1) { // if not last polygon if (gt) { glutess.beginPolygon(); } else { tess.beginPolygon(); } } } else { tessdata.vertexInfo[i].vertexnr = vind[i]; if (mind) tessdata.vertexInfo[i].matnr = mind[matnr]; else tessdata.vertexInfo[i].matnr = matnr; if (matbind >= PER_VERTEX) { matnr++; } if (nind) tessdata.vertexInfo[i].normnr = nind[normnr]; else tessdata.vertexInfo[i].normnr = normnr; if (normbind >= PER_VERTEX) normnr++; if (tind) tessdata.vertexInfo[i].texnr = tind[texnr++]; else tessdata.vertexInfo[i].texnr = texnr++; SbVec3f v = coords->get3(vind[i]); if (!identity) matrix.multVecMatrix(v,v); if (gt) { glutess.addVertex(v, static_cast<void *>(&tessdata.vertexInfo[i])); } else { tess.addVertex(v, static_cast<void *>(&tessdata.vertexInfo[i])); } } } // if last coordIndex != -1, terminate polygon if (numv > 0 && vind[numv-1] != -1) { if (gt) { glutess.endPolygon(); } else { tess.endPolygon(); } } delete [] tessdata.vertexInfo; PRIVATE(this)->coordIndices.fit(); if (tessdata.matIndex) PRIVATE(this)->materialIndices.fit(); if (tessdata.normIndex) PRIVATE(this)->normalIndices.fit(); if (tessdata.texIndex) PRIVATE(this)->texIndices.fit(); }
void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) override { bool canTweakAlphaForCoverage = this->canTweakAlphaForCoverage(); SkMatrix invert; if (this->usesLocalCoords() && !this->viewMatrix().invert(&invert)) { SkDebugf("Could not invert viewmatrix\n"); return; } // Setup GrGeometryProcessor SkAutoTUnref<const GrGeometryProcessor> gp( create_fill_gp(canTweakAlphaForCoverage, invert, this->usesLocalCoords(), this->coverageIgnored())); batchTarget->initDraw(gp, pipeline); size_t vertexStride = gp->getVertexStride(); SkASSERT(canTweakAlphaForCoverage ? vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorAttr) : vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorCoverageAttr)); int instanceCount = fGeoData.count(); int vertexCount = 0; int indexCount = 0; int maxVertices = DEFAULT_BUFFER_SIZE; int maxIndices = DEFAULT_BUFFER_SIZE; uint8_t* vertices = (uint8_t*) malloc(maxVertices * vertexStride); uint16_t* indices = (uint16_t*) malloc(maxIndices * sizeof(uint16_t)); for (int i = 0; i < instanceCount; i++) { Geometry& args = fGeoData[i]; GrAAConvexTessellator tess(args.fStrokeWidth, args.fJoin, args.fMiterLimit); if (!tess.tessellate(args.fViewMatrix, args.fPath)) { continue; } int currentIndices = tess.numIndices(); SkASSERT(currentIndices <= UINT16_MAX); if (indexCount + currentIndices > UINT16_MAX) { // if we added the current instance, we would overflow the indices we can store in a // uint16_t. Draw what we've got so far and reset. draw(batchTarget, pipeline, vertexCount, vertexStride, vertices, indexCount, indices); vertexCount = 0; indexCount = 0; } int currentVertices = tess.numPts(); if (vertexCount + currentVertices > maxVertices) { maxVertices = SkTMax(vertexCount + currentVertices, maxVertices * 2); vertices = (uint8_t*) realloc(vertices, maxVertices * vertexStride); } if (indexCount + currentIndices > maxIndices) { maxIndices = SkTMax(indexCount + currentIndices, maxIndices * 2); indices = (uint16_t*) realloc(indices, maxIndices * sizeof(uint16_t)); } extract_verts(tess, vertices + vertexStride * vertexCount, vertexStride, args.fColor, vertexCount, indices + indexCount, canTweakAlphaForCoverage); vertexCount += currentVertices; indexCount += currentIndices; } draw(batchTarget, pipeline, vertexCount, vertexStride, vertices, indexCount, indices); free(vertices); free(indices); }
tileList tiledCanvas::getTesselation(int w, int h, int x1, int y1, bool flipY) { tileList tessPoints; // Produce an integer version of mOffset that is centered in the w x h screen agg::trans_affine tess(mWidth, floor(mOffset.shy + 0.5), floor(mOffset.shx + 0.5), flipY ? -mHeight : mHeight, x1, y1); agg::rect_i screen(0, 0, w - 1, h - 1); if (mFrieze == CFDG::frieze_x) tess.sy = 0.0; if (mFrieze == CFDG::frieze_y) tess.sx = 0.0; tessPoints.push_back(agg::point_i(x1, y1)); // always include the center tile if (mFrieze) { for (int offset = 1; ; ++offset) { bool hit = false; for (int side: {-1, 1}) { double dx = offset * side; double dy = dx; tess.transform(&dx, &dy); int px = static_cast<int>(floor(dx + 0.5)); int py = static_cast<int>(floor(dy + 0.5)); // If the tile is visible then record it agg::rect_i tile(px, py, px + mWidth - 1, py + mHeight - 1); if (tile.overlaps(screen)) { hit = true; tessPoints.emplace_back(px, py); } } if (!hit) return tessPoints; } } // examine rings of tile units around the center unit until you encounter a // ring that doesn't have any tile units that intersect the screen. Then stop. for (int ring = 1; ; ring++) { bool hit = false; for (int pos = -ring; pos < ring; pos++) { std::array<std::pair<int, int>, 4> points = {{ {pos, -ring}, {ring, pos}, {-pos, ring}, {-ring, -pos} }}; for (auto&& point: points) { // Find where this tile is on the screen double dx = point.first; double dy = point.second; tess.transform(&dx, &dy); int px = static_cast<int>(floor(dx + 0.5)); int py = static_cast<int>(floor(dy + 0.5)); // If the tile is visible then record it agg::rect_i tile(px, py, px + mWidth - 1, py + mHeight - 1); if (tile.overlaps(screen)) { hit = true; tessPoints.emplace_back(px, py); } } } if (!hit) break; } return tessPoints; }
int main(int argc, char *argv[]) { int tot_blocks; // total number of blocks in the domain int mem_blocks; // max blocks in memory int dsize[3]; // domain grid size float jitter; // max amount to randomly displace particles float minvol, maxvol; // volume range, -1.0 = unused double times[TESS_MAX_TIMES]; // timing int wrap; // wraparound neighbors flag int walls; // apply walls to simulation (wrap must be off) char outfile[256]; // output file name int num_threads = 1; // threads diy can use // init MPI MPI_Comm comm = MPI_COMM_WORLD; MPI_Init(&argc, &argv); GetArgs(argc, argv, tot_blocks, mem_blocks, dsize, &jitter, &minvol, &maxvol, &wrap, &walls, outfile); // data extents typedef diy::ContinuousBounds Bounds; Bounds domain { 3 }; for(int i = 0; i < 3; i++) { domain.min[i] = 0; domain.max[i] = dsize[i] - 1.0; } // init diy diy::mpi::communicator world(comm); diy::FileStorage storage("./DIY.XXXXXX"); diy::Master master(world, num_threads, mem_blocks, &create_block, &destroy_block, &storage, &save_block, &load_block); diy::RoundRobinAssigner assigner(world.size(), tot_blocks); AddAndGenerate create(master, jitter); // decompose std::vector<int> my_gids; assigner.local_gids(world.rank(), my_gids); diy::RegularDecomposer<Bounds>::BoolVector wraps; diy::RegularDecomposer<Bounds>::BoolVector share_face; diy::RegularDecomposer<Bounds>::CoordinateVector ghosts; if (wrap) wraps.assign(3, true); diy::decompose(3, world.rank(), domain, assigner, create, share_face, wraps, ghosts); // tessellate quants_t quants; timing(times, -1, -1, world); timing(times, TOT_TIME, -1, world); tess(master, quants, times); // output tess_save(master, outfile, times); timing(times, -1, TOT_TIME, world); tess_stats(master, quants, times); MPI_Finalize(); return 0; }
void PatchInspector::rescanSelection() { // Check if there is one distinct patch selected bool sensitive = (_selectionInfo.patchCount == 1); findNamedObject<wxPanel>(this, "PatchInspectorVertexPanel")->Enable(sensitive); findNamedObject<wxPanel>(this, "PatchInspectorCoordPanel")->Enable(sensitive); // Tesselation is always sensitive when one or more patches are selected findNamedObject<wxPanel>(this, "PatchInspectorTessPanel")->Enable(_selectionInfo.patchCount > 0); // Clear the patch reference setPatch(PatchNodePtr()); if (_selectionInfo.patchCount > 0) { // Get the list of selected patches PatchPtrVector list = selection::algorithm::getSelectedPatches(); Subdivisions tess(UINT_MAX, UINT_MAX); bool tessIsFixed = false; // Try to find a pair of same tesselation values for (PatchPtrVector::const_iterator i = list.begin(); i != list.end(); ++i) { IPatch& p = (*i)->getPatch(); if (tess.x() == UINT_MAX) { // Not initialised yet, take these values for starters tessIsFixed = p.subdivionsFixed(); tess = p.getSubdivisions(); } else { // We already have a pair of divisions, compare Subdivisions otherTess = p.getSubdivisions(); if (tessIsFixed != p.subdivionsFixed() || otherTess != tess) { // Our journey ends here, we cannot find a pair of tesselations // for all selected patches or the same fixed/variable status tessIsFixed = false; break; } } } _updateActive = true; // Load the "fixed tesselation" value findNamedObject<wxCheckBox>(this, "PatchInspectorFixedSubdivisions")->SetValue(tessIsFixed); wxSpinCtrl* fixedSubdivX = findNamedObject<wxSpinCtrl>(this, "PatchInspectorSubdivisionsX"); wxSpinCtrl* fixedSubdivY = findNamedObject<wxSpinCtrl>(this, "PatchInspectorSubdivisionsY"); fixedSubdivX->SetValue(tess[0]); fixedSubdivY->SetValue(tess[1]); fixedSubdivX->Enable(tessIsFixed); fixedSubdivY->Enable(tessIsFixed); findNamedObject<wxStaticText>(this, "PatchInspectorSubdivisionsXLabel")->Enable(tessIsFixed); findNamedObject<wxStaticText>(this, "PatchInspectorSubdivisionsYLabel")->Enable(tessIsFixed); if (_selectionInfo.patchCount == 1) { setPatch(list[0]); } _updateActive = false; } update(); }
void AOVoxelTree::build( const Scene& scene, BuilderType& builder) { // The voxel tree is built using the scene geometry at the middle of the shutter interval. const double time = scene.get_camera()->get_shutter_middle_time(); // Loop over the assembly instances of the scene. for (const_each<AssemblyInstanceContainer> i = scene.assembly_instances(); i; ++i) { // Retrieve the assembly instance. const AssemblyInstance& assembly_instance = *i; // Retrieve the assembly. const Assembly& assembly = assembly_instance.get_assembly(); // Loop over the object instances of the assembly. for (const_each<ObjectInstanceContainer> j = assembly.object_instances(); j; ++j) { // Retrieve the object instance. const ObjectInstance& object_instance = *j; // Compute the object space to world space transformation. const Transformd transform = assembly_instance.transform_sequence().evaluate(time) * 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()); // 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()); // Push all triangles of the region into the tree. 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]; // 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 world space. const GVector3 v0(transform.point_to_parent(v0_os)); const GVector3 v1(transform.point_to_parent(v1_os)); const GVector3 v2(transform.point_to_parent(v2_os)); // Push the triangle into the tree. TriangleIntersector intersector(v0, v1, v2); builder.push(intersector); } } } } }
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 } }