예제 #1
0
void Model::calculate_normal(size_t idx)
{
  // Index is assumed
  ASSERT(!m_shapes[idx].mesh.indices.empty());

  const std::vector<unsigned int> & indices = m_shapes[idx].mesh.indices;
  const std::vector<float> & positions = m_shapes[idx].mesh.positions;

  // To store normal for each vertex
  std::vector<Vector3> new_normals(positions.size()/3, Vector3::Zero());

  // For each face, calculate face normal, add it to each vertex of the face
  for ( size_t i=0; i < indices.size(); i += 3 )
  {
    Vector3 a(positions[3*indices[i+1]  ]-positions[3*indices[i]  ],
                      positions[3*indices[i+1]+1]-positions[3*indices[i]+1],
                      positions[3*indices[i+1]+2]-positions[3*indices[i]+2]);
    Vector3 b(positions[3*indices[i+2]  ]-positions[3*indices[i]  ],
                      positions[3*indices[i+2]+1]-positions[3*indices[i]+1],
                      positions[3*indices[i+2]+2]-positions[3*indices[i]+2]);
    Vector3 n = a.cross(b).normalized();
    new_normals[indices[i  ]] += n;
    new_normals[indices[i+1]] += n;
    new_normals[indices[i+2]] += n;
  }
  for ( size_t i=0; i < new_normals.size(); i++ )
  {
    new_normals[i].normalize();
  }

  std::vector<float> & normals = m_shapes[idx].mesh.normals;
  if ( !normals.empty() )
    WARN("Overwriting exisiting normals...");
  normals.resize(positions.size());

  for ( size_t i=0; i < indices.size(); i++ )
  {
    normals[3*indices[i]  ] = new_normals[indices[i]].x();
    normals[3*indices[i]+1] = new_normals[indices[i]].y();
    normals[3*indices[i]+2] = new_normals[indices[i]].z();
  }
}
예제 #2
0
void MeshWithConnectivity::LoopSubdivision() {
	// generate new (odd) vertices

	// visited edge -> vertex position information
	// Note that this is different from the one in computeConnectivity()
	typedef std::map<std::pair<int, int>, int> edgemap_t;
	edgemap_t new_vertices;

	// The new data must be doublebuffered or otherwise some of the calculations below would
	// not read the original positions but the newly changed ones, which is slightly wrong.
	std::vector<Vec3f> new_positions(positions.size());
	std::vector<Vec3f> new_normals(normals.size());
	std::vector<Vec3f> new_colors(colors.size());

	for (size_t i = 0; i < indices.size(); ++i)
		for (int j = 0; j < 3; ++j) {
			int v0 = indices[i][j];
			int v1 = indices[i][(j+1)%3];

			// Map the edge endpoint indices to new vertex index.
			// We use min and max because the edge direction does not matter when we finally
			// rebuild the new faces (R3); this is how we always get unique indices for the map.
			auto edge = std::make_pair(min(v0, v1), max(v0, v1));

			// With naive iteration, we would find each edge twice, because each is part of two triangles
			// (if the mesh does not have any holes/empty borders). Thus, we keep track of the already
			// visited edges in the new_vertices map. That requires the small R3 task below in the 'if' block.
			if (new_vertices.find(edge) == new_vertices.end()) {
				// YOUR CODE HERE (R4): compute the position for odd (= new) vertex.
				Vec3f pos, col, norm;
				int leftvertex, rightvertex;
				// You will need to use the neighbor information to find the correct vertices.
				// Be careful with indexing!
				// No need to worry about boundaries, though (except for the extra credit!).

				// Then, use the correct weights for each four corner vertex.
				// This default implementation just puts the new vertex at the edge midpoint.
				if (j == 0)
					leftvertex = indices[i][2];
				else if (j == 1)
					leftvertex = indices[i][0];
				else
					leftvertex = indices[i][1];
				Vec3i neigh = neighborTris[i];
				bool found = false;
				for (int k = 0; k < 3; k++)
				{
					int kms = neigh[k];

					if (kms == -1)
						continue;

					int x = indices[kms][0], y= indices[kms][1], z = indices[kms][2];
					if ((indices[kms][0] == v0 || indices[kms][1] == v0 || indices[kms][2] == v0) && (indices[kms][0] == v1 || indices[kms][1] == v1 || indices[kms][2] == v1))
					{
						if ((x == v0 && y == v1) || (x == v1 && y == v0))
							rightvertex = z;
						else if ((y == v0 && z == v1) || (z == v0 && y == v1))
							rightvertex = x;
						else
							rightvertex = y;
						found = true;
						break;
					}
				}
				if (found){
					pos = ((3.0f * (positions[v0] + positions[v1])) + (positions[leftvertex] + positions[rightvertex])) / 8.0f;
					col = ((3.0f * (colors[v0] + colors[v1])) + (colors[leftvertex] + colors[rightvertex])) / 8.0f;
					norm = ((3.0f * (normals[v0] + normals[v1])) + (normals[leftvertex] + normals[rightvertex])) / 8.0f;
				}

				else {
					pos = 0.5f * (positions[v0] + positions[v1]);
					col = 0.5f * (colors[v0] + colors[v1]);
					norm = 0.5f * (normals[v0] + normals[v1]);
				}
				new_positions.push_back(pos);
				new_colors.push_back(col);
				new_normals.push_back(norm);

				// YOUR CODE HERE (R3):
				// Map the edge to the correct vertex index.
				new_vertices[edge] = new_positions.size() - 1;
				// This is just one line! Use new_vertices and the index of the just added position.
			}
		}
		// compute positions for even (old) vertices
		std::vector<bool> vertexComputed(new_positions.size(), false);

		for (int i = 0; i < (int)indices.size(); ++i) {
			for (int j = 0; j < 3; ++j) {
				int v0 = indices[i][j];

				// don't redo if this one is already done
				if (vertexComputed[v0])
					continue;

				vertexComputed[v0] = true;

				Vec3f pos, col, norm;
				std::vector<int> neighbors;
				// YOUR CODE HERE (R5): reposition the old vertices

				// This default implementation just passes the data through unchanged.
				// You need to replace these three lines with the loop over the 1-ring
				// around vertex v0, and compute the new position as a weighted average
				// of the other vertices as described in the handout.
				for (int k = 0; k < indices.size(); k++){
					for (int l = 0; l < 3; l++){
						if (indices[k][l] == v0){
							neighbors.push_back(indices[k][(l + 1) % 3]);
							neighbors.push_back(indices[k][(l + 2) % 3]);
						}
					}
				}
				sort(neighbors.begin(), neighbors.end());
				neighbors.erase(std::unique(neighbors.begin(),neighbors.end()), neighbors.end());

				int n = neighbors.size();
				float b;
				if (n>3)
					b = 3.0f / (8.0f * n);
				else if (n == 3)
					b = 3.0f / 16.0f;
				else
					b = 0.0f;
				Vec3f rightsum1, rightsum2, rightsum3;
				for (int k = 0; k < neighbors.size(); k++){
					rightsum1 += positions[neighbors[k]];
					rightsum2 += colors[neighbors[k]];
					rightsum3 += normals[neighbors[k]];
				}
				rightsum1 *= (float)b;
				rightsum2 *= (float)b;
				rightsum3 *= (float)b;
				float ks = 1.0f - (float)n*(float)b;
				rightsum1 += ks * positions[v0];
				rightsum2 += ks * colors[v0];
				rightsum3 += ks * normals[v0];
				pos = rightsum1;
				col = rightsum2;
				norm = rightsum3;

				new_positions[v0] = pos;
				new_colors[v0] = col;
				new_normals[v0] = norm;
			}
		}
		// and then, finally, regenerate topology
		// every triangle turns into four new ones
		std::vector<Vec3i> new_indices;
		new_indices.reserve(indices.size()*4);
		for (size_t i = 0; i < indices.size(); ++i) {
			Vec3i even = indices[i]; // start vertices of e_0, e_1, e_2

			// YOUR CODE HERE (R3):
			// fill in X and Y (it's the same for both)
			auto edge_a = std::make_pair(min(even.x, even.y), max(even.x, even.y));
			auto edge_b = std::make_pair(min(even.z, even.y), max(even.z, even.y));
			auto edge_c = std::make_pair(min(even.x, even.z), max(even.x, even.z));

			// The edges edge_a, edge_b and edge_c now define the vertex indices via new_vertices.
			// (The mapping is done in the loop above.)
			// The indices define the smaller triangle inside the indices defined by "even", in order.
			// Read the vertex indices out of new_vertices to build the small triangle "odd"
			int a, b, c;
			a = new_vertices[edge_a];
			b = new_vertices[edge_b];
			c = new_vertices[edge_c];
			// Vec3i odd = ...
			new_indices.push_back(Vec3i(a,b,c));
			new_indices.push_back(Vec3i(a, b, even[1]));
			new_indices.push_back(Vec3i(a,c, even[0]));
			new_indices.push_back(Vec3i(b, c, even[2]));
			// Then, construct the four smaller triangles from the surrounding big triangle  "even"
			// and the inner one, "odd". Push them to "new_indices".

			// NOTE: REMOVE the following line after you're done with the new triangles.
			// This just keeps the mesh intact and serves as an example on how to add new triangles.
			//new_indices.push_back( Vec3i( even[0], even[1], even[2] ) );
		}

		// ADD THESE LINES when R3 is finished. Replace the originals with the repositioned data.
		indices = std::move(new_indices);
		positions = std::move(new_positions);
		normals = std::move(new_normals);
		colors = std::move(new_colors);
		neighborTris.size();
}