दोहरी कंटूरिंग 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
।