दो उन्मुख बाउंडिंग बॉक्स (OBB) के बीच सबसे तेज़ 3 डी टक्कर का पता लगाना


10

मैं अपने खेल में उस मुकाम पर हूं जहां मुझे टक्कर प्रणाली को जोड़ने की जरूरत है। मैंने जेलेट की कोशिश की, और जब यह काम किया, तो यह वह नहीं था जिसकी मुझे तलाश थी। मैं सिर्फ यह परीक्षण करने का एक सरल तरीका चाहता हूं कि दो उन्मुख बाउंडिंग बॉक्स (OBB) पेड़ टकरा रहे हैं या नहीं।

मैं पेड़ का इस्तेमाल करके टक्कर मारने वाला था। ब्रॉडपेज़ के लिए एक एएबीबी बनाएं, फिर अगर पेड़ में प्रत्येक ओबीबी दूसरे पेड़ से टकराता है तो यह परीक्षा पास करता है।

मुझे इंटरनेट पर कुछ चीजें मिलीं, लेकिन मैं उन्हें पूरी तरह से समझ नहीं पाया। मैं जो पूछ रहा हूं वह एक वेबसाइट या संसाधन है जो 3 डी ओबीबी टक्करों को अच्छी तरह से समझाता है।

मुझे पता चला कि जीजेके सैट से तेज है, और यह मुझे यह बताने में सक्षम है कि बक्से एक दूसरे से कितनी दूर तक घुसते हैं। मुझे कुछ GJK सामान मिले, लेकिन वे बक्से नहीं थे; इसके बजाय, अधिक जटिल और भ्रमित करने वाली चीजें।

मैं बस 3 वैक्टर से एक ओबीबी बनाने में सक्षम होना चाहता हूं: प्रत्येक अक्ष के केंद्र, आकार और रोटेशन। फिर उन लोगों के साथ टकराव का परीक्षण करने में सक्षम हो। आपके द्वारा पोस्ट की गई किसी भी चीज के लिए अग्रिम धन्यवाद।


आप सुनिश्चित करें कि आपको बाउंडिंग बॉक्स की आवश्यकता है? यदि आपके पास हड्डियों का एक पेड़ है, और आपके पास प्रत्येक हड्डी के केंद्र और एक मोटा विचार है, तो बाउंडिंग गोले आसान होते हैं और लागू करने के लिए बहुत तेज़ होते हैं।
जॉन्हबीरड

जवाबों:


0

मैंने आपकी टिप्पणी में लिंक देखा जिसमें ओबीबी के साथ चरित्र दिखाया गया था जो मेष के चारों ओर अभिभूत थे। कभी-कभी यह बाउंडिंग क्षेत्रों के साथ किया जा सकता है और फिर कोई अभिविन्यास समस्या नहीं होती है और एक गोले का परीक्षण आमतौर पर तेज होता है।

आपका चरित्र, अगर आपके लिंक की तरह बाउंडिंग संरचनाओं को दिखा रहा है तो मिशेलिन आदमी की तरह दिखाई देगा ।


0

यहाँ एक AABB का वास्तविक कार्य उदाहरण है, जो सीधे मेरे गेम इंजन से है:

using System;
using OpenTK;
using OpenTK.Graphics.OpenGL;

namespace GrimoireEngine.Framework.Maths
{
    public struct BoundingBox : IEquatable<BoundingBox>
    {
        public Vector3 Min;
        public Vector3 Max;

        public const int CornerCount = 8;

        public static Vector3 MaxVector3
        {
            get
            {
                return new Vector3(float.MaxValue);
            }
        }

        public static Vector3 MinVector3
        {
            get
            {
                return new Vector3(float.MinValue);
            }
        }

        public static BoundingBox Identity
        {
            get
            {
                return new BoundingBox(Vector3.Zero, Vector3.One);
            }
        }

        public static BoundingBox Zero
        {
            get
            {
                return new BoundingBox();
            }
        }

        public BoundingBox(Vector3 min, Vector3 max)
        {
            Min = min;
            Max = max;
        }

