Làm cách nào để cấu hình lại bộ đệm khung GLES của tôi sau khi xoay?


7

Lưu ý: Để giữ cho câu hỏi đơn giản nhất có thể, tôi chủ động thay đổi nội dung câu hỏi để phản ánh tình trạng hiện tại, thay vì thêm nội dung ở phía dưới.

Tôi đang thực hiện xoay giao diện cho trò chơi dựa trên GLES của mình cho iOS, được viết bằng Xamarin.iOS với OpenTK.

Tôi đang phát hiện vòng quay bằng cách ghi đè WillRotate, trong tôi UIViewControllervà tôi thiết lập lại chính xác tất cả các ma trận chiếu của mình.

Tuy nhiên, kết quả của việc vẽ một sprite trên chế độ ngang và dọc là hơi khác nhau - cảnh quan đất nước hơi mờ-.

Đây là sprite thử nghiệm tôi đang sử dụng, có kích thước 128x128 để tránh mọi lỗi làm tròn:

Hình ảnh mẫu

Ma trận chiếu thử nghiệm của tôi dựa trên màn hình 1024x768 cho iPad. Mặc dù tôi sẽ không thu nhỏ hình ảnh, tôi đang sử dụng tính năng lọc điểm, vì vậy tôi hy vọng kết xuất sẽ là pixel hoàn hảo. Vị trí kết xuất là (0, 0) một lần nữa để tránh mọi lỗi làm tròn. Sprite sẽ rơi chính xác vào ranh giới pixel cho cả dọc và ngang.

Ngoài ra, trong cả hai trường hợp, tôi đang sử dụng cùng một kết cấu với cùng một bộ lấy mẫu, cùng một trình đổ bóng và cùng một trạng thái GL.

Đây là những gì xảy ra khi tôi kết xuất sprite ở chế độ dọc. Đây là khá nhiều cách tôi mong đợi nó sẽ được hiển thị (phóng to 5x):

Chân dung gốc

Và đây là những gì xảy ra khi tôi kết xuất cùng một sprite ở chế độ ngang.

Phong cảnh gốc

Tôi tin rằng bộ đệm khung được tạo ra là 768x1024, nhưng khi xoay, nó được chế tạo để phù hợp với màn hình 1024x768, được đặt theo chiều ngang và kéo dài theo chiều dọc, và đây là nguyên nhân gây ra sự cố.

Nếu tôi đặt OpenTK để tạo bộ đệm khung 1024x1024, kết quả sẽ trở nên nhất quán trong dọc và ngang. Đây là chân dung:

Chân dung 1024

Lưu ý làm thế nào để không có biến dạng trên dọc, điều này cũng xảy ra là 1024 pixel. Biến dạng được giới hạn theo chiều ngang, trong đó độ phân giải không khớp. Đây là phong cảnh:

Cảnh 1024

Lần này sự biến dạng chuyển sang phương thẳng đứng, ủng hộ giả thuyết của tôi.

Hơn nữa, tạo ra nó ở 3072x3072, 3072 là bội số ít phổ biến nhất của 1024 và 768, kết quả là chính xác cả về dọc và ngang:

3072x3072

Lưu ý rằng đây không phải là một giải pháp, vì tôi không chỉ lãng phí rất nhiều bộ nhớ mà còn tạo ra các tạo tác đa mẫu không nhất quán với 3D, vì tỷ lệ dọc khác với tỷ lệ ngang. Ngoài ra, đây không phải là một tùy chọn cho iPhone 5, có độ phân giải 1136x640 sẽ yêu cầu tôi tạo bộ đệm khung 45440x45440.

Vì một vòng quay thiết bị có thể được coi là thay đổi kích thước cửa sổ, tôi nghĩ rằng bộ đệm khung phải được tạo lại để phù hợp với kích thước mới. Điều này là cần thiết cho Windows trên Direct3D. Tôi sẽ phải gọi swapChain.ResizeBuffers()để làm điều này trong SharpDX.

Tôi đã thử cài đặt AutoResize = truetrong máy của mình iPhoneOSGameView, nhưng sau đó bộ đệm khung bị cắt bớt khi tôi xoay giao diện, và sau đó mọi thứ biến mất khi xoay giao diện một lần nữa.

Tôi không làm gì lạ cả, khởi tạo bộ đệm khung của tôi khá là vani:

