Nhầm lẫn về GLViewport


9

Tôi hy vọng ai đó có thể giúp tôi hiểu GLViewport và điều gì xảy ra khi chúng tôi thay đổi kích thước

Điều này sẽ minh họa cho sự nhầm lẫn của tôi ....

nhập mô tả hình ảnh ở đây

Vì vậy, ở đây tôi có một quad bị kẹt ở giữa màn hình. Nếu tôi có GLViewport phù hợp với chiều rộng và chiều cao của thiết bị, tôi sẽ nhận được những gì trên hình ảnh đầu tiên (bên trái). Chính xác những gì tôi mong đợi.

  • Độ phân giải thiết bị, 2560 x 1600
  • Độ phân giải khung nhìn 2560 x 1600
  • Kích thước Quad 200 x 200 (Lưu ý, hình ảnh trên không được chia tỷ lệ !!! :-))
  • Hình tứ giác, xuất hiện dưới dạng hình vuông

Bây giờ, cho bức ảnh thứ 2 (tay phải) ...

  • Độ phân giải thiết bị, 2560 x 1600
  • Độ phân giải khung nhìn 2560 x 1200 (và được căn giữa)
  • Kích thước Quad (200, 200)
  • Hình tứ giác, xuất hiện dưới dạng hình chữ nhật

Câu hỏi của tôi là, tại sao bây giờ quad hiển thị như một hình chữ nhật mà không phải là một hình vuông? Tôi đã xác nhận bằng cách đăng nhập rằng quad của tôi là 200 x 200 pixes - chắc chắn kích thước của các pixel vật lý vẫn giữ nguyên? Họ không thể thay đổi. Chuyện gì đang xảy ra ở đây vậy?

Tôi đã nghĩ (rõ ràng không chính xác) rằng khi tôi thu nhỏ khung nhìn, nó chỉ bị cắt bớt các pixel.

Sẽ đánh giá cao nếu ai đó có thể giải thích làm thế nào điều này hoạt động.

Biên tập

Hiện tại, tôi đang thiết lập chế độ xem của mình như thế này:

width = (int) Math.min(deviceWidth, deviceHeight * 1.702127659574468);    
height = (int) Math.min(deviceHeight, deviceWidth / 1.702127659574468);

ratio = width / height;
GLES20.glViewport(offsetX, offsetY, width, height);

Matrix.orthoM(mProjMatrix, 0, -ratio, ratio, -1, 1, 3, 7);

offsetX và offsetY chỉ để khi có hộp thư, khung nhìn được căn giữa.


Bạn đã thay đổi ma trận chiếu cũng như chế độ xem khi thay đổi từ 1600 đến 1200 pixel dọc? (bạn cần phải)
bcrist

Xin chào @bcrist, vui lòng xem chỉnh sửa của tôi để hiển thị cách tôi đang thiết lập chế độ xem của mình. Mọi thứ tôi vẽ có số pixel bằng nhau (giả sử 50 x 50 hoặc 100 x 100) đang vẽ 'kéo dài' - Có ý tưởng nào không?!
BungleBonce

BTW, nếu bạn sử dụng glScissorthay vì glViewport, nó sẽ chỉ cắt các pixel mà không thay đổi nơi mọi thứ được hiển thị. glViewporthành xử giống như thay đổi kích thước hình ảnh gốc, hơn là cắt xén nó; đó là lý do tại sao nó squish hộp của bạn.
Nathan Reed

Cảm ơn @NathanReed, tôi vẫn thực sự bối rối. Những gì tôi có là đây: Một khung nhìn đưa toàn bộ màn hình lên. Một hộp cắt kéo được chia tỷ lệ để giữ tỷ lệ của thiết bị gốc (vì vậy tôi có thể hiển thị trò chơi trong hộp cắt kéo và vẽ những thứ bên ngoài này cho filler), mọi thứ dường như được kéo dài (theo chiều dọc), vì vậy dài hơn so với chiều rộng. Tôi đang làm gì sai?
BungleBonce