        public BoundingBox(
            float minX, float minY, float minZ,
            float maxX, float maxY, float maxZ)
            : this(
                new Vector3(minX, minY, minZ),
                new Vector3(maxX, maxY, maxZ))
        { }

        public bool Collides(BoundingBox box)
        {
            if (box.Max.X < Min.X
                || box.Min.X > Max.X
                || box.Max.Y < Min.Y
                || box.Min.Y > Max.Y
                || box.Max.Z < Min.Z
                || box.Min.Z > Max.Z)
            {
                return false;
            }
            if (box.Min.X >= Min.X
                && box.Max.X <= Max.X
                && box.Min.Y >= Min.Y
                && box.Max.Y <= Max.Y
                && box.Min.Z >= Min.Z
                && box.Max.Z <= Max.Z)
            {
                return true;
            }
            return true;
        }

        public ContainmentType Contains(BoundingBox box)
        {
            if (box.Max.X < Min.X
                || box.Min.X > Max.X
                || box.Max.Y < Min.Y
                || box.Min.Y > Max.Y
                || box.Max.Z < Min.Z
                || box.Min.Z > Max.Z)
            {
                return ContainmentType.Disjoint;
            }
            if (box.Min.X >= Min.X
                && box.Max.X <= Max.X
                && box.Min.Y >= Min.Y
                && box.Max.Y <= Max.Y
                && box.Min.Z >= Min.Z
                && box.Max.Z <= Max.Z)
            {
                return ContainmentType.Contains;
            }
            return ContainmentType.Intersects;
        }

        public bool Collides(BoundingFrustum frustum)
        {
            int i;
            bool contained;
            Vector3[] corners = frustum.GetCorners();
            for (i = 0; i < corners.Length; i++)
            {
                if (corners[i].X < Min.X
                    || corners[i].X > Max.X
                    || corners[i].Y < Min.Y
                    || corners[i].Y > Max.Y
                    || corners[i].Z < Min.Z
                    || corners[i].Z > Max.Z)
                {
                    contained = false;
                }
                else if (corners[i].X == Min.X
                         || corners[i].X == Max.X
                         || corners[i].Y == Min.Y
                         || corners[i].Y == Max.Y
                         || corners[i].Z == Min.Z
                         || corners[i].Z == Max.Z)
                {
                    contained = true;
                }
                else
                {
                    contained = true;
                }
                if (contained == false)
                {
                    break;
                }
            }
            if (i == corners.Length)
            {
                return true;
            }
            if (i != 0)
            {
                return true;
            }
            i++;
            for (; i < corners.Length; i++)
            {
                if (corners[i].X < Min.X
                    || corners[i].X > Max.X
                    || corners[i].Y < Min.Y
                    || corners[i].Y > Max.Y
                    || corners[i].Z < Min.Z
                    || corners[i].Z > Max.Z)
                {
                    contained = false;
                }
                else if (corners[i].X == Min.X
                         || corners[i].X == Max.X
                         || corners[i].Y == Min.Y
                         || corners[i].Y == Max.Y
                         || corners[i].Z == Min.Z
                         || corners[i].Z == Max.Z)
                {
                    contained = true;
                }
                else
                {
                    contained = true;
                }
                if (contained != true)
                {
                    return true;
                }
            }
            return true;
        }

