Generate a subdivided flat grid in the XZ plane.
Vertices lie at Y = 0. U maps to X, V maps to Z. UV covers [0,1] across the full extent. Normals point along +Y throughout.
824{
825 cols = std::max(cols, 1U);
826 rows = std::max(rows, 1U);
827
828 const glm::vec3 n = glm::normalize(normal);
829 glm::vec3 u;
830 if (std::abs(n.y) < 0.9F) {
831 u = glm::normalize(glm::cross(n, glm::vec3(0.0F, 1.0F, 0.0F)));
832 } else {
833 u = glm::normalize(glm::cross(n, glm::vec3(1.0F, 0.0F, 0.0F)));
834 }
835 const glm::vec3 v = glm::normalize(glm::cross(u, n));
836
837 const float half_x = extent_x * 0.5F;
838 const float half_z = extent_z * 0.5F;
839
840 std::vector<Kakshya::MeshVertex> verts;
841 std::vector<uint32_t> indices;
842 verts.reserve(uint32_t(2 * (cols + 1) * (rows + 1)));
843 indices.reserve(uint32_t(2 * cols * rows * 6));
844
845 for (uint32_t row = 0; row <= rows; ++row) {
846 const float fv = static_cast<float>(row) / static_cast<float>(rows);
847 for (uint32_t col = 0; col <= cols; ++col) {
848 const float fu = static_cast<float>(col) / static_cast<float>(cols);
849 const glm::vec3 p = center
850 + u * glm::mix(-half_x, half_x, fu)
851 + v * glm::mix(-half_z, half_z, fv);
852 verts.push_back({
853 .position = p,
854 .uv = { fu, 1.0F - fv },
855 .normal = n,
856 });
857 }
858 }
859
860 const uint32_t stride = cols + 1;
861 const auto vert_count = static_cast<uint32_t>(verts.size());
862
863 for (uint32_t row = 0; row < rows; ++row) {
864 for (uint32_t col = 0; col < cols; ++col) {
865 const uint32_t
a = row * stride + col;
866 const uint32_t
b =
a + 1;
867 const uint32_t c =
a + stride;
868 const uint32_t d = c + 1;
869 indices.insert(indices.end(), {
a,
b, c,
b, d, c });
870 }
871 }
872
873 for (uint32_t row = 0; row <= rows; ++row) {
874 const float fv = static_cast<float>(row) / static_cast<float>(rows);
875 for (uint32_t col = 0; col <= cols; ++col) {
876 const float fu = static_cast<float>(col) / static_cast<float>(cols);
877 const glm::vec3 p = center
878 + u * glm::mix(-half_x, half_x, fu)
879 + v * glm::mix(-half_z, half_z, fv);
880 verts.push_back({
881 .position = p,
882 .uv = { fu, 1.0F - fv },
883 .normal = -n,
884 });
885 }
886 }
887
888 for (uint32_t row = 0; row < rows; ++row) {
889 for (uint32_t col = 0; col < cols; ++col) {
890 const uint32_t
a = vert_count + row * stride + col;
891 const uint32_t
b =
a + 1;
892 const uint32_t c =
a + stride;
893 const uint32_t d = c + 1;
894 indices.insert(indices.end(), { a, c, b, b, c, d });
895 }
896 }
897
898 auto data = Kakshya::MeshData::empty();
899 Kakshya::MeshInsertion ins(data.vertex_variant, data.index_variant);
900 ins.insert_flat(
901 std::span<const uint8_t>(reinterpret_cast<const uint8_t*>(verts.data()),
902 verts.size() * sizeof(Kakshya::MeshVertex)),
903 std::span<const uint32_t>(indices),
904 Kakshya::VertexLayout::for_meshes(sizeof(Kakshya::MeshVertex)));
905 data.layout = Kakshya::VertexLayout::for_meshes(sizeof(Kakshya::MeshVertex));
906 data.layout.vertex_count = static_cast<uint32_t>(verts.size());
907 return data;
908}