দ্বৈত কনট্যুরিং - বৈশিষ্ট্য বিন্দুটি সন্ধান করা, স্বাভাবিক হয়ে যায়


9

ডুয়াল কনট্যুরিং 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);

(২.০, ২.০, ২.০) একটি ছেদ গণনা করে, তাই আমি ধরে নিলাম এটি সঠিকভাবে কাজ করে। তবুও, সঠিক শিখুনটি নয়। আমি সত্যিই এটি আমার স্বাভাবিক মনে করি।


ইউনিটির ইতিমধ্যে একটি Planeকাঠামো সংজ্ঞায়িত হয়েছে ( দেখুন এখানে ), আপনি ইতিমধ্যে সংজ্ঞায়িত পদ্ধতি দিয়েছেন (সবচেয়ে সংক্ষিপ্ত ভেক্টর পদ্ধতি বাদে, যা আপনি Planeসি # এক্সটেনশন পদ্ধতি ব্যবহার করে কাঠামোতে যুক্ত করতে পারেন )। আপনি আপনার GetDistanceToPointপদ্ধতির পরিবর্তে পদ্ধতিটি ব্যবহার করতে পারেন Distance
এভিলটাক

আপনার মন্তব্যের জন্য ধন্যবাদ, আমি আমার বাস্তবায়নটি ইউনিটি বাস্তবায়নের সাথে প্রতিস্থাপন করেছি এবং এই ফাংশনটি বেসরকারী ভেক্টর 3 শর্টেস্টেস্ট্যান্সভেস্টার (প্লেন পি, ভেক্টর 3 পয়েন্ট) ব্যবহার করে {রিটার্ন পি। গেটডেসটেন্সটাইপয়েন্ট (পয়েন্ট) * পি.এনরমাল; } আমি কেবল এলোমেলোভাবে শিখুন পেয়েছি। আমার সন্দেহ হয় আমার স্বাভাবিক অবস্থা পুরোপুরি বন্ধ আছে। আমি একটি সম্পাদনাও যুক্ত করেছি, যেখানে আমি দ্বিতীয় পদ্ধতিটি চেষ্টা করেছি, সম্ভবত আপনি এটি দেখতে পারেন এবং সেখানে আমি কী ভুল করেছি তা বলতে পারেন।
এলডুডেরিনো

2
Can I actually calculate the edge normal by averaging the normal of the edge vertices?- আমার ভুল হতে পারে তবে আমি মনে করি যে আমি অন্য কোথাও পরামর্শ দেখেছি যে নরমাল হওয়ার জন্য কখনও বিভ্রান্ত হওয়া উচিত নয় - এগুলি কেবল ভালভাবে বিভক্ত হয় না। প্রতি মুখ গণনা করুন, এটি নিরাপদ। সত্যিই, আপনার স্বাভাবিকের গণনা সঠিক কিনা তা নিশ্চিত করতে আপনার প্রথমে সর্বনিম্ন পরীক্ষার কেস তৈরি করা উচিত। তারপরে এটি নিয়ে এগিয়ে যান।
ইঞ্জিনিয়ার

তবে আমি স্বাভাবিক হওয়ার পরে কেবল মুখগুলি পাই, বিমানগুলি তৈরি করতে এবং সেগুলির থেকে মুখগুলির জন্য শীর্ষগুলি আনতে আমার স্বাভাবিক প্রয়োজন। এবং আমার বর্তমান কাঠামোর সাথে বলা হিসাবে আমি কেবলমাত্র প্রান্তের শীর্ষে আমার ডেটাতে সূচক করতে পারি। বা আপনি কোন মুখের কথা বলছেন?
এলডুডেরিনো

@ এলডুডেরিনো জালের মুখগুলি (বা ত্রিভুজ) এর মতো চেহারা, তবে কীভাবে আপনি আপনার ডেটা থেকে এটি পেতে পারেন তা আমি জানি না। আপনি যদি প্রান্তগুলির পরিবর্তে ত্রিভুজ তৈরি করতে পারেন তবে সাধারণ গণনা সত্যিই সহজ হয়ে যায়।
এভিলটাক

উত্তর:


1

আপনার সমস্ত স্বাভাবিকের প্রথমে সম্পূর্ণ জরিমানা হওয়া উচিত যদি সেগুলি ফরোয়ার্ড- / পশ্চাৎ / / কেন্দ্রীয়- পার্থক্যের মধ্য দিয়ে গণনা করা হয়। সমস্যাটি হ'ল আপনি নিজের কেন্দ্রবিন্দুটি আপনার ফিচারপয়েন্ট ফাংশনে ভুল দিকটি সরিয়ে নিয়েছেন যার ফলস্বরূপ সর্বনিম্ন থেকে আরও দূরে যেতে হবে।

Vector3 c = Center;
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.GetDistanceToPoint(c) * edges[0].normal;
    Vector3 v1 = p1.GetDistanceToPoint(c) * edges[1].normal;
    Vector3 v2 = p2.GetDistanceToPoint(c) * edges[2].normal;
    Vector3 avg = (v0+v1+v2)/3;
    c -= avg * 0.7f; // Error was here!
}
return c;

