Modern OpenGL ile birden fazla görüntü alanı?


9

Kullandığım SDL2 .

Şu anda tek gölgelendiricimin bir MVP matrisi var ve puanları onunla dönüştürüyor.

GLM'li bir kamera için Görünüm ve Projeksiyon matrisimi hesaplıyorum:

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

Onu aradım, ancak yalnızca birden çok görünüm penceresinin eski uygulamasını bulabilirim.

Örneğin 4 kamera oluşturursam ve hepsinin aynı olduğunu varsayalım , ancak her kamera ekranın farklı bir çeyreğini oluşturacak. (Bu yüzden aynı içeriğe sahip 4 görünüm alanı istiyorum)

Bunu nasıl yapabilirim? Eğer yeterince bilgi vermediysem özür dilerim, sormaya çekinmeyin.


Özellikle render işlemini 4 kez mi yapmak istiyorsunuz yoksa sadece bir kez render etmek mi ve sonucu 4 farklı yerde mi görüntülemek istiyorsunuz?
trichoplax

İşlemeyi 4 kez gerçekleştirin. Yazdıklarım sadece basitleştirilmiş bir örnek, örneğin ana kameranın tam pencerede bir araba oluşturmasını istiyorum ve başka bir kamera arabayı köşelerden birinde küçük bir kare içinde yandan oluşturuyor.
Tudvari

Bunu doğru anladıysam, pencerenizi örneğin 4 parçaya bölmeniz ve her bölümde sahnenin diğer kısımlarını bu şekilde mi işlemeniz gerekiyor ?
narthex

Evet, ama kesinlikle 4 parça değil. Esnek olmasını istiyorum. Esnek boyut ve görünüm dikdörtgeninin konumu.
Tudvari

Yanıtlar:


8

Aynı ekranın farklı görünüm pencerelerine (parçalarına) oluşturma aşağıdaki gibi yapılabilir:

Örneğin, ekranı dört parçaya bölmek ve aynı sahneyi her bir köşeye farklı üniformalar ve farklı görünüm pencereleriyle dört kez oluşturmak:

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

Böylece glViewPort () ile bir sonraki çizmek istediğim yeri tanımlayabilirim ve glBlendFunc ile GPU'nun çakışan alanları (framebuffers) birbiriyle nasıl karıştırması gerektiğini tanımlayabilirim. Doğrumuyum?
Tudvari

1
Evet, bunu parametreleştirmekte özgürsünüz. Parametrelerin parametreleri, viewportparçanın sol alt köşesinin x, y ve genişliğinin, parçanın yüksekliğidir. Karıştırma ile deney yapabilirsiniz.
narthex

1
neden karıştırma? soruyla nasıl bağlantılı?
Raxvan

3
Karıştırma veya birden çok çerçeve tamponuna ihtiyacınız yoktur. Oluşturma, geçerli glViewport dikdörtgeni dışındaki hiçbir piksele yazmaz, böylece her bir görünümü seçip sırayla çizebilirsiniz. BTW , örtüşen görünüm pencerelerini kullanmak istediğinizde, temizliği belirli bir dikdörtgenle sınırlamak için makas testini de kullanabilirsiniz .
Nathan Reed

2
Harmanlamanın bununla hiçbir ilgisi yoktur ve cevabı daha karmaşık hale getirir. Görünümlerin kurulumu sadece gerekli
varsayılan

11

Kendi Köşe / Parça Gölgelendiricinizi yazıyorsanız, bunu yapmak için başka bir olasılık daha vardır. Çok daha karmaşıktır, ancak sizin ve / veya başkaları için yararlı olabilir. Ayrıca bir draw komutuna yalnızca bir çağrı kullandığı için tüm çizim sürecini hızlandırır. Maksimum Görüntüleme Sayısı GL_MAX_VIEWPORTS tarafından tanımlanır ve genellikle 16'dır.

OpenGL 4.1'den beri glViewportArrayv yöntemi bulunmaktadır. Bir dizi Viewports tanımlayabilir. Bu yöntemle oluşturulan Viewports'a bir dizin atanır.

Bu dizin, sahnenin oluşturulduğu Görünüm Penceresini ayarlamak için Vertex Shader'da kullanılabilir. ( Gölgelendirici koduna " ARB_shader_viewport_layer_array " uzantısını eklemeniz gerekir)

Sizin durumunuzda aşağıdakileri yapmanızı öneririm:


" Bu dizin, sahnenin oluşturulduğu Görünüm Penceresini ayarlamak için Vertex Shader'da kullanılabilir. " Hayır, yapılamaz. ARB_shader_viewport_layer_array uzantısı veya AMD eşdeğeri olmadan değil. Bunların hiçbiri GL 4.5'te standart değildir. Belki de Geometry Shader'ları düşünüyorsunuz.
Nicol Bolas

@Nicol, Bu ipucu için teşekkürler! Uzantıyı eklemeniz gerektiğini belirtmeyi unuttum. Cevabımı düzenleyeceğim.
Christian_B

5

Bu, @ narthex'in cevabının bir kopyasıdır, tek ihtiyacınız olan şey yalnızca görünüm alanları hariç. Neden çerçeve arabelleği / karışım malzemesinin cevabına dahil edildiğinden emin değilim.

//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

1

Bunların hepsi iyi cevaplar ve yine de başka bir yol var: (Her zaman yok mu?)

Sanal gerçekliğin artan popülaritesi nedeniyle, OculusVR'deki insanlar "Multiview" uzantılarının üçlüsünü geliştirdiler:

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

Bu uzantılar, aynı sahnenin birden çok görünümünün tek bir çizim çağrısında oluşturulmasına izin vererek, aynı sahnenin her bir gözün bakış açısından aynı durumda oluşturulmasının fazlalığını ortadan kaldırır. VR amacıyla oluşturulmuş olsa da, geliştirici sadece iki görünümle sınırlı değildir. Aksine, bu uzantı MAX_VIEWS_OVR tarafından belirtilen sayıda görünüme izin verir .

Bu uzantıları kullanmadan önce geliştirici, aşağıdaki kodu ekleyerek kullanıcının grafik sürücüsünde desteklerini kontrol etmelidir:

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 );
}

Oradan, bu özelliği kullanmak için çerçeve aracınızın ayarlanması önemlidir:

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

ve aynı şekilde gölgelendiricide:

#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);
}

CPU bağlantılı bir uygulamada bu uzantı , özellikle daha karmaşık sahnelerde oluşturma süresini önemli ölçüde azaltabilir :

Çoklu görüntü ve normal stereo arasındaki göreli CPU süresi.  X ekseni üzerindeki küp sayısı ve y ekseni üzerindeki göreceli süre ile ne kadar küçük olursa o kadar iyidir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.