ใช้สองเฉดสีแทนหนึ่งด้วยคำสั่ง IF


9

ฉันทำงานเกี่ยวกับการโอนย้ายแหล่ง OpenGL ของ ES 1.1 ที่ค่อนข้างใหญ่ไปเป็น ES 2.0

ใน OpenGL ES 2.0 (ซึ่งหมายความว่าทุกอย่างใช้ shaders) ฉันต้องการวาดกาน้ำชาสามครั้ง

  1. คนแรกที่มีสีสม่ำเสมอ (AlCa เก่า glColor4f)

  2. ตัวที่สองด้วยสีต่อจุดสุดยอด (กาน้ำชามีสีของจุดสุดยอดเช่นกัน)

  3. อันที่สามที่มีพื้นผิวต่อยอด

  4. และอาจเป็นอันที่สี่ที่มีทั้งพื้นผิวและสีต่อจุด แล้วก็อาจจะเป็นอันดับที่ 5 ที่มีบรรทัดฐานเช่นกัน ..

มีสองทางเลือกที่ฉันมีกับการนำไปปฏิบัติเท่าที่ฉันรู้ สิ่งแรกคือสร้าง shader ที่รองรับทั้งหมดข้างต้นด้วยชุดที่กำหนดให้เปลี่ยนพฤติกรรม (เช่นใช้ชุดสีเอกพจน์หรือชุดสีต่อจุดสุดยอด)

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

ฉันหมายความว่าวิธีที่ดีที่สุดในการทำสิ่งนี้คือการสร้างทั้งสองอย่างและวัดผล แต่ก็เป็นการดีที่จะได้ยินอินพุตใด ๆ

คำตอบ:


10

ค่าใช้จ่ายในการปฏิบัติงานของการแยกอาจไม่เล็กเกินไป ในกรณีของคุณจุดยอดและชิ้นส่วนทั้งหมดที่ถูกวาดจะใช้เส้นทางเดียวกันผ่านเฉดสีของคุณดังนั้นสำหรับฮาร์ดแวร์เดสก์ท็อปสมัยใหม่มันจะไม่เลวร้ายอย่างที่ควรจะเป็น แต่คุณกำลังใช้ ES2 ซึ่งหมายความว่าคุณไม่ได้ใช้สมัยใหม่ ฮาร์ดแวร์เดสก์ท็อป

กรณีที่เลวร้ายที่สุดที่มีการแตกกิ่งจะเป็นดังนี้

  • ประเมินทั้งสองด้านของสาขา
  • คำสั่ง "มิกซ์" หรือ "ขั้นตอน" จะถูกสร้างขึ้นโดยคอมไพเลอร์ shader และแทรกลงในโค้ดของคุณเพื่อตัดสินใจว่าจะใช้ด้านไหน

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

แอปเปิ้ล " คู่มือการเขียนโปรแกรม OpenGL ES สำหรับ iOS " ของ Apple (ซึ่งสามารถใช้เป็นตัวแทนสำหรับฮาร์ดแวร์เป้าหมายของคุณ) มีสิ่งนี้เพื่อพูดคุยเกี่ยวกับการแยกสาขา:

หลีกเลี่ยงการแตกแขนง

กิ่งก้านเป็นสิ่งที่ท้อใจเพราะพวกเขาสามารถลดความสามารถในการดำเนินการแบบขนานบน 3D กราฟิกโปรเซสเซอร์ หากเฉดสีของคุณต้องใช้กิ่งไม้ทำตามคำแนะนำเหล่านี้:

  • ประสิทธิภาพที่ดีที่สุด: Branch บนค่าคงที่ที่รู้จักกันเมื่อรวบรวม shader
  • ยอมรับได้: แยกสาขากับตัวแปรแบบเดียวกัน
  • อาจเกิดขึ้นช้า: การแบรนช์บนค่าที่คำนวณภายใน shader

แทนที่จะสร้าง shader ขนาดใหญ่ที่มีลูกบิดและคันโยกจำนวนมากให้สร้าง shader ที่มีขนาดเล็กลงสำหรับงานการเรนเดอร์เฉพาะ มีการแลกเปลี่ยนระหว่างการลดจำนวนสาขาในเฉดของคุณและเพิ่มจำนวนตัวสร้างที่คุณสร้าง ทดสอบตัวเลือกที่แตกต่างกันและเลือกทางออกที่เร็วที่สุด

แม้ว่าคุณจะพอใจว่าคุณอยู่ในช่อง "ยอมรับได้" ที่นี่คุณยังต้องพิจารณาด้วยการเลือก 4 หรือ 5 รายคุณจะต้องเพิ่มจำนวนคำสั่งในเฉดสีของคุณ คุณควรตระหนักถึงข้อ จำกัด ในการนับจำนวนคำสั่งบนฮาร์ดแวร์เป้าหมายของคุณและตรวจสอบให้แน่ใจว่าคุณไม่ได้ไปเหนือพวกเขาโดยอ้างอีกครั้งจากลิงค์ Apple ด้านบน:

การใช้งาน OpenGL ES ไม่จำเป็นต้องใช้ซอฟต์แวร์สำรองเมื่อเกินขีด จำกัด เหล่านี้ แต่ shader ไม่สามารถรวบรวมหรือลิงก์ได้

สิ่งนี้ไม่ได้หมายความว่าการแตกแขนงไม่ใช่ทางออกที่ดีที่สุดสำหรับความต้องการของคุณ คุณระบุข้อเท็จจริงที่ถูกต้องว่าคุณควรทำโปรไฟล์ทั้งสองวิธีเพื่อให้เป็นคำแนะนำสุดท้าย แต่ควรระวังด้วยว่าเมื่อเฉดสีมีความซับซ้อนมากขึ้นโซลูชันที่อิงกับการแยกสาขาอาจให้ค่าใช้จ่ายสูงกว่าการเปลี่ยนแปลง shader เล็กน้อย


3

ค่าใช้จ่ายในการผูกเฉดสีอาจไม่สำคัญ แต่จะไม่เป็นปัญหาคอขวดของคุณเว้นแต่ว่าคุณจะแสดงสิ่งของหลายพันรายการโดยไม่ต้องแบทช์วัตถุทั้งหมดที่ใช้เฉดสีเดียวกัน

แม้ว่าฉันไม่แน่ใจว่าสิ่งนี้ใช้ได้กับอุปกรณ์มือถือหรือไม่ แต่ GPU ไม่ช้าอย่างน่ากลัวกับกิ่งไม้หากเงื่อนไขอยู่ระหว่างค่าคงที่และสม่ำเสมอ ทั้งสองถูกต้องทั้งคู่ถูกนำมาใช้ในอดีตและจะยังคงใช้ในอนาคตเลือกสิ่งที่คุณคิดว่าจะสะอาดกว่าในกรณีของคุณ

นอกจากนี้ยังมีวิธีอื่นอีกสองสามวิธีในการทำสิ่งนี้: "Uber-shaders" และกลอุบายเล็กน้อยกับวิธีที่โปรแกรม OpenGL เชื่อมโยง

"Uber-shaders" เป็นตัวเลือกแรกโดยไม่หักสาขา แต่คุณมีหลายเฉดสี แทนการใช้ifงบที่คุณใช้พรีโพรเซสเซอร์ - #define, #ifdef, #else, #endif, และเรียบเรียงรุ่นต่าง ๆ รวมทั้งที่เหมาะสม#defineสำหรับสิ่งที่คุณต้องการ

vec4 color;
#ifdef PER_VERTEX_COLOR
color = in_color;
#else
color = obj_color;
#endif

นอกจากนี้คุณยังสามารถแบ่ง shader ขึ้นเป็นฟังก์ชั่นแยก มีหนึ่ง shader ที่กำหนดต้นแบบสำหรับฟังก์ชั่นทั้งหมดและเรียกพวกเขาเชื่อมโยงกลุ่มของเฉดพิเศษที่รวมถึงการใช้งานที่เหมาะสม ฉันใช้เคล็ดลับนี้สำหรับการทำแผนที่เงาเพื่อให้ง่ายต่อการสลับวิธีการกรองในวัตถุทั้งหมดโดยไม่ต้องปรับเปลี่ยนเฉดสีทั้งหมด

//ins, outs, uniforms

float getShadowCoefficient();

void main()
{
    //shading stuff goes here

    gl_FragColor = color * getShadowCoefficient();
}

จากนั้นฉันสามารถมีไฟล์ shader อื่น ๆ หลายไฟล์ที่กำหนดgetShadowCoefficient()เครื่องแบบที่จำเป็นและไม่มีอะไรอื่น ตัวอย่างเช่นshadow_none.glslประกอบด้วย:

float getShadowCoefficient()
{
    return 1;
}

และshadow_simple.glslมี (เรียบง่ายจาก shader ของฉันที่ใช้ CSM):

in vec4 eye_position;

uniform sampler2DShadow shad_tex;
uniform mat4 shad_mat;

float getShadowCoefficient()
{
    vec4 shad_coord = shad_mat * eye_position;
    return texture(shad_tex, shad_coord).x;
}

และคุณสามารถเลือกได้ว่าต้องการแรเงาหรือไม่โดยการเชื่อมโยงshadow_*shader อื่น วิธีการแก้ปัญหานี้อาจมีค่าใช้จ่ายมากขึ้น แต่ฉันต้องการคิดว่าคอมไพเลอร์ GLSL นั้นดีพอที่จะเพิ่มประสิทธิภาพค่าใช้จ่ายเพิ่มเติมใด ๆ เมื่อเทียบกับวิธีการทำเช่นนี้ ฉันไม่ได้ทำการทดสอบใด ๆ เกี่ยวกับเรื่องนี้ แต่มันเป็นวิธีที่ฉันชอบทำ

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