        public ContainmentType Contains(BoundingFrustum frustum)
        {
            int i;
            ContainmentType contained;
            Vector3[] corners = frustum.GetCorners();
            for (i = 0; i < corners.Length; i++)
            {
                if (corners[i].X < Min.X
                    || corners[i].X > Max.X
                    || corners[i].Y < Min.Y
                    || corners[i].Y > Max.Y
                    || corners[i].Z < Min.Z
                    || corners[i].Z > Max.Z)
                {
                    contained = ContainmentType.Disjoint;
                }
                else if (corners[i].X == Min.X
                         || corners[i].X == Max.X
                         || corners[i].Y == Min.Y
                         || corners[i].Y == Max.Y
                         || corners[i].Z == Min.Z
                         || corners[i].Z == Max.Z)
                {
                    contained = ContainmentType.Intersects;
                }
                else
                {
                    contained = ContainmentType.Contains;
                }
                if (contained == ContainmentType.Disjoint)
                {
                    break;
                }
            }
            if (i == corners.Length)
            {
                return ContainmentType.Contains;
            }
            if (i != 0)
            {
                return ContainmentType.Intersects;
            }
            i++;
            for (; i < corners.Length; i++)
            {
                if (corners[i].X < Min.X
                    || corners[i].X > Max.X
                    || corners[i].Y < Min.Y
                    || corners[i].Y > Max.Y
                    || corners[i].Z < Min.Z
                    || corners[i].Z > Max.Z)
                {
                    contained = ContainmentType.Disjoint;
                }
                else if (corners[i].X == Min.X
                         || corners[i].X == Max.X
                         || corners[i].Y == Min.Y
                         || corners[i].Y == Max.Y
                         || corners[i].Z == Min.Z
                         || corners[i].Z == Max.Z)
                {
                    contained = ContainmentType.Intersects;
                }
                else
                {
                    contained = ContainmentType.Contains;
                }
                if (contained != ContainmentType.Contains)
                {
                    return ContainmentType.Intersects;
                }
            }
            return ContainmentType.Contains;
        }

        public bool Collides(BoundingSphere sphere)
        {
            if (sphere.Center.X - Min.X >= sphere.Radius
                && sphere.Center.Y - Min.Y >= sphere.Radius
                && sphere.Center.Z - Min.Z >= sphere.Radius
                && Max.X - sphere.Center.X >= sphere.Radius
                && Max.Y - sphere.Center.Y >= sphere.Radius
                && Max.Z - sphere.Center.Z >= sphere.Radius)
            {
                return true;
            }
            double dmin = 0;
            double e = sphere.Center.X - Min.X;
            if (e < 0)
            {
                if (e < -sphere.Radius)
                {
                    return false;
                }
                dmin += e * e;
            }
            else
            {
                e = sphere.Center.X - Max.X;
                if (e > 0)
                {
                    if (e > sphere.Radius)
                    {
                        return false;
                    }
                    dmin += e * e;
                }
            }
            e = sphere.Center.Y - Min.Y;
            if (e < 0)
            {
                if (e < -sphere.Radius)
                {
                    return false;
                }
                dmin += e * e;
            }
            else
            {
                e = sphere.Center.Y - Max.Y;
                if (e > 0)
                {
                    if (e > sphere.Radius)
                    {
                        return false;
                    }
                    dmin += e * e;
                }
            }
            e = sphere.Center.Z - Min.Z;
            if (e < 0)
            {
                if (e < -sphere.Radius)
                {
                    return false;
                }
                dmin += e * e;
            }
            else
            {
                e = sphere.Center.Z - Max.Z;
                if (e > 0)
                {
                    if (e > sphere.Radius)
                    {
                        return false;
                    }
                    dmin += e * e;
                }
            }
            return dmin <= sphere.Radius * sphere.Radius;
        }

