import trimesh import numpy as np import mesh2sdf def mesh_to_sdf_glsl(path, resolution=32): # Load mesh mesh = trimesh.load(path) print(f"\nInitial mesh:") print(f" Vertices: {len(mesh.vertices)}") print(f" Faces: {len(mesh.faces)}") print(f" Bounds: {mesh.bounds}") print(f" Extents: {mesh.extents}") # Center the mesh bounds = mesh.bounds center = (bounds[0] + bounds[1]) / 2.0 mesh.vertices -= center print(f"\nAfter centering:") print(f" Center: {center}") print(f" Bounds: {mesh.bounds}") print(f" Extents: {mesh.extents}") # Scale the mesh to fit in a reasonable size for SDF computation max_extent = np.max(mesh.extents) scale = 1.0 / max_extent mesh.vertices *= scale print(f"\nAfter scaling:") print(f" Scale factor: {scale}") print(f" Bounds: {mesh.bounds}") print(f" Extents: {mesh.extents}") print(f" Vertex range: [{np.min(mesh.vertices)}, {np.max(mesh.vertices)}]") # Convert vertices and faces to the correct types vertices = mesh.vertices.astype(np.float32) faces = mesh.faces.astype(np.uint32) print(f"\nVertex/Face types:") print(f" Vertices dtype: {vertices.dtype}") print(f" Faces dtype: {faces.dtype}") # Calculate signed distances using mesh2sdf print(f"\nComputing SDF with resolution {resolution}...") distances = mesh2sdf.compute(vertices, faces, resolution) # Debug output print(f"\nSDF computation results:") print(f" Distance range: [{np.min(distances)}, {np.max(distances)}]") print(f" Distance shape: {distances.shape}") print(f" Mean distance: {np.mean(distances)}") print(f" Std distance: {np.std(distances)}") # Check for any NaN or infinite values print(f" NaN values: {np.isnan(distances).sum()}") print(f" Inf values: {np.isinf(distances).sum()}") # Normalize distances to [-1, 1] range # This preserves the sign information which is important for SDF max_dist = np.max(np.abs(distances)) distances = distances / max_dist print(f"\nAfter normalization:") print(f" Max distance: {max_dist}") print(f" New range: [{np.min(distances)}, {np.max(distances)}]") print(f" Mean distance: {np.mean(distances)}") print(f" Std distance: {np.std(distances)}") # Split the data into chunks of 1024 elements (GLSL array size limit) chunk_size = 1024 chunks = [] flat_distances = distances.ravel() print(f"\nChunking:") print(f" Total elements: {len(flat_distances)}") print(f" Number of chunks: {len(flat_distances) // chunk_size + 1}") for i in range(0, len(flat_distances), chunk_size): chunk = flat_distances[i : i + chunk_size] chunks.append(", ".join(f"{float(v):.4f}" for v in chunk)) # Generate GLSL code with multiple arrays glsl_code = f"""// Auto-generated SDF GLSL from mesh // Resolution: {resolution}x{resolution}x{resolution} // Split into chunks to avoid GLSL array size limits float sdfData0[{len(chunks[0].split(','))}] = float[]( {chunks[0]} ); """ # Add additional chunks if needed for i in range(1, len(chunks)): glsl_code += f""" float sdfData{i}[{len(chunks[i].split(','))}] = float[]( {chunks[i]} ); """ # Add the SDF function that combines chunks glsl_code += f""" float SDF(vec3 p) {{ // Map from [-1,1] to [0,resolution-1] vec3 dim = vec3({resolution}.0); vec3 uv = (p + 1.0) * 0.5 * (dim - 1.0); // Add a small offset to avoid boundary issues uv = clamp(uv, vec3(0.0), dim - 1.0); // Use smooth interpolation between voxels ivec3 idx = ivec3(floor(uv)); vec3 frac = uv - vec3(idx); // Convert 3D index to 1D array index int i = idx.x + idx.y * {resolution} + idx.z * {resolution * resolution}; // Select the appropriate chunk and index within it int chunk = i / {chunk_size}; int local_idx = i % {chunk_size}; // Return the appropriate value based on chunk switch(chunk) {{ """ # Add switch cases for each chunk for i in range(len(chunks)): glsl_code += f" case {i}: return sdfData{i}[local_idx];\n" glsl_code += """ default: return 1.0; // Outside the volume } } """ return glsl_code