এই হ্যাপেনড কারণ আপনার কোডটি কোনও বিন্দুর বিরুদ্ধে রূপান্তরিত করে না এবং আপনার ভক্সেল বাক্স থেকে ঝাঁপিয়ে পড়ে। আমি জানি না যে কোড থেকে কোডটি কেউ দ্বৈত কনট্যুরিংয়ের ব্যাখ্যা দিতে পারে কিনা ?একটি অভিক্ষেপ পদ্ধতির ব্যবহার করার উদ্দেশ্য ছিল যেখানে পয়েন্টটি বিমানের মধ্য দিয়ে প্রজেক্ট হয়:

distance = Vector3.Dot(point - origin, normal);
projectedPoint = point - distance * normal;

তবে এটি একই পদ্ধতি। আপনি যদি নিজের মূল কোডটিতে প্রক্ষেপণটি পুনরায় লিখেন তবে এর ফলাফল:

    Vector3 v0 = c - p0.GetDistanceToPoint(c) * edges[0].normal;
    Vector3 v1 = c - p1.GetDistanceToPoint(c) * edges[1].normal;
    Vector3 v2 = c - p2.GetDistanceToPoint(c) * edges[2].normal;
    c = (v0+v1+v2)/3;

এগুলিতে আবার লেখা যেতে পারে:

    Vector3 v0 = p0.GetDistanceToPoint(c) * edges[0].normal;
    Vector3 v1 = p1.GetDistanceToPoint(c) * edges[1].normal;
    Vector3 v2 = p2.GetDistanceToPoint(c) * edges[2].normal;
    c = c - (v0+v1+v2)/3;

এবং সুতরাং প্রথম কোড ফলাফল। তিনটি অ-পরিকল্পনাকারী বিমানের উপরে বিন্দুটি প্রজেক্ট করার মাধ্যমে ধীরে ধীরে এটি সর্বনিম্নের দিকে রূপান্তরিত হয় কারণ আপনি চিত্রের শো হিসাবে প্রতিটি প্লেন থেকে আপনার পয়েন্টের দূরত্বকে হ্রাস করেন।

লাল বিন্দুগুলি বৈশিষ্ট্য বিন্দুটি বোঝায়, নীল রেখাগুলি স্বাভাবিক এবং বেগুনি বিন্দুটি বিন্দুটি বিমানটিতে প্রক্ষেপণ করে। আপনার 0.7 ফ্যাক্টরটি ব্যবহার করার দরকার নেই কারণ এটি ছাড়া এটি আরও দ্রুত রূপান্তরিত হওয়া উচিত। আপনি যদি এই পদ্ধতিটি ব্যবহার করেন তবে সাবধান হন, আপনার অবিচ্ছিন্ন প্লেন না থাকলে অ্যালগরিদম কাজ করতে পারে না।


আরে, 2 বছর পরেও উত্তর পাওয়া খুব দুর্দান্ত :) আমি কোনও সমাধান খুঁজে পাই নি, তাই আমি এই প্রকল্পটি বন্ধ করে দিয়েছি, তবে আমি এই জ্ঞানটি দিয়ে এটি আবার ঘুরে দেখব এবং এটি কীভাবে চলেছে তা আপনাকে জানিয়ে দেব। ততক্ষণে একটি +1 করুন।
এলডুডেরিনো

অসাধারণ! আমি আপনাকে সাহায্য করতে পারে খুশি। যদি তোমার জন্য এটি কাজ করে, তাহলে আমাকে জানাও.
টিম রল্ফ 30'17
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.