        public ContainmentType Contains(BoundingSphere sphere)
        {
            if (sphere.Center.X - Min.X >= sphere.Radius
                && sphere.Center.Y - Min.Y >= sphere.Radius
                && sphere.Center.Z - Min.Z >= sphere.Radius
                && Max.X - sphere.Center.X >= sphere.Radius
                && Max.Y - sphere.Center.Y >= sphere.Radius
                && Max.Z - sphere.Center.Z >= sphere.Radius)
            {
                return ContainmentType.Contains;
            }
            double dmin = 0;
            double e = sphere.Center.X - Min.X;
            if (e < 0)
            {
                if (e < -sphere.Radius)
                {
                    return ContainmentType.Disjoint;
                }
                dmin += e * e;
            }
            else
            {
                e = sphere.Center.X - Max.X;
                if (e > 0)
                {
                    if (e > sphere.Radius)
                    {
                        return ContainmentType.Disjoint;
                    }
                    dmin += e * e;
                }
            }
            e = sphere.Center.Y - Min.Y;
            if (e < 0)
            {
                if (e < -sphere.Radius)
                {
                    return ContainmentType.Disjoint;
                }
                dmin += e * e;
            }
            else
            {
                e = sphere.Center.Y - Max.Y;
                if (e > 0)
                {
                    if (e > sphere.Radius)
                    {
                        return ContainmentType.Disjoint;
                    }
                    dmin += e * e;
                }
            }
            e = sphere.Center.Z - Min.Z;
            if (e < 0)
            {
                if (e < -sphere.Radius)
                {
                    return ContainmentType.Disjoint;
                }
                dmin += e * e;
            }
            else
            {
                e = sphere.Center.Z - Max.Z;
                if (e > 0)
                {
                    if (e > sphere.Radius)
                    {
                        return ContainmentType.Disjoint;
                    }
                    dmin += e * e;
                }
            }
            return dmin <= sphere.Radius * sphere.Radius ? ContainmentType.Intersects : ContainmentType.Disjoint;
        }

        public bool Collides(Vector3 point)
        {
            if (point.X < Min.X
                || point.X > Max.X
                || point.Y < Min.Y
                || point.Y > Max.Y
                || point.Z < Min.Z
                || point.Z > Max.Z)
            {
                return false;
            }
            if (point.X == Min.X
                || point.X == Max.X
                || point.Y == Min.Y
                || point.Y == Max.Y
                || point.Z == Min.Z
                || point.Z == Max.Z)
            {
                return true;
            }
            return true;
        }

        public ContainmentType Contains(Vector3 point)
        {
            ContainmentType result;
            if (point.X < Min.X
                || point.X > Max.X
                || point.Y < Min.Y
                || point.Y > Max.Y
                || point.Z < Min.Z
                || point.Z > Max.Z)
            {
                result = ContainmentType.Disjoint;
            }
            else if (point.X == Min.X
                     || point.X == Max.X
                     || point.Y == Min.Y
                     || point.Y == Max.Y
                     || point.Z == Min.Z
                     || point.Z == Max.Z)
            {
                result = ContainmentType.Intersects;
            }
            else
            {
                result = ContainmentType.Contains;
            }
            return result;
        }

        public bool Equals(BoundingBox other)
        {
            return (Min == other.Min) && (Max == other.Max);
        }

        public override bool Equals(object obj)
        {
            return (obj is BoundingBox) && Equals((BoundingBox)obj);
        }

        public Vector3[] GetCorners()
        {
            return new[] {
                new Vector3(Min.X, Max.Y, Max.Z),
                new Vector3(Max.X, Max.Y, Max.Z),
                new Vector3(Max.X, Min.Y, Max.Z),
                new Vector3(Min.X, Min.Y, Max.Z),
                new Vector3(Min.X, Max.Y, Min.Z),
                new Vector3(Max.X, Max.Y, Min.Z),
                new Vector3(Max.X, Min.Y, Min.Z),
                new Vector3(Min.X, Min.Y, Min.Z)
            };
        }

        public override int GetHashCode()
        {
            return Min.GetHashCode() + Max.GetHashCode();
        }

        public bool Intersects(BoundingBox box)
        {
            if ((Max.X >= box.Min.X) && (Min.X <= box.Max.X))
            {
                if ((Max.Y < box.Min.Y) || (Min.Y > box.Max.Y))
                {
                    return false;
                }
                return (Max.Z >= box.Min.Z) && (Min.Z <= box.Max.Z);
            }
            return false;
        }

        public bool Intersects(BoundingFrustum frustum)
        {
            return frustum.Intersects(this);
        }

