opengl 菱形十二面体的精确符号距离函数

wf82jlnq  于 2024-01-07  发布在  其他
关注(0)|答案(1)|浏览(197)

我正在使用一个带有rhombic dodecahedra形状的体素的光线行进引擎,因为它们可以像2D空间的六边形一样完美地测试3D空间。问题是,我只得到了该实体的signed distance function的近似值。渲染体素是可以的,但它会给出非常尖锐的边缘。我想使用精确的SDF。
"有人知道菱形十二角体的SDF吗?"
以下是我的SDF(不准确):

  1. float Sdf(Voxel voxel, vec3 position) {
  2. position = position - voxel.Position;
  3. // Exploit the solid's symmetries
  4. position = vec3(abs(position.x), sign(position.z) * position.y, abs(position.z));
  5. // distance to each face
  6. float a = dot(vec3(1. , 0. , 0. ), position) - voxelSize;
  7. float b = dot(vec3(0.5 , 0. , sqrt3 / 2. ), position) - voxelSize;
  8. float c = dot(vec3(0. , - sqrt2 / sqrt3, 1. / sqrt3 ), position) - voxelSize;
  9. float d = dot(vec3(0.5 , sqrt2 / sqrt3, sqrt3 / 6. ), position) - voxelSize;
  10. float e = dot(vec3(0.5 , - sqrt2 / sqrt3, - sqrt3 / 6.), position) - voxelSize;
  11. return max(a, max(b, max(c, max(d, e))));
  12. }

字符串
它看起来是这样的:

编辑:

因此,我对如何处理这个问题有了一些新的想法。在这个新技术中,我试图找到不同的区域,它们将有不同的距离公式(取决于离实体最近的点是在面上、边上还是顶点上)并分别计算它们的距离。到目前为止,我只有最近点在面上或边上的区域的正确间距和距离。代码如下所示:

  1. float Sdf(Voxel voxel, vec3 position){
  2. position = position - voxel.Position;
  3. vec3 normals[6];
  4. float dists[6];
  5. float signs[6];
  6. // The rhombic dodecahedron has 6 pairs of opposite faces.
  7. // Assign a normal to each pair of faces.
  8. normals[0] = vec3(1. , 0. , 0. );
  9. normals[1] = vec3(0.5 , 0. , sqrt3 / 2. );
  10. normals[2] = vec3(0.5 , 0. , - sqrt3 / 2.);
  11. normals[3] = vec3(0. , - sqrt2 / sqrt3, 1. / sqrt3 );
  12. normals[4] = vec3(0.5 , sqrt2 / sqrt3, sqrt3 / 6. );
  13. normals[5] = vec3(0.5 , - sqrt2 / sqrt3, - sqrt3 / 6.);
  14. // Compute the distance to each face (the sign tells which face of the pair of faces is closest)
  15. for (int i = 0; i < 6; i++){
  16. dists[i] = dot(normals[i], position);
  17. signs[i] = sign(dists[i]);
  18. dists[i] = max(0., abs(dists[i]) - voxelSize);
  19. }
  20. bool sorted = false;
  21. while(!sorted){
  22. sorted = true;
  23. for (int i = 0; i < 5; i++){
  24. if (dists[i] < dists[i+1]){
  25. vec3 n = normals[i];
  26. float d = dists[i];
  27. float s = signs[i];
  28. normals[i] = normals[i+1];
  29. dists[i] = dists[i+1];
  30. signs[i] = signs[i+1];
  31. normals[i+1] = n;
  32. dists[i+1] = d;
  33. signs[i+1] = s;
  34. sorted = false;
  35. }
  36. }
  37. }
  38. if (dists[1] < dists[0] * 0.5){ //0.5 comes from sin(pi/6)
  39. // case where the closest point is on a face
  40. return dists[0];
  41. }
  42. else if (dists[2] == 0.){
  43. // case where the closest point is on an edge
  44. float a = 0.5 * dists[0];
  45. float b = 0.5 * (dists[1] - a);
  46. return length((dists[0] - b) * signs[0] * normals[0]
  47. + (dists[1] - a) * signs[1] * normals[1]);
  48. }
  49. else {
  50. //dunno
  51. }
  52. }


这里有一个简单的草图,展示了我的方法

剩下的案子越来越疯狂了,如果有突破,我会更新帖子的。

js4nwp54

js4nwp541#

前言

假设菱形十二面体的方向为seen here
此方向使其相对于沿着所有三个坐标平面的镜像对称。
然后,您需要的是一个适用于(+,+,+)八分区中this shape的sdf。

替代近似值

形状可以被看作是三个平面的联合。利用曼哈顿距离,可以定义近似sdf的替代方案:

  1. float Sdf(float3 position, float size)
  2. {
  3. position = abs(position);
  4. float halfsqrt2 = sqrt(2) / 2;
  5. float side1 = (position.x + position.y - size) * halfsqrt2;
  6. float side2 = (position.x + position.z - size) * halfsqrt2;
  7. float side3 = (position.y + position.z - size) * halfsqrt2;
  8. return max(max(side1, side2), side3);
  9. }

字符串
这可以缩写为:

  1. float Sdf(float3 position, float size)
  2. {
  3. position = abs(position);
  4. return (max(max(position.x + position.y, position.x + position.z), position.y + position.z) - size) * sqrt(2) / 2;
  5. }

准确的sdf

形状也可以看作是transformed cube。从一个矩阵转换到另一个矩阵是

  1. 0 1 1
  2. 1 0 1
  3. 1 1 0


它是逆的

  1. -0.5 0.5 0.5
  2. 0.5 -0.5 0.5
  3. 0.5 0.5 -0.5


(有多个矩阵可以工作,但这是我使用的一个)
转换后,可以使用圆框的sdf。下面是一个代码示例:

  1. float SdfRoundRhombicDodecahedron(float3 position, float size, float edgeSize)
  2. {
  3. float3x3 w2r = float3x3(
  4. 0, 1, 1,
  5. 1, 0, 1,
  6. 1, 1, 0
  7. );
  8. position = abs(position);
  9. position = mul(w2r, position);
  10. position -= clamp(position, 0, size - edgeSize);
  11. return length(position) - edgeSize;
  12. }


变换和镜像的圆形立方体然后具有菱形十二面体的形状。Here is a visualisation of it made in Unity

展开查看全部

相关问题