วิวพอร์ตหลายรายการพร้อม OpenGL ที่ทันสมัย?


9

ฉันใช้SDL2

ในปัจจุบัน shader เดียวของฉันมีเมทริกซ์ MVPและแปลงคะแนนด้วย

ฉันคำนวณเมทริกซ์มุมมองและการฉายของฉันสำหรับกล้องที่มี GLM:

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

ฉันค้นหามัน แต่ฉันสามารถค้นหาการใช้งานแบบดั้งเดิมของวิวพอร์ตหลายรายการเท่านั้น

ถ้าฉันสร้างตัวอย่างสำหรับกล้อง 4 ตัวและสมมุติว่ามันเหมือนกันหมดยกเว้นกล้องทุกตัวจะมีหน้าจอที่แตกต่างกันออกไป (ดังนั้นฉันต้องการ 4 วิวพอร์ตที่มีเนื้อหาเดียวกัน)

ฉันจะทำสิ่งนี้ได้อย่างไร ขออภัยถ้าฉันไม่ได้ให้ข้อมูลเพียงพออย่าลังเลที่จะถาม


คุณกำลังมองหาการเรนเดอร์ 4 ครั้งโดยเฉพาะหรือเพียงเพื่อเรนเดอร์หนึ่งครั้งและแสดงผลลัพธ์ใน 4 ที่ต่างกันหรือไม่?
trichoplax

ดำเนินการเรนเดอร์ 4 ครั้ง สิ่งที่ฉันเขียนเป็นเพียงตัวอย่างง่าย ๆ ตัวอย่างเช่นฉันต้องการให้กล้องหลักทำการแสดงรถยนต์ที่หน้าต่างแบบเต็มและกล้องอีกตัวทำการแสดงรถจากด้านข้างในสี่เหลี่ยมจัตุรัสเล็ก ๆ ที่มุมใดมุมหนึ่ง
Tudvari

ถ้าผมเข้าใจเรื่องนี้อย่างถูกต้องดังนั้นคุณต้องแยกหน้าต่างของคุณเพื่อตัวอย่างเช่น 4 ส่วนและในแต่ละส่วนทำให้ส่วนอื่น ๆ ของฉากเช่นนั้น ?
narthex

ใช่ แต่ไม่เคร่งครัด 4 ส่วน ฉันต้องการให้ยืดหยุ่น ขนาดที่ยืดหยุ่นและตำแหน่งของสี่เหลี่ยมผืนผ้า viewport
Tudvari

คำตอบ:


8

การเรนเดอร์ไปยังวิวพอร์ตต่าง ๆ (ส่วนต่าง ๆ ) ของหน้าจอเดียวกันสามารถทำได้ดังนี้:

ตัวอย่างเช่นการแบ่งหน้าจอออกเป็นสี่ส่วนและแสดงฉากเดียวกันสี่ครั้งในแต่ละมุมด้วยเครื่องแบบที่แตกต่างกันและวิวพอร์ตที่ต่างกัน:

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

ดังนั้นด้วย glViewPort () ฉันสามารถกำหนดตำแหน่งที่ฉันต้องการวาดต่อไปและด้วย glBlendFunc ฉันสามารถกำหนดวิธีที่ GPU ควรผสมผสานพื้นที่ที่ทับซ้อนกัน (framebuffers) เข้าด้วยกัน ฉันถูกไหม?
Tudvari

1
ใช่คุณมีอิสระที่จะกำหนดว่า เนื่องจากพารามิเตอร์ของviewportคือ x, y ของมุมล่างซ้ายของก้อนและความกว้างความสูงของก้อน ด้วยการผสมคุณสามารถทดลอง
narthex

1
ทำไมต้องผสม มันเกี่ยวข้องกับคำถามอย่างไร
Raxvan

3
คุณไม่จำเป็นต้องผสมหรือ framebuffers หลายตัว การเรนเดอร์จะไม่เขียนไปยังพิกเซลใด ๆ ที่อยู่นอกสี่เหลี่ยมผืนผ้า glViewport ปัจจุบันดังนั้นคุณสามารถตั้งค่าและวาดวิวพอร์ตแต่ละอันได้ BTW คุณยังสามารถใช้การทดสอบกรรไกรเพื่อ จำกัด เคลียร์ให้กับสี่เหลี่ยมบางอันในกรณีที่คุณต้องการวิวพอร์ตที่ทับซ้อนกัน
นาธานรีด

2
การผสมไม่เกี่ยวข้องกับสิ่งนี้และทำให้คำตอบสับสนมากขึ้น การตั้งค่าวิวพอร์ตเป็นสิ่งที่จำเป็น
เริ่มต้น

11