        public bool Intersects(BoundingSphere sphere)
        {
            if (sphere.Center.X - Min.X > sphere.Radius
                && sphere.Center.Y - Min.Y > sphere.Radius
                && sphere.Center.Z - Min.Z > sphere.Radius
                && Max.X - sphere.Center.X > sphere.Radius
                && Max.Y - sphere.Center.Y > sphere.Radius
                && Max.Z - sphere.Center.Z > sphere.Radius)
            {
                return true;
            }
            double dmin = 0;
            if (sphere.Center.X - Min.X <= sphere.Radius)
            {
                dmin += (sphere.Center.X - Min.X) * (sphere.Center.X - Min.X);
            }
            else if (Max.X - sphere.Center.X <= sphere.Radius)
            {
                dmin += (sphere.Center.X - Max.X) * (sphere.Center.X - Max.X);
            }
            if (sphere.Center.Y - Min.Y <= sphere.Radius)
            {
                dmin += (sphere.Center.Y - Min.Y) * (sphere.Center.Y - Min.Y);
            }
            else if (Max.Y - sphere.Center.Y <= sphere.Radius)
            {
                dmin += (sphere.Center.Y - Max.Y) * (sphere.Center.Y - Max.Y);
            }
            if (sphere.Center.Z - Min.Z <= sphere.Radius)
            {
                dmin += (sphere.Center.Z - Min.Z) * (sphere.Center.Z - Min.Z);
            }
            else if (Max.Z - sphere.Center.Z <= sphere.Radius)
            {
                dmin += (sphere.Center.Z - Max.Z) * (sphere.Center.Z - Max.Z);
            }
            return dmin <= sphere.Radius * sphere.Radius;
        }

        public PlaneIntersectionType Intersects(Plane plane)
        {
            Vector3 positiveVertex;
            Vector3 negativeVertex;
            if (plane.Normal.X >= 0)
            {
                positiveVertex.X = Max.X;
                negativeVertex.X = Min.X;
            }
            else
            {
                positiveVertex.X = Min.X;
                negativeVertex.X = Max.X;
            }
            if (plane.Normal.Y >= 0)
            {
                positiveVertex.Y = Max.Y;
                negativeVertex.Y = Min.Y;
            }
            else
            {
                positiveVertex.Y = Min.Y;
                negativeVertex.Y = Max.Y;
            }
            if (plane.Normal.Z >= 0)
            {
                positiveVertex.Z = Max.Z;
                negativeVertex.Z = Min.Z;
            }
            else
            {
                positiveVertex.Z = Min.Z;
                negativeVertex.Z = Max.Z;
            }
            float distance = plane.Normal.X * negativeVertex.X + plane.Normal.Y * negativeVertex.Y + plane.Normal.Z * negativeVertex.Z + plane.D;
            if (distance > 0)
            {
                return PlaneIntersectionType.Front;
            }
            distance = plane.Normal.X * positiveVertex.X + plane.Normal.Y * positiveVertex.Y + plane.Normal.Z * positiveVertex.Z + plane.D;
            if (distance < 0)
            {
                return PlaneIntersectionType.Back;
            }
            return PlaneIntersectionType.Intersecting;
        }

        public float? Intersects(Ray ray)
        {
            return ray.Intersects(this);
        }

        public static bool operator ==(BoundingBox a, BoundingBox b)
        {
            return a.Equals(b);
        }

        public static bool operator !=(BoundingBox a, BoundingBox b)
        {
            return !a.Equals(b);
        }

        public override string ToString()
        {
            return "{{Min:" + Min + " Max:" + Max + "}}";
        }

        public void DrawImmediate()
        {
            GL.Begin(PrimitiveType.LineLoop);
            GL.Vertex3(Max.X, Max.Y, Min.Z);
            GL.Vertex3(Min.X, Max.Y, Min.Z);
            GL.Vertex3(Min.X, Min.Y, Min.Z);
            GL.Vertex3(Max.X, Min.Y, Min.Z);
            GL.End();
            GL.Begin(PrimitiveType.LineLoop);
            GL.Vertex3(Max.X, Min.Y, Max.Z);
            GL.Vertex3(Max.X, Max.Y, Max.Z);
            GL.Vertex3(Min.X, Max.Y, Max.Z);
            GL.Vertex3(Min.X, Min.Y, Max.Z);
            GL.End();
            GL.Begin(PrimitiveType.LineLoop);
            GL.Vertex3(Max.X, Max.Y, Min.Z);
            GL.Vertex3(Max.X, Max.Y, Max.Z);
            GL.Vertex3(Min.X, Max.Y, Max.Z);
            GL.Vertex3(Min.X, Max.Y, Min.Z);
            GL.End();
            GL.Begin(PrimitiveType.LineLoop);
            GL.Vertex3(Max.X, Min.Y, Max.Z);
            GL.Vertex3(Min.X, Min.Y, Max.Z);
            GL.Vertex3(Min.X, Min.Y, Min.Z);
            GL.Vertex3(Max.X, Min.Y, Min.Z);
            GL.End();
        }
    }
}

