Beberapa viewports dengan OpenGL modern?


9

Saya menggunakan SDL2 .

Saat ini satu-satunya shader saya memiliki matriks MVP , dan mengubah poin dengan itu.

Saya menghitung matriks Tampilan dan Proyeksi untuk kamera dengan GLM:

glm::lookAt(pos, pos + forward, up);
glm::perspective(fov, aspectRatio, zNear, zFar);

Saya mencarinya, tetapi saya hanya dapat menemukan implementasi warisan dari beberapa viewports.

Jika saya membuat misalnya 4 kamera dan katakan saja semuanya sama , kecuali setiap kamera memiliki seperempat layar berbeda untuk ditampilkan. (Jadi saya ingin 4 viewports dengan konten yang sama)

Bagaimana saya bisa melakukan ini? Maaf jika saya tidak memberikan informasi yang cukup, jangan ragu untuk bertanya.


Apakah Anda secara khusus ingin melakukan rendering 4 kali, atau hanya membuat sekali dan menampilkan hasilnya di 4 tempat yang berbeda?
trichoplax

Lakukan rendering 4 kali. Apa yang saya tulis hanyalah contoh sederhana, misalnya saya ingin kamera utama membuat mobil di jendela penuh, dan kamera lain membuat mobil dari samping di kotak kecil di salah satu sudut.
Tudvari

Jika saya mengerti ini dengan benar maka Anda perlu membagi jendela Anda ke misalnya 4 bagian dan di setiap bagian membuat bagian lain dari adegan seperti itu ?
narthex

Ya, tetapi tidak sepenuhnya 4 bagian. Saya ingin menjadi fleksibel. Ukuran dan posisi persegi panjang viewport fleksibel.
Tudvari

Jawaban:


8

Rendering ke berbagai viewports (bagian) dari layar yang sama dapat dilakukan sebagai berikut:

Misalnya membagi layar menjadi empat bagian dan menampilkan adegan yang sama empat kali ke setiap sudut dengan seragam yang berbeda dan viewports yang berbeda:

bindFramebuffer();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
scene->setConstPerFrameUniforms();

//left bottom
glViewport(0, 0, WindowWidth*0.5, WindowHeight*0.5);
scene->setVarPerFrameUniforms(1);
scene->draw();

//right bottom
glViewport(WindowWidth*0.5, 0, WindowWidth*0.5, WindowHeight*0.5);
scene->setVarPerFrameUniforms(2);
scene->draw();

//left top
glViewport(0, WindowHeight*0.5, WindowWidth*0.5, WindowHeight*0.5);
scene->setVarPerFrameUniforms(3);
scene->draw();

//right top
glViewport(WindowWidth*0.5, WindowHeight*0.5, WindowWidth*0.5, WindowHeight*0.5);
scene->setVarPerFrameUniforms(4);
scene->draw();

glViewport(0, 0, WindowWidth, WindowHeight); //restore default

Jadi dengan glViewPort () saya dapat menentukan di mana saya ingin menggambar berikutnya, dan dengan glBlendFunc saya dapat mendefinisikan bagaimana GPU harus memadukan area yang tumpang tindih (framebuffer) satu sama lain. Apakah saya benar?
Tudvari

1
Ya, Anda bebas menentukan itu. Sebagai parameter viewportadalah x, y sudut kiri bawah chunk dan lebar, tinggi chunk. Dengan memadukan Anda dapat bereksperimen.
narthex

1
mengapa blending? bagaimana ini terkait dengan pertanyaan?
Raxvan

3
Anda tidak perlu blending atau beberapa framebuffer. Rendering tidak akan menulis ke piksel apa pun di luar persegi panjang glViewport saat ini, jadi Anda bisa mengatur dan menggambar setiap viewport secara bergantian. BTW, Anda juga dapat menggunakan tes gunting untuk membatasi pembukaan hingga persegi panjang tertentu, jika Anda ingin tumpang tindih viewports.
Nathan Reed

2
Memadukan tidak ada hubungannya dengan ini dan membuat jawabannya lebih membingungkan. Penyiapan viewports adalah semua yang diperlukan
default

10

Jika Anda menulis Vertex / Fragment Shader Anda sendiri, ada kemungkinan tambahan untuk melakukan ini. Ini jauh lebih rumit tetapi mungkin berguna untuk Anda dan / atau orang lain. Selain itu ia mempercepat seluruh proses menggambar karena hanya menggunakan satu panggilan ke perintah menggambar. Jumlah maksimum Viewports ditentukan oleh GL_MAX_VIEWPORTS dan biasanya 16.

