Thực hiện 2D CSG (cho hình dạng va chạm)?


7

Có bất kỳ thuật toán đơn giản (hoặc tài liệu tốt) nào cho các hoạt động CSG cơ bản trên đa giác 2D không?

Tôi đang tìm cách để 'thêm' một số hình dạng va chạm 2D chồng chéo. Đây có thể là lồi hoặc lõm, nhưng sẽ là hình dạng đóng, được định nghĩa là một tập hợp các phân đoạn dòng, không có giao điểm tự.

Việc sử dụng này sẽ là xây dựng một tập hợp các cạnh va chạm sạch sẽ, để sử dụng với động cơ vật lý 2D, từ một cảnh bao gồm nhiều vật thể được đặt tùy ý (và thường xuyên chồng chéo), mỗi vật thể có hình dạng va chạm riêng.

Để bắt đầu, tôi chỉ cần 'thêm' hình dạng, nhưng khả năng 'trừ', để tạo lỗ, cũng có thể hữu ích.


Tự thêm một câu trả lời - như tôi đã kết thúc bằng cách sử dụng này: sourceforge.net/projects/polyclipping - thay vì cố gắng thực hiện từ đầu. Cho đến nay nó đang thực hiện công việc khá độc đáo và rất dễ sử dụng (với C #) Wikipedia có các liên kết đến một chút thông tin về chủ đề này, khi tôi bắt đầu tìm kiếm bằng cách sử dụng thuật ngữ đúng: en.wikipedia.org/wiki/ Boolean_operations_on_polygons
bluescrn

Đây là một triển khai javascript tuyệt vời của 3D CSG. Điều này chắc chắn là quá mức cho vấn đề của bạn, nhưng mã này nhỏ, sạch sẽ và được ghi chép đầy đủ, vì vậy bạn có thể học được rất nhiều bằng cách nghiên cứu nó.
DaleyPaley

Câu trả lời:


3

Đây là cho nhà thiết kế cấp, hoặc cho động cơ?

Đối với trình thiết kế mức - bạn sẽ cần mã đó để kết hợp các đối tượng tĩnh. Nghiên cứu API đồ họa vector cho giải pháp, tác vụ nghe có vẻ khá phổ biến đối với SVG, PostScript, WMF, v.v. Trước tiên hãy thử sử dụng CombineRgn Win32 API :-)

Đối với công cụ trò chơi - Tôi khuyên bạn không nên làm những gì bạn muốn .. Bạn sẽ dành số lượng lớn CPU kết hợp các đối tượng của mình lại với nhau. Bạn sẽ dành rất nhiều dự đoán sai chi nhánh để kiểm tra các điều kiện biên, kiểm tra xem 2 phân đoạn có giao nhau hay không, v.v. Và, quá trình này phải được lặp lại mỗi khung hình cho phần hiển thị của bản đồ.

Chỉ cần thực hiện kiểm tra hộp giới hạn, sau đó va chạm các đối tượng cá nhân. Nếu hình dạng đối tượng của bạn quá phức tạp - đơn giản hóa chúng trong khi xuất dữ liệu vào động cơ và sử dụng các hình dạng khác nhau để va chạm và vẽ.

Cập nhật : xem mã C # GDI + của tôi thực hiện những gì bạn muốn. Bạn có thể dễ dàng viết tương tự trong C ++: lớp GraphicsPath chỉ đơn thuần là một trình bao bọc mỏng trên các hàm gdiplus.dll tương ứng.

static class GraphicsPathExt
{
    [DllImport( @"gdiplus.dll" )]
    static extern int GdipWindingModeOutline( HandleRef path, IntPtr matrix, float flatness );

    static HandleRef getPathHandle( GraphicsPath p )
    {
        return new HandleRef( p, (IntPtr)p.GetType().GetField( "nativePath", BindingFlags.NonPublic | BindingFlags.Instance ).GetValue( p ) );
    }