Hừm. Chỉnh lưu cắt kéo không nên thay đổi bất cứ điều gì về tỷ lệ khung hình hoặc tỷ lệ của hình ảnh. Nếu nó trông chính xác mà không cần cắt kéo, thì chỉ cần kích hoạt trình cắt kéo - giữ nguyên chế độ xem, ma trận chiếu, v.v. - chỉ cần cắt hình ảnh.
Nathan Reed

Câu trả lời:


11

Để hiểu những gì đang xảy ra, bạn phải hiểu đường ống kết xuất:

Hình học của bạn (bộ tứ) ban đầu được xác định trong không gian thế giới, hãy coi đây là một hệ tọa độ toàn cầu. Bên trong bộ đổ bóng đỉnh được chuyển thành tọa độ thiết bị chuẩn hóa (NDC), một hệ tọa độ ảo được xác định sao cho mọi thứ từ -1 đến 1 sẽ được vẽ lên màn hình. Lưu ý rằng NDC nằm trong khoảng từ -1 đến 1 trong X và Y và hoàn toàn độc lập với tỷ lệ và độ phân giải của thiết bị. Việc chuyển đổi từ không gian thế giới sang NDC được thực hiện bởi mô hình, khung nhìn và ma trận chiếu (ở dạng đơn giản, chỉ một ma trận cho mọi thứ hoặc hình học thậm chí được xác định trong NDC để bắt đầu!).

Đơn vị rasterisation cần biết raster ở đâu và lớn như thế nào và đây là những gì bạn xác định với lệnh gọi glViewport: bắt đầu từ đâu là hai tham số đầu tiên, kích thước là hai tham số thứ hai. Phần cứng sau đó sẽ chuyển đổi từ NDC sang tọa độ pixel theo tỷ lệ và dịch chuyển đơn giản - và đây là những gì bạn thấy trong ví dụ của mình: một tỷ lệ trong trục Y.

Vì vậy, để đảm bảo quad của bạn được hiển thị theo tỷ lệ khung hình chính xác, bạn cũng cần điều chỉnh ma trận chiếu để bao gồm tỷ lệ khung hình dự kiến ​​của lệnh gọi glViewport.


Xin chào @Robert, cảm ơn rất nhiều vì điều này, tôi gặp một số khó khăn khi cố gắng thực hiện điều này, bạn có thể vui lòng cho một ví dụ về việc thiết lập ma trận chiếu trong câu trả lời của bạn không? Cảm ơn!
BungleBonce

4
Xin chào user22241, không có lệnh OpenGL nào để thực hiện điều này cho bạn, bạn cần tự xác định ma trận (một mảng 4 x 4 phao) và cung cấp chúng cho shader đỉnh của bạn như một bộ đồng phục. Những gì bạn cần (phối cảnh, trực giao) phụ thuộc vào những gì bạn muốn làm. Nếu các khái niệm toán học của các phép chiếu 3D là mới đối với bạn, bạn có thể muốn tìm kiếm các hướng dẫn OpenGL dạy về cấu hình cốt lõi hoạt động giống như OpenGL ES về vấn đề này.
Robert

@BungleBonce trong khi không có lệnh OpenGL cho điều này trong hồ sơ cốt lõi, bạn luôn có thể xem tài liệu về các lệnh lỗi thời như glFrustumliệt kê ma trận chính xác được xây dựng bởi các hàm này. Ma trận chiếu phổ biến khác mà bạn có thể muốn được tạo bởi glOrtho. Trong khi tất cả các lệnh này đã lỗi thời, tài liệu về chúng là một nguồn tuyệt vời của một số toán học có nguồn gốc.
Ruslan

0

Trong cuộc gọi tới glViewport, bạn chỉ định ít pixel hơn về chiều rộng và chiều cao. Ma trận chiếu của bạn được xác định theo các pixel. Đó là lý do tại sao bạn sẽ phải tính toán ma trận chiếu mới sau cuộc gọi glViewport.