Sejak OpenGL 4.1 ada metode glViewportArrayv . Itu dapat menentukan array Viewports. Viewports yang dibuat oleh metode ini memiliki indeks yang ditetapkan.

Indeks ini dapat digunakan dalam Vertex Shader untuk mengatur Viewport tempat adegan dibuat. (Anda harus memasukkan ekstensi " ARB_shader_viewport_layer_array " dalam kode shader)

Dalam kasus Anda, saya akan menyarankan untuk melakukan hal berikut:


" Indeks ini dapat digunakan di Vertex Shader untuk mengatur Viewport ke tempat adegan dibuat. " Tidak, tidak bisa. Ya, bukan tanpa ekstensi ARB_shader_viewport_layer_array, atau yang setara dengan AMD. Tidak ada yang standar dalam GL 4.5. Anda mungkin memikirkan Geometry Shaders.
Nicol Bolas

@Nicol, Terima kasih atas petunjuk ini! Saya lupa menyebutkan, bahwa Anda harus memasukkan ekstensi. Saya akan mengedit jawaban saya.
Christian_B

5

Ini adalah salinan jawaban @ narthex, kecuali hanya dengan viewports karena hanya itu yang Anda butuhkan. Saya tidak yakin mengapa hal-hal buffer bingkai / campuran termasuk dalam jawabannya.

//left bottom
glViewport(0, 0, WindowWidth*0.5, WindowHeight*0.5);
scene->draw();

//right bottom
glViewport(WindowWidth*0.5, 0, WindowWidth*0.5, WindowHeight*0.5);
scene->draw();

//left top
glViewport(0, WindowHeight*0.5, WindowWidth*0.5, WindowHeight*0.5);
scene->draw();

//right top
glViewport(WindowWidth*0.5, WindowHeight*0.5, WindowWidth*0.5, WindowHeight*0.5);
scene->draw();

glViewport(0, 0, WindowWidth, WindowHeight); //restore default

0

Ini semua adalah jawaban yang baik, namun ada cara lain: (Bukankah selalu ada?)

Karena semakin populernya realitas virtual, orang-orang di OculusVR telah mengembangkan trio ekstensi "Multiview" yang disebut:

  1. OVR_multiview ,
  2. OVR_multiview2 , &
  3. OVR_multiview_multisampled_render_to_texture

Ekstensi ini memungkinkan beberapa tampilan adegan yang sama untuk ditampilkan dalam satu panggilan undian, menghilangkan redundansi rendering adegan yang sama dalam keadaan yang sama dari sudut pandang masing-masing mata. Meskipun dibuat untuk tujuan VR, pengembang tidak harus terbatas hanya pada dua pandangan. Sebaliknya, ekstensi ini memungkinkan untuk dilihat sebanyak yang ditentukan oleh MAX_VIEWS_OVR .

Sebelum menggunakan ekstensi ini, pengembang harus memeriksa dukungannya pada driver grafis pengguna dengan menambahkan kode berikut:

const GLubyte* extensions = GL_CHECK( glGetString( GL_EXTENSIONS ) );
char * found_extension = strstr( (const char*)extensions, "GL_OVR_multiview" );
if (NULL == found_extension)
{
     exit( EXIT_FAILURE );
}

Dari sana, Anda perlu mengatur framebuffer Anda untuk menggunakan fitur ini:

glFramebufferTextureMultisampledMultiviewOVR = PFNGLFRAMEBUFFERTEXTUREMULTISAMPLEDMULTIVIEWOVR(eglGetProcAddress("glFramebufferTextureMultisampleMultiviewOVR"));
glFramebufferTextureMultisampledMultiviewOVR (GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, textureID, 0, 0, 2);

dan juga di shader:

#version 300 es
#extension GL_OVR_multiview : enable

layout(num_views = 2) in;
in vec3 vertexPosition;
uniform mat4 MVP[2];

void main(){
    gl_Position = MVP[gl_ViewID_OVR] * vec4(vertexPosition, 1.0f);
}

Dalam aplikasi yang terikat CPU, ekstensi ini dapat secara dramatis mengurangi waktu render, terutama dengan adegan yang lebih kompleks :

Waktu CPU relatif antara multiview dan stereo biasa.  Semakin kecil semakin baik, dengan jumlah kubus pada sumbu x dan waktu relatif pada sumbu y.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.