OverviewFilesCommitsIssuesDocsReleasesPeers

dc-terrain commits / 2c29b2e

dc-terrain: tell the material how coarse the mesh under it is
ARRAY_CUSTOM1 widens from R_FLOAT to RG_FLOAT: .x stays curvature, .y is the chunk's voxel size. A material substituting a finer normal for an under-detailed mesh has to know when the mesh is the limiting factor, and had no way to ask. Inferring it from camera distance is a proxy that breaks the moment the camera climbs -- ground 2 km away drawn from coarse chunks sits inside any near band you pick, so it keeps the faceted per-vertex attributes while the horizon looks right. Comparing voxel size against the pixel footprint answers the question itself. WRITTEN UNCONDITIONALLY, even where curvature is unavailable. Gating the channel on has_curv would leave .y at zero on those meshes, and a consumer dividing by it would silently switch itself off rather than fail -- the worst kind of wrong, and one that costs a long time to find on screen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2c29b2ed87bf3b4394b512e059078b742356e33c
by plankatron <fleeky@gmail.com> · 2026-09-07T17:28:11.000Z

Changed files (1) +27 -9

src/dc_terrain.cpp +27 -9
……@@ -2147,16 +2147,34 @@ void DCTerrain::_upload_cell(CellResult& result) {
21472147 }
21482148 }
21492149
2150 // CURVATURE -> ARRAY_CUSTOM1 (R_FLOAT). The third material attribute, from
2151 // qef_solve's horizontal Laplacian of the density grid. A separate channel
2152 // rather than a third component of CUSTOM0: that one is RG_FLOAT and every
2153 // shader reading it expects two projection candidates in .xy.
2150 // CURVATURE + LOD VOXEL SIZE -> ARRAY_CUSTOM1 (RG_FLOAT).
2151 //
2152 // .x is curvature, from qef_solve's horizontal Laplacian of the density
2153 // grid. A separate channel rather than a third component of CUSTOM0: that
2154 // one is RG_FLOAT and every shader reading it expects two projection
2155 // candidates in .xy.
2156 //
2157 // .y is THIS CHUNK'S VOXEL SIZE, and it is here because a material has no
2158 // other way to know how coarse the geometry under it actually is. A shader
2159 // that wants to substitute a finer normal for an under-detailed mesh was
2160 // otherwise reduced to inferring it from the pixel footprint, which is a
2161 // proxy: it gets the boundary wrong whenever the camera climbs, because
2162 // distance-to-camera and chunk LOD stop agreeing. Comparing voxel size
2163 // against the footprint answers "is the mesh coarser than a pixel" exactly.
2164 //
2165 // WRITTEN UNCONDITIONALLY, even when curvature is unavailable. Gating the
2166 // whole channel on has_curv would leave .y at zero on any mesh without
2167 // curvature, and a consumer dividing by it would silently switch itself
2168 // off rather than fail -- the worst kind of wrong.
21542169 PackedFloat32Array curv_array;
21552170 bool has_curv = (static_cast<int>(mesh_data.curv.size()) == vert_count);
2156 if (has_curv) {
2157 curv_array.resize(vert_count);
2171 curv_array.resize(vert_count * 2);
2172 {
21582173 float* cvp = curv_array.ptrw();
2159 for (int i = 0; i < vert_count; i++) cvp[i] = mesh_data.curv[i];
2174 for (int i = 0; i < vert_count; i++) {
2175 cvp[i * 2 + 0] = has_curv ? mesh_data.curv[i] : 0.0f;
2176 cvp[i * 2 + 1] = lod_voxel;
2177 }
21602178 }
21612179
21622180 Array arrays;
……@@ -2165,14 +2183,14 @@ void DCTerrain::_upload_cell(CellResult& result) {
21652183 arrays[Mesh::ARRAY_NORMAL] = normals_array;
21662184 if (has_materials) arrays[Mesh::ARRAY_COLOR] = colors_array;
21672185 if (has_proj) arrays[Mesh::ARRAY_CUSTOM0] = proj_array;
2168 if (has_curv) arrays[Mesh::ARRAY_CUSTOM1] = curv_array;
2186 arrays[Mesh::ARRAY_CUSTOM1] = curv_array;
21692187 arrays[Mesh::ARRAY_INDEX] = indices_array;
21702188
21712189 auto t_arrays = std::chrono::high_resolution_clock::now();
21722190
21732191 uint64_t surf_flags = 0;
21742192 if (has_proj) surf_flags |= (uint64_t)Mesh::ARRAY_CUSTOM_RG_FLOAT << Mesh::ARRAY_FORMAT_CUSTOM0_SHIFT;
2175 if (has_curv) surf_flags |= (uint64_t)Mesh::ARRAY_CUSTOM_R_FLOAT << Mesh::ARRAY_FORMAT_CUSTOM1_SHIFT;
2193 surf_flags |= (uint64_t)Mesh::ARRAY_CUSTOM_RG_FLOAT << Mesh::ARRAY_FORMAT_CUSTOM1_SHIFT;
21762194
21772195 Ref<ArrayMesh> arr_mesh;
21782196 arr_mesh.instantiate();