17#ifdef MAYAFLUX_ARCH_X64
18 const __m256 vals = _mm256_loadu_ps(v);
19 const __m256
threshold = _mm256_set1_ps(iso);
20 const __m256 cmp = _mm256_cmp_ps(vals,
threshold, _CMP_LT_OS);
21 return static_cast<uint32_t
>(_mm256_movemask_ps(cmp));
22#elif defined(MAYAFLUX_ARCH_ARM64)
23 const float32x4_t lo = vld1q_f32(v);
24 const float32x4_t hi = vld1q_f32(v + 4);
25 const float32x4_t thresh = vdupq_n_f32(iso);
30 const uint32x4_t lo_mask = vcltq_f32(lo, thresh);
31 const uint32x4_t hi_mask = vcltq_f32(hi, thresh);
35 alignas(16)
static const uint32_t k_lo_shifts[4] = { 31, 30, 29, 28 };
36 alignas(16)
static const uint32_t k_hi_shifts[4] = { 27, 26, 25, 24 };
38 const uint32x4_t lo_bits = vshlq_u32(vshrq_n_u32(lo_mask, 31),
39 vld1q_s32(
reinterpret_cast<const int32_t*
>(k_lo_shifts)));
40 const uint32x4_t hi_bits = vshlq_u32(vshrq_n_u32(hi_mask, 31),
41 vld1q_s32(
reinterpret_cast<const int32_t*
>(k_hi_shifts)));
43 const uint32x4_t combined = vorrq_u32(lo_bits, hi_bits);
44 return vaddvq_u32(combined);
47 idx |=
static_cast<uint32_t
>(v[0] < iso) << 0;
48 idx |=
static_cast<uint32_t
>(v[1] < iso) << 1;
49 idx |=
static_cast<uint32_t
>(v[2] < iso) << 2;
50 idx |=
static_cast<uint32_t
>(v[3] < iso) << 3;
51 idx |=
static_cast<uint32_t
>(v[4] < iso) << 4;
52 idx |=
static_cast<uint32_t
>(v[5] < iso) << 5;
53 idx |=
static_cast<uint32_t
>(v[6] < iso) << 6;
54 idx |=
static_cast<uint32_t
>(v[7] < iso) << 7;
70 const glm::vec3& bounds_min,
71 const glm::vec3& bounds_max,
77 res_x = std::max(res_x, 1U);
78 res_y = std::max(res_y, 1U);
79 res_z = std::max(res_z, 1U);
81 const glm::vec3 extent = bounds_max - bounds_min;
82 const glm::vec3 step {
83 extent.x /
static_cast<float>(res_x),
84 extent.y /
static_cast<float>(res_y),
85 extent.z /
static_cast<float>(res_z),
88 const uint32_t nx = res_x + 1;
89 const uint32_t ny = res_y + 1;
90 const uint32_t nz = res_z + 1;
92 const uint32_t px = nx + 2;
93 const uint32_t py = ny + 2;
94 const uint32_t pz = nz + 2;
95 const size_t num_voxels =
static_cast<size_t>(px) * py * pz;
99 const size_t sz =
static_cast<size_t>(py) * px;
101 std::vector<float> vals(num_voxels);
102 for (uint32_t iz = 0; iz < pz; ++iz) {
103 float z = bounds_min.z +
static_cast<float>(
static_cast<int32_t
>(iz) - 1) * step.z;
104 for (uint32_t iy = 0; iy < py; ++iy) {
105 float y = bounds_min.y +
static_cast<float>(
static_cast<int32_t
>(iy) - 1) * step.y;
106 size_t base_idx = (
static_cast<size_t>(iz) * py + iy) * px;
107 for (uint32_t ix = 0; ix < px; ++ix) {
108 float x = bounds_min.x +
static_cast<float>(
static_cast<int32_t
>(ix) - 1) * step.x;
109 vals[base_idx + ix] = field(glm::vec3(x, y, z));
114 std::vector<Kakshya::MeshVertex> verts;
115 std::vector<uint32_t> indices;
116 verts.reserve(
static_cast<size_t>(res_x * res_y * res_z) * 3);
117 indices.reserve(
static_cast<size_t>(res_x * res_y * res_z) * 3);
119 auto grad_at = [&](
size_t ptr) -> glm::vec3 {
121 (vals[
ptr + sx] - vals[
ptr - sx]) / step.x,
122 (vals[
ptr + sy] - vals[
ptr - sy]) / step.y,
123 (vals[
ptr + sz] - vals[
ptr - sz]) / step.z
125 float len = glm::length(n);
126 return len > 1e-7F ? (n / len) : glm::vec3(0.0F, 1.0F, 0.0F);
129 for (uint32_t iz = 0; iz < res_z; ++iz) {
130 float z0 = bounds_min.z +
static_cast<float>(iz) * step.z;
131 float z1 = z0 + step.z;
133 for (uint32_t iy = 0; iy < res_y; ++iy) {
134 float y0 = bounds_min.y +
static_cast<float>(iy) * step.y;
135 float y1 = y0 + step.y;
137 size_t voxel_ptr = (
static_cast<size_t>(iz + 1) * py + (iy + 1)) * px + 1;
139 for (uint32_t ix = 0; ix < res_x; ++ix, ++voxel_ptr) {
141 vals[voxel_ptr], vals[voxel_ptr + sx], vals[voxel_ptr + sy + sx], vals[voxel_ptr + sy],
142 vals[voxel_ptr + sz], vals[voxel_ptr + sz + sx], vals[voxel_ptr + sz + sy + sx], vals[voxel_ptr + sz + sy]
150 float x0 = bounds_min.x +
static_cast<float>(ix) * step.x;
151 float x1 = x0 + step.x;
152 const glm::vec3 c[8] = {
153 { x0, y0, z0 }, { x1, y0, z0 }, { x1, y1, z0 }, { x0, y1, z0 },
154 { x0, y0, z1 }, { x1, y0, z1 }, { x1, y1, z1 }, { x0, y1, z1 }
157 const glm::vec3 nrm[8] = {
158 grad_at(voxel_ptr), grad_at(voxel_ptr + sx), grad_at(voxel_ptr + sy + sx), grad_at(voxel_ptr + sy),
159 grad_at(voxel_ptr + sz), grad_at(voxel_ptr + sz + sx), grad_at(voxel_ptr + sz + sy + sx), grad_at(voxel_ptr + sz + sy)
165 float va = v[i1], vb = v[i2];
167 float t = (std::abs(d) < 1e-7F) ? 0.5F : ((iso_level - va) / d);
170 .position = c[i1] + t * (c[i2] - c[i1]),
171 .normal = glm::normalize(nrm[i1] + t * (nrm[i2] - nrm[i1]))
176 ep[0] = interp_edge(0, 1);
178 ep[1] = interp_edge(1, 2);
180 ep[2] = interp_edge(2, 3);
182 ep[3] = interp_edge(3, 0);
184 ep[4] = interp_edge(4, 5);
186 ep[5] = interp_edge(5, 6);
188 ep[6] = interp_edge(6, 7);
190 ep[7] = interp_edge(7, 4);
192 ep[8] = interp_edge(0, 4);
194 ep[9] = interp_edge(1, 5);
196 ep[10] = interp_edge(2, 6);
198 ep[11] = interp_edge(3, 7);
202 for (
int i = 0; tri[i] != -1; i += 3) {
203 const auto base =
static_cast<uint32_t
>(verts.size());
205 for (
int j = 0; j < 3; ++j) {
206 const auto& edge_data = ep[tri[i + j]];
207 glm::vec2 uv((edge_data.position.x - bounds_min.x) / extent.x,
208 (edge_data.position.y - bounds_min.y) / extent.y);
210 verts.push_back({ .position = edge_data.position,
212 .normal = edge_data.normal });
214 indices.insert(indices.end(), { base, base + 1, base + 2 });
226 std::span<const uint8_t>(
reinterpret_cast<const uint8_t*
>(verts.data()), verts.size() *
sizeof(
Kakshya::MeshVertex)),
227 std::span<const uint32_t>(indices),
231 data.layout.vertex_count =
static_cast<uint32_t
>(verts.size());