TEST_F(MeshRendererTest, Triangle) { MeshRenderer* mesh_renderer = static_cast<MeshRenderer*>(go->AddComponent<MeshRenderer>()); EXPECT_NE(mesh_renderer, nullptr); Mesh mesh; EXPECT_EQ(mesh.IsDirty(), true); mesh.AddVertex(Vertex(Vec3f(0, 0, 0), Vec4f(1, 0, 0, 1))); mesh.AddVertex(Vertex(Vec3f(1, 0, 0), Vec4f(0, 1, 0, 1))); mesh.AddVertex(Vertex(Vec3f(0, 1, 0), Vec4f(0, 0, 1, 1))); EXPECT_EQ(mesh.GetVertexCount(), 3u); mesh.AddIndex(0); mesh.AddIndex(1); mesh.AddIndex(2); EXPECT_EQ(mesh.GetIndexCount(), 3u); EXPECT_EQ(mesh.IsDirty(), true); mesh.UpdateMesh(); EXPECT_EQ(mesh.IsDirty(), false); anjing::gfx::Shader* shader = anjing::gfx::Shader::LoadShaderProgram("default/default.vs", "default/default.fs"); anjing::gfx::Material* mat = Anew anjing::gfx::Material; mat->SetShader(shader); mesh_renderer->SetMaterial(mat); mesh_renderer->SetMesh(&mesh); anjing::core::Scene::GetInstance().Render(); }
TEST_F(GraphicsLightTest, TestLightTwoSided) { // Clear. glClearColor(0.2f, 0.4f, 0.6f, 0.f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glEnable(GL_DEPTH_TEST); // Setup camera. glMatrixMode(GL_PROJECTION); glFrontFace(GL_CW); glFrustumf(-0.5f, 0.5f, -0.5f, 0.5f, 1.f, 30.f); glMatrixMode(GL_MODELVIEW); glTranslatef(0.f, 0.f, -2.f); glEnable(GL_LIGHTING); // Setup triangle mesh. Mesh triangle; triangle.AddVertex().Position(0.f, 0.f, 0.f).Normal(0.f, 0.f, 1.f); triangle.AddVertex().Position(1.f, 0.f, 0.f).Normal(0.f, 0.f, 1.f); triangle.AddVertex().Position(1.f, 1.f, 0.f).Normal(0.f, 0.f, 1.f); glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(3, GL_FLOAT, 0, triangle.Positions()); glEnableClientState(GL_NORMAL_ARRAY); glNormalPointer(GL_FLOAT, 0, triangle.Normals()); // Front light (green). const float front[] = {0.f, 0.f, -5.f, 1.f}; glEnable(GL_LIGHT0); glLightfv(GL_LIGHT0, GL_POSITION, front); glLightfv(GL_LIGHT0, GL_AMBIENT, kRed); glLightfv(GL_LIGHT0, GL_DIFFUSE, kRed); // Back light (red). const float back[] = {0.f, 0.f, 5.f, 1.f}; glEnable(GL_LIGHT1); glLightfv(GL_LIGHT1, GL_POSITION, back); glLightfv(GL_LIGHT1, GL_AMBIENT, kGreen); glLightfv(GL_LIGHT1, GL_DIFFUSE, kGreen); // Draw triangle, enable two-sided lighting, and draw it again // slightly offset. glTranslatef(-1.f, -1.f, 0.f); glDrawArrays(GL_TRIANGLES, 0, triangle.VertexCount()); glLightModelf(GL_LIGHT_MODEL_TWO_SIDE, 1.f); glTranslatef(1.f, 1.f, 0.f); glDrawArrays(GL_TRIANGLES, 0, triangle.VertexCount()); glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_VERTEX_ARRAY); EXPECT_IMAGE(); }
void GuiElement::GenerateMesh() { if(m_NeedsUpdate) { Mesh* mesh = new Mesh(); Vec2 Pos = Vec2(0,0); mesh->AddVertex(Vec3(Pos.x,Pos.y, 0)); mesh->AddTexCoord(Vec2(0,0)); mesh->AddVertex(Vec3(Pos.x,Pos.y + m_Size.y,0)); mesh->AddTexCoord(Vec2(0,1)); mesh->AddVertex(Vec3(Pos.x + m_Size.x,Pos.y,0)); mesh->AddTexCoord(Vec2(1,0)); mesh->AddVertex(Vec3(Pos.x + m_Size.x,Pos.y,0)); mesh->AddTexCoord(Vec2(1,0)); mesh->AddVertex(Vec3(Pos.x,Pos.y + m_Size.y,0)); mesh->AddTexCoord(Vec2(0,1)); mesh->AddVertex(Vec3(Pos + m_Size,0)); mesh->AddTexCoord(Vec2(1,1)); //if(m_Font) //m_Font->AddToMesh(mesh, InnerText_,Vec3(0,0,0),(i32)m_Size.x, FontSize_); m_Component->SetMesh(mesh); m_NeedsUpdate = false; } }
void Model::InitMesh(const aiMesh* mesh) { MeshInfo* meshInfo = new MeshInfo; meshInfo->NumVertices = mesh->mNumVertices; meshInfo->NumIndices = mesh->mNumFaces * 3; Mesh* modelMesh = new Mesh(this, meshInfo); /*READ VERTS INTO MODEL MESH*/ size_t numVerts = mesh->mNumVertices; for(size_t i = 0; i < numVerts; i++) { aiVector3D vertex = mesh->mVertices[i]; aiVector3D tangent = aiVector3D(0.0f); if(mesh->HasTangentsAndBitangents()) { tangent = mesh->mTangents[i]; } aiVector3D normal(0.0f); float u = 0.0f; float v = 0.0f; if(mesh->HasNormals()) { normal = mesh->mNormals[i]; } if(mesh->HasTextureCoords(0)) { aiVector3D uvs = mesh->mTextureCoords[0][i]; u = uvs.x; v = uvs.y; } meshInfo->Vertices.push_back(Vec3(vertex.x, vertex.y, vertex.z)); modelMesh->AddVertex(vertex.x, vertex.y, vertex.z, normal.x, normal.y, normal.z, u, v, tangent.x, tangent.y, tangent.z); } /*READ FACES INTO MODEL MESH*/ size_t numFaces = mesh->mNumFaces; for(size_t i = 0; i < numFaces; i++) { aiFace face = mesh->mFaces[i]; modelMesh->AddFace(face.mIndices[0], face.mIndices[1], face.mIndices[2]); } /*INITIALIZE MESH*/ modelMesh->Init(); /*ADD MODELMESH TO COLLECTION*/ m_meshes.push_back(modelMesh); }
int main(int argc, char *argv[]) { // 1. Initialize MPI. int num_procs, myid; MPI_Init(&argc, &argv); MPI_Comm_size(MPI_COMM_WORLD, &num_procs); MPI_Comm_rank(MPI_COMM_WORLD, &myid); // 2. Parse command-line options. int elem_type = 1; int ref_levels = 2; int amr = 0; int order = 2; bool always_snap = false; bool visualization = 1; OptionsParser args(argc, argv); args.AddOption(&elem_type, "-e", "--elem", "Type of elements to use: 0 - triangles, 1 - quads."); args.AddOption(&order, "-o", "--order", "Finite element order (polynomial degree)."); args.AddOption(&ref_levels, "-r", "--refine", "Number of times to refine the mesh uniformly."); args.AddOption(&amr, "-amr", "--refine-locally", "Additional local (non-conforming) refinement:" " 1 = refine around north pole, 2 = refine randomly."); args.AddOption(&visualization, "-vis", "--visualization", "-no-vis", "--no-visualization", "Enable or disable GLVis visualization."); args.AddOption(&always_snap, "-snap", "--always-snap", "-no-snap", "--snap-at-the-end", "If true, snap nodes to the sphere initially and after each refinement " "otherwise, snap only after the last refinement"); args.Parse(); if (!args.Good()) { if (myid == 0) { args.PrintUsage(cout); } MPI_Finalize(); return 1; } if (myid == 0) { args.PrintOptions(cout); } // 3. Generate an initial high-order (surface) mesh on the unit sphere. The // Mesh object represents a 2D mesh in 3 spatial dimensions. We first add // the elements and the vertices of the mesh, and then make it high-order // by specifying a finite element space for its nodes. int Nvert = 8, Nelem = 6; if (elem_type == 0) { Nvert = 6; Nelem = 8; } Mesh *mesh = new Mesh(2, Nvert, Nelem, 0, 3); if (elem_type == 0) // inscribed octahedron { const double tri_v[6][3] = { { 1, 0, 0}, { 0, 1, 0}, {-1, 0, 0}, { 0, -1, 0}, { 0, 0, 1}, { 0, 0, -1} }; const int tri_e[8][3] = { {0, 1, 4}, {1, 2, 4}, {2, 3, 4}, {3, 0, 4}, {1, 0, 5}, {2, 1, 5}, {3, 2, 5}, {0, 3, 5} }; for (int j = 0; j < Nvert; j++) { mesh->AddVertex(tri_v[j]); } for (int j = 0; j < Nelem; j++) { int attribute = j + 1; mesh->AddTriangle(tri_e[j], attribute); } mesh->FinalizeTriMesh(1, 1, true); } else // inscribed cube { const double quad_v[8][3] = { {-1, -1, -1}, {+1, -1, -1}, {+1, +1, -1}, {-1, +1, -1}, {-1, -1, +1}, {+1, -1, +1}, {+1, +1, +1}, {-1, +1, +1} }; const int quad_e[6][4] = { {3, 2, 1, 0}, {0, 1, 5, 4}, {1, 2, 6, 5}, {2, 3, 7, 6}, {3, 0, 4, 7}, {4, 5, 6, 7} }; for (int j = 0; j < Nvert; j++) { mesh->AddVertex(quad_v[j]); } for (int j = 0; j < Nelem; j++) { int attribute = j + 1; mesh->AddQuad(quad_e[j], attribute); } mesh->FinalizeQuadMesh(1, 1, true); } // Set the space for the high-order mesh nodes. H1_FECollection fec(order, mesh->Dimension()); FiniteElementSpace nodal_fes(mesh, &fec, mesh->SpaceDimension()); mesh->SetNodalFESpace(&nodal_fes); // 4. Refine the mesh while snapping nodes to the sphere. Number of parallel // refinements is fixed to 2. for (int l = 0; l <= ref_levels; l++) { if (l > 0) // for l == 0 just perform snapping { mesh->UniformRefinement(); } // Snap the nodes of the refined mesh back to sphere surface. if (always_snap) { SnapNodes(*mesh); } } if (amr == 1) { for (int l = 0; l < 3; l++) { mesh->RefineAtVertex(Vertex(0, 0, 1)); } SnapNodes(*mesh); } else if (amr == 2) { for (int l = 0; l < 2; l++) { mesh->RandomRefinement(0.5); // 50% probability } SnapNodes(*mesh); } ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh); delete mesh; { int par_ref_levels = 2; for (int l = 0; l < par_ref_levels; l++) { pmesh->UniformRefinement(); // Snap the nodes of the refined mesh back to sphere surface. if (always_snap) { SnapNodes(*pmesh); } } if (!always_snap || par_ref_levels < 1) { SnapNodes(*pmesh); } } if (amr == 1) { for (int l = 0; l < 2; l++) { pmesh->RefineAtVertex(Vertex(0, 0, 1)); } SnapNodes(*pmesh); } else if (amr == 2) { for (int l = 0; l < 2; l++) { pmesh->RandomRefinement(0.5); // 50% probability } SnapNodes(*pmesh); } // 5. Define a finite element space on the mesh. Here we use isoparametric // finite elements -- the same as the mesh nodes. ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, &fec); HYPRE_Int size = fespace->GlobalTrueVSize(); if (myid == 0) { cout << "Number of unknowns: " << size << endl; } // 6. Set up the linear form b(.) which corresponds to the right-hand side of // the FEM linear system, which in this case is (1,phi_i) where phi_i are // the basis functions in the finite element fespace. ParLinearForm *b = new ParLinearForm(fespace); ConstantCoefficient one(1.0); FunctionCoefficient rhs_coef (analytic_rhs); FunctionCoefficient sol_coef (analytic_solution); b->AddDomainIntegrator(new DomainLFIntegrator(rhs_coef)); b->Assemble(); // 7. Define the solution vector x as a finite element grid function // corresponding to fespace. Initialize x with initial guess of zero. ParGridFunction x(fespace); x = 0.0; // 8. Set up the bilinear form a(.,.) on the finite element space // corresponding to the Laplacian operator -Delta, by adding the Diffusion // and Mass domain integrators. ParBilinearForm *a = new ParBilinearForm(fespace); a->AddDomainIntegrator(new DiffusionIntegrator(one)); a->AddDomainIntegrator(new MassIntegrator(one)); // 9. Assemble the parallel linear system, applying any transformations // such as: parallel assembly, applying conforming constraints, etc. a->Assemble(); HypreParMatrix A; Vector B, X; Array<int> empty_tdof_list; a->FormLinearSystem(empty_tdof_list, x, *b, A, X, B); // 10. Define and apply a parallel PCG solver for AX=B with the BoomerAMG // preconditioner from hypre. Extract the parallel grid function x // corresponding to the finite element approximation X. This is the local // solution on each processor. HypreSolver *amg = new HypreBoomerAMG(A); HyprePCG *pcg = new HyprePCG(A); pcg->SetTol(1e-12); pcg->SetMaxIter(200); pcg->SetPrintLevel(2); pcg->SetPreconditioner(*amg); pcg->Mult(B, X); a->RecoverFEMSolution(X, *b, x); delete a; delete b; // 11. Compute and print the L^2 norm of the error. double err = x.ComputeL2Error(sol_coef); if (myid == 0) { cout << "\nL2 norm of error: " << err << endl; } // 12. Save the refined mesh and the solution. This output can be viewed // later using GLVis: "glvis -np <np> -m sphere_refined -g sol". { ostringstream mesh_name, sol_name; mesh_name << "sphere_refined." << setfill('0') << setw(6) << myid; sol_name << "sol." << setfill('0') << setw(6) << myid; ofstream mesh_ofs(mesh_name.str().c_str()); mesh_ofs.precision(8); pmesh->Print(mesh_ofs); ofstream sol_ofs(sol_name.str().c_str()); sol_ofs.precision(8); x.Save(sol_ofs); } // 13. Send the solution by socket to a GLVis server. if (visualization) { char vishost[] = "localhost"; int visport = 19916; socketstream sol_sock(vishost, visport); sol_sock << "parallel " << num_procs << " " << myid << "\n"; sol_sock.precision(8); sol_sock << "solution\n" << *pmesh << x << flush; } // 14. Free the used memory. delete pcg; delete amg; delete fespace; delete pmesh; MPI_Finalize(); return 0; }
int main(int argc, char *argv[]) { // 1. Parse command-line options. int elem_type = 1; int ref_levels = 2; int amr = 0; int order = 2; bool always_snap = false; bool visualization = 1; OptionsParser args(argc, argv); args.AddOption(&elem_type, "-e", "--elem", "Type of elements to use: 0 - triangles, 1 - quads."); args.AddOption(&order, "-o", "--order", "Finite element order (polynomial degree)."); args.AddOption(&ref_levels, "-r", "--refine", "Number of times to refine the mesh uniformly."); args.AddOption(&amr, "-amr", "--refine-locally", "Additional local (non-conforming) refinement:" " 1 = refine around north pole, 2 = refine randomly."); args.AddOption(&visualization, "-vis", "--visualization", "-no-vis", "--no-visualization", "Enable or disable GLVis visualization."); args.AddOption(&always_snap, "-snap", "--always-snap", "-no-snap", "--snap-at-the-end", "If true, snap nodes to the sphere initially and after each refinement " "otherwise, snap only after the last refinement"); args.Parse(); if (!args.Good()) { args.PrintUsage(cout); return 1; } args.PrintOptions(cout); // 2. Generate an initial high-order (surface) mesh on the unit sphere. The // Mesh object represents a 2D mesh in 3 spatial dimensions. We first add // the elements and the vertices of the mesh, and then make it high-order // by specifying a finite element space for its nodes. int Nvert = 8, Nelem = 6; if (elem_type == 0) { Nvert = 6; Nelem = 8; } Mesh *mesh = new Mesh(2, Nvert, Nelem, 0, 3); if (elem_type == 0) // inscribed octahedron { const double tri_v[6][3] = { { 1, 0, 0}, { 0, 1, 0}, {-1, 0, 0}, { 0, -1, 0}, { 0, 0, 1}, { 0, 0, -1} }; const int tri_e[8][3] = { {0, 1, 4}, {1, 2, 4}, {2, 3, 4}, {3, 0, 4}, {1, 0, 5}, {2, 1, 5}, {3, 2, 5}, {0, 3, 5} }; for (int j = 0; j < Nvert; j++) { mesh->AddVertex(tri_v[j]); } for (int j = 0; j < Nelem; j++) { int attribute = j + 1; mesh->AddTriangle(tri_e[j], attribute); } mesh->FinalizeTriMesh(1, 1, true); } else // inscribed cube { const double quad_v[8][3] = { {-1, -1, -1}, {+1, -1, -1}, {+1, +1, -1}, {-1, +1, -1}, {-1, -1, +1}, {+1, -1, +1}, {+1, +1, +1}, {-1, +1, +1} }; const int quad_e[6][4] = { {3, 2, 1, 0}, {0, 1, 5, 4}, {1, 2, 6, 5}, {2, 3, 7, 6}, {3, 0, 4, 7}, {4, 5, 6, 7} }; for (int j = 0; j < Nvert; j++) { mesh->AddVertex(quad_v[j]); } for (int j = 0; j < Nelem; j++) { int attribute = j + 1; mesh->AddQuad(quad_e[j], attribute); } mesh->FinalizeQuadMesh(1, 1, true); } // Set the space for the high-order mesh nodes. H1_FECollection fec(order, mesh->Dimension()); FiniteElementSpace nodal_fes(mesh, &fec, mesh->SpaceDimension()); mesh->SetNodalFESpace(&nodal_fes); // 3. Refine the mesh while snapping nodes to the sphere. for (int l = 0; l <= ref_levels; l++) { if (l > 0) // for l == 0 just perform snapping { mesh->UniformRefinement(); } // Snap the nodes of the refined mesh back to sphere surface. if (always_snap || l == ref_levels) { SnapNodes(*mesh); } } if (amr == 1) { for (int l = 0; l < 5; l++) { mesh->RefineAtVertex(Vertex(0, 0, 1)); } SnapNodes(*mesh); } else if (amr == 2) { for (int l = 0; l < 4; l++) { mesh->RandomRefinement(0.5); // 50% probability } SnapNodes(*mesh); } // 4. Define a finite element space on the mesh. Here we use isoparametric // finite elements -- the same as the mesh nodes. FiniteElementSpace *fespace = new FiniteElementSpace(mesh, &fec); cout << "Number of unknowns: " << fespace->GetTrueVSize() << endl; // 5. Set up the linear form b(.) which corresponds to the right-hand side of // the FEM linear system, which in this case is (1,phi_i) where phi_i are // the basis functions in the finite element fespace. LinearForm *b = new LinearForm(fespace); ConstantCoefficient one(1.0); FunctionCoefficient rhs_coef (analytic_rhs); FunctionCoefficient sol_coef (analytic_solution); b->AddDomainIntegrator(new DomainLFIntegrator(rhs_coef)); b->Assemble(); // 6. Define the solution vector x as a finite element grid function // corresponding to fespace. Initialize x with initial guess of zero. GridFunction x(fespace); x = 0.0; // 7. Set up the bilinear form a(.,.) on the finite element space // corresponding to the Laplacian operator -Delta, by adding the Diffusion // and Mass domain integrators. BilinearForm *a = new BilinearForm(fespace); a->AddDomainIntegrator(new DiffusionIntegrator(one)); a->AddDomainIntegrator(new MassIntegrator(one)); // 8. Assemble the linear system, apply conforming constraints, etc. a->Assemble(); SparseMatrix A; Vector B, X; Array<int> empty_tdof_list; a->FormLinearSystem(empty_tdof_list, x, *b, A, X, B); #ifndef MFEM_USE_SUITESPARSE // 9. Define a simple symmetric Gauss-Seidel preconditioner and use it to // solve the system AX=B with PCG. GSSmoother M(A); PCG(A, M, B, X, 1, 200, 1e-12, 0.0); #else // 9. If MFEM was compiled with SuiteSparse, use UMFPACK to solve the system. UMFPackSolver umf_solver; umf_solver.Control[UMFPACK_ORDERING] = UMFPACK_ORDERING_METIS; umf_solver.SetOperator(A); umf_solver.Mult(B, X); #endif // 10. Recover the solution as a finite element grid function. a->RecoverFEMSolution(X, *b, x); // 11. Compute and print the L^2 norm of the error. cout<<"\nL2 norm of error: " << x.ComputeL2Error(sol_coef) << endl; // 12. Save the refined mesh and the solution. This output can be viewed // later using GLVis: "glvis -m sphere_refined.mesh -g sol.gf". { ofstream mesh_ofs("sphere_refined.mesh"); mesh_ofs.precision(8); mesh->Print(mesh_ofs); ofstream sol_ofs("sol.gf"); sol_ofs.precision(8); x.Save(sol_ofs); } // 13. Send the solution by socket to a GLVis server. if (visualization) { char vishost[] = "localhost"; int visport = 19916; socketstream sol_sock(vishost, visport); sol_sock.precision(8); sol_sock << "solution\n" << *mesh << x << flush; } // 14. Free the used memory. delete a; delete b; delete fespace; delete mesh; return 0; }