| … | … | @@ -2147,16 +2147,34 @@ void DCTerrain::_upload_cell(CellResult& result) { |
| 2147 | 2147 | } |
| 2148 | 2148 | } |
| 2149 | 2149 | |
| 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. |
| 2154 | 2169 | PackedFloat32Array curv_array; |
| 2155 | 2170 | 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 | { |
| 2158 | 2173 | 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 | } |
| 2160 | 2178 | } |
| 2161 | 2179 | |
| 2162 | 2180 | Array arrays; |
| … | … | @@ -2165,14 +2183,14 @@ void DCTerrain::_upload_cell(CellResult& result) { |
| 2165 | 2183 | arrays[Mesh::ARRAY_NORMAL] = normals_array; |
| 2166 | 2184 | if (has_materials) arrays[Mesh::ARRAY_COLOR] = colors_array; |
| 2167 | 2185 | 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; |
| 2169 | 2187 | arrays[Mesh::ARRAY_INDEX] = indices_array; |
| 2170 | 2188 | |
| 2171 | 2189 | auto t_arrays = std::chrono::high_resolution_clock::now(); |
| 2172 | 2190 | |
| 2173 | 2191 | uint64_t surf_flags = 0; |
| 2174 | 2192 | 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; |
| 2176 | 2194 | |
| 2177 | 2195 | Ref<ArrayMesh> arr_mesh; |
| 2178 | 2196 | arr_mesh.instantiate(); |