หากคุณกำลังเขียน Vertex / Fragment Shader ของคุณเองก็มีความเป็นไปได้ที่จะทำเช่นนี้ มันซับซ้อนกว่ามาก แต่อาจมีประโยชน์สำหรับคุณและ / หรือผู้อื่น นอกจากนี้ยังเพิ่มความเร็วในกระบวนการวาดทั้งหมดเนื่องจากใช้การเรียกไปยังคำสั่ง draw เพียงครั้งเดียว จำนวนการดูสูงสุดถูกกำหนดโดย GL_MAX_VIEWPORTS และโดยปกติคือ 16

ตั้งแต่ OpenGL 4.1 มีวิธีการglViewportArrayvอยู่ มันสามารถกำหนดอาร์เรย์ของวิวพอร์ต Viewports ที่สร้างขึ้นโดยวิธีนี้มีดัชนีที่ได้รับมอบหมาย

ดัชนีนี้สามารถใช้ใน Vertex Shader เพื่อตั้งค่าวิวพอร์ตที่แสดงผลฉาก (คุณต้องรวมส่วนขยาย " ARB_shader_viewport_layer_array " ในรหัส shader)

ในกรณีของคุณฉันขอแนะนำให้ทำดังต่อไปนี้:

  • จัดเก็บเมทริกซ์กล้อง 4 ตัวใน Shader Storage Buffer (Array of mat4) เพื่อใช้ใน Vertex Shader
  • ใช้การวาดภาพที่จัดทำดัชนีตัวอย่างเช่น: glDrawElementsInstanced
  • ใช้ build ในgl_InstanceIDของ Vertex Shader เพื่อเข้าถึงอาร์เรย์เมทริกซ์ของกล้อง
  • ตั้งค่าบิวด์ในตัวแปรเอาต์พุตเอาท์พุต gl_ViewportIndex ใน Fragment Shader เป็น gl_InstanceID (สำหรับรายละเอียดดูARB_fragment_layer_viewport )

" ดัชนีนี้สามารถใช้ใน Vertex Shader เพื่อตั้งค่าวิวพอร์ตที่แสดงฉากได้ " ไม่ไม่สามารถทำได้ ก็ใช่ว่าจะไม่มีส่วนขยาย ARB_shader_viewport_layer_array หรือเทียบเท่าของ AMD ไม่มีสิ่งใดที่เป็นมาตรฐานใน GL 4.5 บางทีคุณอาจนึกถึงเรื่องเรขาคณิต
Nicol Bolas

@Nicol ขอบคุณสำหรับคำแนะนำนี้! ฉันลืมที่จะพูดถึงว่าคุณต้องรวมส่วนขยาย ฉันจะแก้ไขคำตอบของฉัน
Christian_B

5

นี่เป็นสำเนาของคำตอบของ @ narthex ยกเว้นมีวิวพอร์ตเพียงอย่างเดียวเนื่องจากเป็นสิ่งที่คุณต้องการ ฉันไม่แน่ใจว่าทำไมสิ่งที่เฟรมบัฟเฟอร์ / การผสมผสานรวมอยู่ในคำตอบของเขา

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

ทั้งหมดนี้เป็นคำตอบที่ดีและยังมีอีกวิธีหนึ่ง: (ไม่มีเสมอ)

เนื่องจากความนิยมที่เพิ่มขึ้นของความเป็นจริงเสมือนผู้คนที่ OculusVR ได้พัฒนาส่วนขยายสามส่วนของ "Multiview" ที่เรียกว่า:

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

ส่วนขยายเหล่านี้อนุญาตให้มีการแสดงผลหลายฉากของฉากเดียวกันในการดึงสายเดียวขจัดความซ้ำซ้อนของการเรนเดอร์ฉากเดียวกันในสถานะเดียวกันจากมุมมองของตาแต่ละข้าง แม้ว่าจะถูกสร้างขึ้นเพื่อวัตถุประสงค์ของ VR แต่ผู้พัฒนาไม่ได้ จำกัด อยู่เพียงแค่สองมุมมองเท่านั้น แต่ส่วนขยายนี้อนุญาตให้มีการดูได้มากตามที่MAX_VIEWS_OVRระบุ

ก่อนใช้ส่วนขยายเหล่านี้นักพัฒนาควรตรวจสอบการสนับสนุนในไดรเวอร์กราฟิกของผู้ใช้โดยเพิ่มรหัสต่อไปนี้:

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

จากตรงนั้นเป็นเรื่องของการตั้งค่า framebuffer ของคุณเพื่อใช้คุณสมบัตินี้:

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

และเช่นเดียวกันใน 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);
}

ในแอปพลิเคชันที่เชื่อมโยงกับ CPU ส่วนขยายนี้สามารถลดเวลาการเรนเดอร์ลงได้อย่างมากโดยเฉพาะกับฉากที่ซับซ้อนมากขึ้น :

เวลา CPU สัมพัทธ์ระหว่างสเตอริโอหลายมุมและสเตอริโอปกติ  ยิ่งมีขนาดเล็กก็จะยิ่งดีขึ้นโดยมีจำนวนลูกบาศก์บนแกน x และเวลาที่สัมพันธ์กันบนแกน y

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.