I am trying to model heat diffusion on the surface of a mesh. I annexed the most important bits of theory about this topic as screenshots on the question see the bottom.
The crux of the issue is we are solving a linear system $(M - tL_C)u = \delta_y$. In this case $M$ is a diagonal matrix, $L_C$ is the discrete Laplace operator, $t$ is a constant time step equal to some epsilon and $\delta_y$ is a sparse vector with only one non-zero entry which is equal to 1.
My expectation is that, upon solving this system and drawing the resulting vertex distances, I get a fading from white to black starting at the source vertex and slowly fading away as the vertices go away from the source. I am however seeing this:
Which looks like random noise to me, as if I messed up the calculation.
I implemented the solver using Eigen, this is the snippet:
Eigen::DiagonalMatrix<float, Eigen::Dynamic> areas(sources.size()); Eigen::SparseMatrix<float> laplace_operator(sources.size(), sources.size()); for(uint i = 0; i < sources.size(); i++) laplace_operator.insert(i, i) = 0; areas.setZero(); for(uint e = 0; e < mesh.Edges().size(); e += 2) { const auto& edge = mesh.Edges()[e]; const uint i = edge.Vert().ID(); const uint j = edge.Pair().Vert().ID(); const Eigen::Vector3f e1 = -edge.Next().Dir().normalized(); const Eigen::Vector3f e2 = edge.Prev().Dir().normalized(); const float alpha = acos(e1.dot(e2)); const Eigen::Vector3f p1 = -edge.Pair().Next().Dir().normalized(); const Eigen::Vector3f p2 = edge.Pair().Prev().Dir().normalized(); const float beta = acos(p1.dot(p2)); const float laplace_coeff = -0.5f * ((1.f / tan(alpha)) + (1.f / tan(beta))); laplace_operator.insert(i, j) = laplace_coeff; laplace_operator.insert(j, i) = laplace_coeff; laplace_operator.coeffRef(i, i) -= laplace_coeff; laplace_operator.coeffRef(j, j) -= laplace_coeff; } uint count = 0; for(auto& v: mesh.Verts()) { std::vector<HMesh<VertexData>::MFace*> faces = v.ContainingFaces(); for(auto f: faces) { areas.diagonal()[count] += f->Area(); } areas.diagonal()[count] /= 3.f; count++; } SparseLU<SparseMatrix<float>, COLAMDOrdering<int> > solver; const Eigen::SparseMatrix<float> a = Eigen::SparseMatrix<float>(areas) - 0.01 * laplace_operator; solver.analyzePattern(a); solver.factorize(a); return solver.solve(sources); I have checked and sources is indeed a sparse vector with a singular source vertex set to 1 so the input is correct. The mesh operations that fetch values are very tested and they are returning what is expected, so I know the error is in the logic of this function.
I suspect my mistake might be creating the laplace operator, but I am not sure.




edgeis from i to j and edges are ordered clockwise, then $\alpha$ is betweenedge.Next()andedge.Pair().Prev()-- in your code, that'd bee1andp2. Similarly, $\beta$ is betweene2andp1. $\endgroup$edge.Pair().Prev()andedge.Next()should not be on the same face, so i fail to see how they are the correct angles, but perhaps I am just confused here. $\endgroup$edge.Next()andedge.Pair().Prev()should correspond to different faces entirely. But maybe I am not seeing something. $\endgroup$