Xin chào @bogglez, cảm ơn câu trả lời của bạn. Tôi đã chỉnh sửa câu hỏi của mình để hiển thị (ở phần cuối) tôi đang sử dụng mã nào cho chế độ xem của mình. Tất cả những gì tôi đang sử dụng là glViewPort - đây có phải là cách không chính xác để làm điều này? Xin vui lòng cho tôi một ví dụ về những gì bạn có ý nghĩa trong câu trả lời của bạn? Cảm ơn.
BungleBonce

Đọc này: songho.ca/opengl/gl_projectionmatrix.html Đối với 2D bạn muốn có ma trận chiếu trực giao, đối với 3D bạn có thể muốn có ma trận phối cảnh. Nếu bạn sử dụng OpenGL hiện đại, bạn sẽ cung cấp ma trận cho trình đổ bóng. Nếu bạn sử dụng OpenGL không dùng với đường ống đồ họa cố định, bạn sẽ sử dụng các chức năng như glLoadMatrix, glFrustum, v.v. để tính ma trận chiếu. Thư viện tiện ích GLU có chức năng gluPers perspective ( opengl.org/sdk/docs/man2/xhtml/gluPers perspective.xml ) và gluOrtho2D ( opengl.org/sdk/docs/man2/xhtml/gluOrtho2D.xml ) với bạn.
bogglez

0

Đối với hình ảnh đầu tiên:

  1. Chúng tôi đang tạo ma trận chiếu. Ví dụ: các tham số được sử dụng là: Left1, Right1, bottom1, Top1, Near1, Far1. Tại đây, Aspect_Ratio_1A = (Right1 - Left1) / (Top1 - bottom1);

  2. Sau đó, chúng tôi đang thực hiện một chuyển đổi cổng xem. Ví dụ: các tham số được sử dụng là: Width1, height1. (Tôi không đề cập đến các tham số thay đổi cho đơn giản). Tại đây, Aspect_Ratio_1B = Width1 / height1;

Đối với hình ảnh thứ hai:

  1. Chúng tôi đang tạo cùng một ma trận chiếu với các tham số như trước. Vậy: Aspect_Ratio_2A = Aspect_Ratio_1A;

  2. Lần này, chuyển đổi cổng xem có các tham số khác nhau: Width2 và height2. Tại đây, Aspect_Ratio_2B = Width2 / height2.

Chúng tôi lưu ý rằng Aspect_Ratio_1B và Aspect_Ratio_2B là khác nhau. Cụ thể họ là:

Aspect_Ratio_1B = 2560/1600 = 1.6 Aspect_Ratio_2B = 2560/1200 = 2.13

Vì vậy, nếu chúng tôi tóm tắt những gì chúng tôi đang làm cho trường hợp thứ hai là:

Chúng tôi đang chiếu hình ảnh lên một mặt phẳng với Aspect_Ratio_2A và trước khi hiển thị nó cho người dùng, chúng tôi đang phóng to nó thành Aspect_Ratio_2B. Những người dùng khác đang yêu cầu chúng tôi sửa ma trận chiếu theo cách sao cho Aspect_Ratio_2A = Aspect_Ratio_2B.

Chúng ta cũng có thể đọc bình luận của Robert một vài lần để hiểu rõ hơn.

Ngoài ra, tôi không thể đồng ý rằng hình tứ giác màu đỏ trong bức ảnh thứ hai có kích thước 200 x 200 pixel khi được vẽ trên màn hình. Vì chúng ta biết, một pixel là một hình vuông, nếu hình tứ giác có một trong các cạnh dài hơn cạnh kia, thì mặt dài hơn sẽ có nhiều pixel hơn để được vẽ chắc chắn. Cá nhân tôi không biết đăng nhập là gì, nhưng có thể nó không trả về kích thước pixel màn hình.

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.