int scaling = (int)UIScreen.MainScreen.Scale;
DeviceWidth = (int)UIScreen.MainScreen.Bounds.Width * scaling;
DeviceHeight = (int)UIScreen.MainScreen.Bounds.Height * scaling;
Size = new System.Drawing.Size((int)(DeviceWidth), (int)(DeviceHeight));
Bounds = new System.Drawing.RectangleF(0, 0, DeviceWidth, DeviceHeight);
Frame = new System.Drawing.RectangleF(0, 0, DeviceWidth, DeviceHeight);
ContextRenderingApi = EAGLRenderingAPI.OpenGLES2;
AutoResize = true;
LayerRetainsBacking = true;
LayerColorFormat = EAGLColorFormat.RGBA8;

Tôi nhận được kết quả không phù hợp khi thay đổi Size, BoundsFrametrên tôi CreateFrameBufferghi đè. Thật không may, tài liệu rất không đầy đủ, vì vậy tôi đã dùng đến những thứ thay đổi ngẫu nhiên ở đây và ở đó mà không thực sự biết điều gì đang xảy ra.

Có một câu hỏi tương tự không có câu trả lời. Tuy nhiên, tôi không biết liệu họ có đang gặp phải vấn đề tương tự như tôi không.

Ngoài ra, có một mối quan tâm tương tự tại các diễn đàn xamarin , đặc biệt đề cập đến vấn đề xoay vòng. Dường như không có giải pháp nào bên ngoài việc bỏ GameViewhoàn toàn.

Là giả định của tôi rằng tái tạo bộ đệm khung là cần thiết, đúng không? Nếu vậy, có ai biết làm thế nào để làm điều đó một cách chính xác trong OpenTK cho Xamarin.iOS không?


2
Chỉ cần một ghi chú bên cạnh, có lẽ bạn có thể kiểm tra bằng hình ảnh mẫu bàn cờ 1px để thấy rõ hơn những gì đang diễn ra (nâng cấp, lấy mẫu xuống, dịch chuyển texel, v.v.)
Kromster

@Krom: Tôi có thể làm điều đó
Panda Pajama

1
Điều gì xảy ra nếu bạn không sử dụng xoay thiết bị nhưng áp dụng ma trận xoay 90 °, điều đó có làm biến dạng tương tự không?
bogglez

@bogglez Tôi cũng có thể làm điều đó
Panda Pajama

@Krom: Tôi đã thêm thông tin liên quan đến nhận xét của bạn
Panda Pajama

Câu trả lời:


1

Có, trình kết xuất phải được tạo lại khi giao diện được xoay và được đặt thành kích thước mới.

Tái tạo nó không khó. Tuy nhiên, ID renderbuffer là riêng tư iPhoneOSGameViewvà chỉ có thể truy cập thông qua thuộc Renderbuffertính, không có bộ cài đặt công khai.

Phản ánh để giải cứu! Bằng cách kiểm tra iPhoneOSGameView, tôi phát hiện ra rằng nó có chứa một trường được gọi là renderbufferdường như khá hứa hẹn là trường hậu thuẫn phía sau Renderbuffer.

Vì vậy, khi tôi phát hiện một vòng quay, tôi tạo lại trình kết xuất đồ họa của mình và sau đó đặt nó thông qua sự phản chiếu.

Làm những việc như thế này khá rủi ro, vì tôi không thực sự biết điều gì khác (nếu có gì) tôi phải thay đổi, nhưng cho đến nay nó có vẻ tốt.

public void ResizeFrameBuffer(int newWidth, int newHeight)
{
    DeviceWidth = newWidth;
    DeviceHeight = newHeight;

    Size = new System.Drawing.Size(DeviceWidth, DeviceHeight);
    Bounds = new System.Drawing.RectangleF(0, 0, DeviceWidth, DeviceHeight);

    MakeCurrent();

    int renderbuffer = Renderbuffer;

    GL.DeleteRenderbuffers(1, ref renderbuffer);

    GL.BindFramebuffer(FramebufferTarget.Framebuffer, Framebuffer);
    GL.GenRenderbuffers(1, out renderbuffer);
    GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, renderbuffer);
    EAGLContext.RenderBufferStorage((uint)RenderbufferTarget.Renderbuffer, (CAEAGLLayer)Layer);
    GL.FramebufferRenderbuffer(FramebufferTarget.Framebuffer, FramebufferSlot.ColorAttachment0, RenderbufferTarget.Renderbuffer, renderbuffer);
    GL.Viewport(0, 0, DeviceWidth, DeviceHeight);
    GL.Scissor(0, 0, DeviceWidth, DeviceHeight);

    var type = typeof(iPhoneOSGameView);
    var renderbufferField = type.GetField("renderbuffer", BindingFlags.NonPublic | BindingFlags.Instance);
    renderbufferField.SetValue(this, renderbuffer);

    Frame = new System.Drawing.RectangleF(0, 0, DeviceWidth, DeviceHeight);
}

iPhoneOSGameView chưa bao giờ thấy nó đến ...


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.