बस अन्य बाउंडिंग प्रकार विधियों को हटा दें।


3
यह मेरे लिए एक ओओबी की तरह नहीं दिखता है, लेकिन एक एएबीबी, जो ओपी के लिए क्या देख रहा है ऐसा नहीं लगता है?
Tyyppi_77

@ Tyyppi_77 प्रश्न शीर्षक "सबसे तेज़ बाउंडिंग बॉक्स एल्गोरिथम" पढ़ता है। अस्पष्ट प्रश्नों के साथ यही समस्या है।
२२:१६

3
प्रश्न निकाय काफी स्पष्ट रूप से इंगित करता है कि ओपी ओओबी के बारे में पूछ रहा है: "मैं सिर्फ एक ओबीबी बनाने में सक्षम होना चाहता हूं"।
Tyyppi_77

-2

मौली रॉकेट हमेशा के लिए आपका दोस्त है।

http://mollyrocket.com/849

लेकिन ऐसा लगता है कि आप एक बाउंडिंग बॉक्स के सामान्य उपयोग को गलत समझ रहे हैं। आप वास्तव में भौतिकी टकराव प्रणाली के लिए इसका उपयोग नहीं करते हैं। खासकर जब यह उस तरह के उपयोग के लिए बहुत ही अयोग्य हो सकता है।

शायद आप एक दृश्य ग्राफ की टक्कर क्वेरी के बारे में सोच रहे हैं? जहां आप जांचते हैं कि कोई ऑब्जेक्ट क्वाडट्री या ओक्ट्री में प्रवेश कर रहा है या नहीं, और आप अपने ग्राफ को जल्दी से पुनर्निर्माण करते हैं।


क्षमा करें यदि मुझे गलत समझा गया था। जिस तरह से मैं टक्कर करने के बारे में सोच रहा था वह जाल पर प्रत्येक हड्डी होने से एक बाउंडिंग बॉक्स था, जो प्रत्येक हड्डी के मैट्रिक्स के साथ चलता था। उदाहरण के लिए: लिंक । यह ट्रिमेश टक्कर करने की तुलना में तेज़ प्रतीत होता है, खासकर अगर मेष में कंकाल एनीमेशन होने वाला हो। मैं जटिल भौतिकी के लिए नहीं जा रहा था, मेषों के बीच टकराव की सूचना देने के लिए बस साधारण टक्कर कॉलबैक।
andrew3ds

1
आपका उत्तर बाहरी लिंक पर बहुत निर्भर करता है। मेरा सुझाव है कि किसी दिन लिंक नीचे चले जाने की स्थिति में आप प्रासंगिक जानकारी को शामिल करने के लिए उत्तर को अपडेट करें।
MichaelHouse

ओह। एक हिट बॉक्स वह है जो आप चाहते थे। हिट बॉक्स आवश्यक रूप से पेड़ नहीं हैं, और वास्तव में एएबी भी नहीं हैं। वे मूल रूप से हड्डियों से जुड़ी अदृश्य टक्कर की जाली हैं। भौतिकी पुस्तकालय जो आपने पहले इस्तेमाल किया था, वह आसानी से आपको ऐसा करने में मदद कर सकता है। लेकिन हाँ, GTK अभी भी इस तरह की प्रणाली में काफी अच्छी तरह से काम कर सकता है। खासकर अगर आप जानना चाहते हैं कि क्या किया।
चांदनीलीनलोकत
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.