    public static void FlattenPath( this GraphicsPath p )
    {
        HandleRef h = getPathHandle( p );
        int status = GdipWindingModeOutline( h, IntPtr.Zero, 0.25F );
        // TODO: see http://msdn.microsoft.com/en-us/library/ms534175(VS.85).aspx and throw a correct exception.
        if( 0 != status )
            throw new ApplicationException( "GDI+ error " + status.ToString() );
    }
}

class Program
{

    static void Main( string[] args )
    {
        PointF[] fig1 = 
        {
            new PointF(-50, 0),
            new PointF(0, 50),
            new PointF(50, 0),
        };

        PointF[] fig2 = 
        {
            new PointF(-50, 25),
            new PointF(50, 25),
            new PointF(0, -25),
        };

        GraphicsPath path1 = new GraphicsPath();
        path1.AddLines( fig1 );
        path1.CloseAllFigures();

        GraphicsPath path2 = new GraphicsPath();
        path2.AddLines( fig2 );
        path2.CloseAllFigures();

        GraphicsPath combined = new GraphicsPath();
        combined.AddPath( path1, true );
        combined.AddPath( path2, true );
        combined.FlattenPath();

        foreach (var p in combined.PathPoints)
        {
            Console.WriteLine( "<{0}, {1}>", p.X, p.Y );
        }
    }
}

2

Tôi đã viết một bằng chứng nhỏ về khái niệm đã sử dụng CSG để tạo ra trò chơi theo phong cách đất / giun thiêu đốt. Tôi đã thực hiện nó với gluTessellate . Sau đó, tôi đã ánh xạ các hình tam giác tessellated lên đa giác Box2D. Tôi có thể thêm và trừ bụi bẩn từ mô phỏng cũng như tạo và lấp lỗ hổng.

Vấn đề lớn nhất tôi tìm thấy khi sử dụng gluTessallate là nó không có vấn đề gì khi trả về các tam giác thoái hóa. Tôi đã phải lọc chúng ra trước khi chuyển các hình tam giác thành động cơ vật lý.

Một trong những điều tốt đẹp về gluTessallate là có thể xác định tính phụ thuộc từ thông tin gọi lại. Tôi không bao giờ đưa nó đi xa hơn nhưng về lý thuyết bạn có thể sử dụng kề và SCC để phát hiện chính xác việc đảo.


Thú vị, tôi sẽ phải đọc lên về điều đó. Tuy nhiên, tôi đang cố gắng tránh xa các lưới tam giác - và xử lý hoàn toàn các cạnh viền (như đối với các mục đích va chạm, bất kỳ cạnh bên trong / bao quanh nào được gắn vào một đỉnh trên đường viền có thể gây ra va chạm không mong muốn). Nhưng có lẽ một lưới tam giác như một bước trung gian, trước khi lọc ra các cạnh bên trong, là một cách tiếp cận có thể?
bluescrn

1
gluTessellate cũng chỉ có chế độ phác thảo GLU_TESS_BOUNDRY_ONLY. Liên kết tôi cung cấp có một phần ngắn cụ thể về CSG.
deft_code

Wow, trông có vẻ mạnh mẽ đáng kinh ngạc, tôi chưa bao giờ nhận ra rằng glu có chức năng đó. Có vẻ như đó là một tùy chọn (mặc dù công cụ của tôi dựa trên D3D), nhưng tôi vẫn khá tò mò về các thuật toán sẽ tham gia vào giải pháp DIY
bluescrn

Thực sự không có gì mới lạ trong tessellator của OpenGL. Tôi tưởng tượng bất kỳ tessellator tiên tiến có thể làm những điều tương tự. Ngoài ra DirectX11 có tính năng phần cứng, tôi không biết liệu nó có các tính năng nâng cao cần thiết cho CSG hay không nhưng nó sẽ đáng xem.
deft_code
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.