이 자습서를 따라 듀얼 컨투어링을 구현하고 있습니다. http://www.sandboxie.com/misc/isosurf/isosurfaces.html
내 데이터 소스는 그리드 16x16x16입니다. 이 그리드를 아래에서 위로, 왼쪽에서 오른쪽으로, 먼 곳에서 먼 곳으로 이동합니다.
그리드의 각 인덱스에 대해 큐브 구조를 만듭니다.
public Cube(int x, int y, int z, Func<int, int, int, IsoData> d, float isoLevel) {
this.pos = new Vector3(x,y,z);
//only create vertices need for edges
Vector3[] v = new Vector3[4];
v[0] = new Vector3 (x + 1, y + 1, z);
v[1] = new Vector3 (x + 1, y, z + 1);
v[2] = new Vector3 (x + 1, y + 1, z + 1);
v[3] = new Vector3 (x, y + 1, z + 1);
//create edges from vertices
this.edges = new Edge[3];
edges[0] = new Edge (v[1], v[2], d, isoLevel);
edges[1] = new Edge (v[2], v[3], d, isoLevel);
edges[2] = new Edge (v[0], v[2], d, isoLevel);
}
그리드를 가로 지르는 방법으로 인해 4 개의 정점과 3 개의 모서리 만 봐야합니다. 이 그림에서 정점 2, 5, 6, 7은 내 정점 0, 1, 2, 3에 해당하고 모서리 5, 6, 10은 내 모서리 0, 1, 2에 해당합니다.
가장자리는 다음과 같습니다.
public Edge(Vector3 p0, Vector3 p1, Func<int, int, int, IsoData> d, float isoLevel) {
//get density values for edge vertices, save in vector , d = density function, data.z = isolevel
this.data = new Vector3(d ((int)p0.x, (int)p0.y, (int)p0.z).Value, d ((int)p1.x, (int)p1.y, (int)p1.z).Value, isoLevel);
//get intersection point
this.mid = LerpByDensity(p0,p1,data);
//calculate normals by gradient of surface
Vector3 n0 = new Vector3(d((int)(p0.x+1), (int)p0.y, (int)p0.z ).Value - data.x,
d((int)p0.x, (int)(p0.y+1), (int)p0.z ).Value - data.x,
d((int)p0.x, (int)p0.y, (int)(p0.z+1) ).Value - data.x);
Vector3 n1 = new Vector3(d((int)(p1.x+1), (int)p1.y, (int)p1.z ).Value - data.y,
d((int)p1.x, (int)(p1.y+1), (int)p1.z ).Value - data.y,
d((int)p1.x, (int)p1.y, (int)(p1.z+1) ).Value - data.y);
//calculate normal by averaging normal of edge vertices
this.normal = LerpByDensity(n0,n1,data);
}
그런 다음 주변 큐브를 찾아 해당 큐브의 특징점을 얻으면 모든 모서리에서 부호 변경이 있는지 확인합니다.
이제 특징점을 큐브 센터로 설정하면 블록 마인 크래프트 모양을 얻습니다. 그러나 그것은 내가 원하는 것이 아닙니다.
특징점을 찾으려면이 게시물에서와 같이하고 싶습니다 : https://gamedev.stackexchange.com/a/83757/49583
기본적으로 셀 중심에서 정점을 시작합니다. 그런 다음 정점에서 각 평면으로 가져온 모든 벡터의 평균을 계산하고 그 결과를 따라 정점을 이동하고이 단계를 고정 된 횟수만큼 반복합니다. 결과를 따라 ~ 70 % 이동하면 최소한의 반복 횟수로 안정화됩니다.
그래서 나는 비행기 수업을 받았습니다 :
private class Plane {
public Vector3 normal;
public float distance;
public Plane(Vector3 point, Vector3 normal) {
this.normal = Vector3.Normalize(normal);
this.distance = -Vector3.Dot(normal,point);
}
public float Distance(Vector3 point) {
return Vector3.Dot(this.normal, point) + this.distance;
}
public Vector3 ShortestDistanceVector(Vector3 point) {
return this.normal * Distance(point);
}
}
그리고 특징점을 얻는 함수. 각 모서리마다 하나씩 3 개의 평면을 만들고 중심까지의 거리를 평균화합니다.
public Vector3 FeaturePoint {
get {
Vector3 c = Center;
// return c; //minecraft style
Plane p0 = new Plane(edges[0].mid,edges[0].normal);
Plane p1 = new Plane(edges[1].mid,edges[1].normal);
Plane p2 = new Plane(edges[2].mid,edges[2].normal);
int iterations = 5;
for(int i = 0; i < iterations; i++) {
Vector3 v0 = p0.ShortestDistanceVector(c);
Vector3 v1 = p1.ShortestDistanceVector(c);
Vector3 v2 = p2.ShortestDistanceVector(c);
Vector3 avg = (v0+v1+v2)/3;
c += avg * 0.7f;
}
return c;
}
}
그러나 작동하지 않습니다. 꼭짓점은 모든 곳에 있습니다. 오류는 어디에 있습니까? 가장자리 정점의 법선을 평균하여 가장자리 법선을 실제로 계산할 수 있습니까? 데이터 소스로 정수 그리드 만 있기 때문에 가장자리 중간 점에서 밀도를 얻을 수 없습니다 ...
편집 : 나는 또한 http://www.mathsisfun.com/algebra/systems-linear-equations-matrices.html 여기에서 행렬을 사용하여 3 개의 평면의 교차점을 계산할 수 있다는 것을 알았습니다. 적어도 그것을 이해하는 방법입니다. 이 방법을 만들었습니다
public static Vector3 GetIntersection(Plane p0, Plane p1, Plane p2) {
Vector3 b = new Vector3(-p0.distance, -p1.distance, -p2.distance);
Matrix4x4 A = new Matrix4x4 ();
A.SetRow (0, new Vector4 (p0.normal.x, p0.normal.y, p0.normal.z, 0));
A.SetRow (1, new Vector4 (p1.normal.x, p1.normal.y, p1.normal.z, 0));
A.SetRow (2, new Vector4 (p2.normal.x, p2.normal.y, p2.normal.z, 0));
A.SetRow (3, new Vector4 (0, 0, 0, 1));
Matrix4x4 Ainv = Matrix4x4.Inverse(A);
Vector3 result = Ainv * b;
return result;
}
이 데이터로
Plane p0 = new Plane (new Vector3 (2, 0, 0), new Vector3 (1, 0, 0));
Plane p1 = new Plane (new Vector3 (0, 2, 0), new Vector3 (0, 1, 0));
Plane p2 = new Plane (new Vector3 (0, 0, 2), new Vector3 (0, 0, 1));
Vector3 cq = Plane.GetIntersection (p0, p1, p2);
(2.0, 2.0, 2.0)에서 교차점을 계산하므로 올바르게 작동한다고 가정합니다. 여전히 올바른 정점이 아닙니다. 나는 그것이 내 법칙이라고 생각합니다.
Can I actually calculate the edge normal by averaging the normal of the edge vertices?
-나는 틀릴 수도 있지만, 법선을 얻기 위해 보간하지 말라고 다른 곳에서 조언을 보았을 것입니다. 얼굴 당 계산하면 더 안전합니다. 실제로 법선 계산이 올바른지 확인하기 위해 최소 테스트 사례를 먼저 구성해야합니다. 그런 다음 계속하십시오.
Plane
정의 된 구조가 있습니다 ( 여기 참조). 여기 에는 이미 정의한 메소드가 있습니다 (Plane
C # 확장 메소드를 사용 하여 구조에 추가 할 수있는 가장 짧은 벡터 메소드는 제외 ).GetDistanceToPoint
방법 대신 방법을 사용할 수 있습니다Distance
.