| 1419 | } |
| 1420 | |
| 1421 | void rasterizeMeshTriangle(std::vector<float>& image, |
| 1422 | std::vector<float>& depth, |
| 1423 | const int width, |
| 1424 | const int height, |
| 1425 | const lfs::core::MeshData& mesh, |
| 1426 | const size_t material_index, |
| 1427 | const MeshRenderOptions& options, |
| 1428 | const std::array<glm::vec3, 3>& screen, |
| 1429 | const std::array<glm::vec3, 3>& world, |
| 1430 | const std::array<glm::vec3, 3>& normals, |
| 1431 | const std::array<glm::vec3, 3>& tangents, |
| 1432 | const std::array<float, 3>& tangent_handedness, |
| 1433 | const std::array<glm::vec2, 3>& texcoords, |
| 1434 | const std::array<glm::vec4, 3>& colors, |
| 1435 | const glm::vec3& camera_position, |
| 1436 | const glm::vec3& light_dir, |
| 1437 | const SoftwareShadowMap& shadow_map) { |
| 1438 | const glm::vec2 p0(screen[0]); |
| 1439 | const glm::vec2 p1(screen[1]); |
| 1440 | const glm::vec2 p2(screen[2]); |
| 1441 | const float area = edgeFunction(p0, p1, p2); |
| 1442 | if (std::abs(area) <= 1e-6f) { |
| 1443 | return; |
| 1444 | } |
| 1445 | |
| 1446 | const int min_x = std::clamp( |
| 1447 | static_cast<int>(std::floor(std::min({p0.x, p1.x, p2.x}))), 0, width - 1); |
| 1448 | const int max_x = std::clamp( |
| 1449 | static_cast<int>(std::ceil(std::max({p0.x, p1.x, p2.x}))), 0, width - 1); |
| 1450 | const int min_y = std::clamp( |
| 1451 | static_cast<int>(std::floor(std::min({p0.y, p1.y, p2.y}))), 0, height - 1); |
| 1452 | const int max_y = std::clamp( |
| 1453 | static_cast<int>(std::ceil(std::max({p0.y, p1.y, p2.y}))), 0, height - 1); |
| 1454 | const size_t pixel_count = static_cast<size_t>(width) * height; |
| 1455 | |
| 1456 | for (int y = min_y; y <= max_y; ++y) { |
| 1457 | for (int x = min_x; x <= max_x; ++x) { |
| 1458 | const glm::vec2 p(static_cast<float>(x) + 0.5f, static_cast<float>(y) + 0.5f); |
| 1459 | const float w0 = edgeFunction(p1, p2, p) / area; |
| 1460 | const float w1 = edgeFunction(p2, p0, p) / area; |
| 1461 | const float w2 = edgeFunction(p0, p1, p) / area; |
| 1462 | if (w0 < 0.0f || w1 < 0.0f || w2 < 0.0f) { |
| 1463 | continue; |
| 1464 | } |
| 1465 | const float z = w0 * screen[0].z + w1 * screen[1].z + w2 * screen[2].z; |
| 1466 | const size_t pixel = static_cast<size_t>(y) * width + x; |
| 1467 | if (z >= depth[pixel]) { |
| 1468 | continue; |
| 1469 | } |
| 1470 | const glm::vec3 world_position = w0 * world[0] + w1 * world[1] + w2 * world[2]; |
| 1471 | const glm::vec3 normal = safeNormalize(w0 * normals[0] + w1 * normals[1] + w2 * normals[2], |
| 1472 | glm::normalize(glm::cross(world[1] - world[0], |
| 1473 | world[2] - world[0]))); |
| 1474 | const glm::vec3 tangent = safeNormalize(w0 * tangents[0] + w1 * tangents[1] + w2 * tangents[2], |
| 1475 | glm::vec3(1.0f, 0.0f, 0.0f)); |
| 1476 | const float handedness = w0 * tangent_handedness[0] + |
| 1477 | w1 * tangent_handedness[1] + |
| 1478 | w2 * tangent_handedness[2]; |
no test coverage detected