ไปป์ไลน์การแสดงผลของเครื่องยนต์


10

ฉันพยายามสร้างเอ็นจิ้นเกม 2D โดยใช้ OpenGL ES 2.0 (iOS สำหรับตอนนี้) ฉันได้เขียนเลเยอร์แอปพลิเคชันใน Objective C และแยกตัวเองบรรจุ RendererGLES20 ใน C ++ ไม่มีการโทรเฉพาะ GL นอกสายแสดงภาพ มันทำงานได้อย่างสมบูรณ์

แต่ฉันมีปัญหาการออกแบบเมื่อใช้ shaders Shader แต่ละตัวมีคุณสมบัติและเครื่องแบบที่เป็นเอกลักษณ์ของตัวเองซึ่งจำเป็นต้องตั้งค่าก่อนการเรียกสายหลัก (glDrawArrays ในกรณีนี้) ตัวอย่างเช่นในการวาดรูปทรงเรขาคณิตฉันจะทำ:

void RendererGLES20::render(Model * model)
{
    // Set a bunch of uniforms
    glUniformMatrix4fv(.......);
    // Enable specific attributes, can be many
    glEnableVertexAttribArray(......);
    // Set a bunch of vertex attribute pointers:
    glVertexAttribPointer(positionSlot, 2, GL_FLOAT, GL_FALSE, stride, m->pCoords);

    // Now actually Draw the geometry
    glDrawArrays(GL_TRIANGLES, 0, m->vertexCount);

    // After drawing, disable any vertex attributes:
    glDisableVertexAttribArray(.......);
}

อย่างที่คุณเห็นรหัสนี้เข้มงวดมาก ถ้าฉันจะใช้ shader อื่นพูดเอฟเฟ็กต์ระลอกคลื่นฉันจะต้องผ่านชุดพิเศษจุดยอด attribs ฯลฯ กล่าวอีกนัยหนึ่งฉันต้องเปลี่ยน RendererGLES20 render source code เพื่อรวม shader ใหม่เข้าด้วยกัน

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

ต่อไปนี้แสดงให้เห็นถึงระดับนักแสดง:

class Actor : public ISceneNode
{
    ModelController * model;
    AIController * AI;
};

โมเดลคอนโทรลเลอร์คลาส: คลาส ModelController {คลาส IShader * shader; รหัสพื้นผิว int; สี vec4; อัลฟาลอย; struct Vertex * vertexArray; };

คลาส Shader มีเพียงวัตถุ shader การรวบรวมและเชื่อมโยงรูทีนย่อยเป็นต้น

ในคลาส Game Logic จริง ๆ แล้วฉันแสดงวัตถุ:

void GameLogic::update(float dt)
{
    IRenderer * renderer = g_application->GetRenderer();

    Actor * a = GetActor(id);
    renderer->render(a->model);
}

โปรดทราบว่าแม้ว่านักแสดงจะขยาย ISceneNode แต่ฉันยังไม่ได้เริ่มใช้ SceneGraph ฉันจะทำทันทีที่ฉันแก้ไขปัญหานี้

ความคิดใดที่จะปรับปรุงสิ่งนี้? รูปแบบการออกแบบที่เกี่ยวข้อง ฯลฯ ?

ขอบคุณที่อ่านคำถาม



ไม่แน่ใจว่ามันซ้ำกันจริง ๆ หรือเปล่า แต่มันกลับกลายเป็นว่าคุณกำลังพยายามทำอะไรอยู่
Sean Middleditch

คำตอบ:


12

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

ข้อแรกข้อจำกัดความรับผิดชอบ: ระบบที่ขับเคลื่อนด้วยข้อมูลสามารถทำให้เพิ่ม shaders ใหม่ได้ง่ายขึ้น แต่ในทางกลับกันมันมาพร้อมกับค่าใช้จ่ายในแง่ของความซับซ้อนที่เพิ่มขึ้นของระบบซึ่งทำให้การบำรุงรักษาและการดีบักยากขึ้น ดังนั้นจึงเป็นความคิดที่ดีที่จะคิดอย่างรอบคอบว่าข้อมูลที่ขับเคลื่อนด้วยข้อมูลจะดีต่อคุณเพียงใด (สำหรับโครงการขนาดเล็กคำตอบอาจเป็น "ไม่มี") และอย่าพยายามสร้างระบบที่กว้างเกินไป

โอเคเรามาพูดถึงรูปแบบจุดสุดยอด (คุณสมบัติ) ก่อน คุณสามารถสร้างคำอธิบายข้อมูลโดยการสร้าง struct ที่มีข้อมูลที่จะส่งผ่านglVertexAttribPointer- ดัชนีประเภทขนาด ฯลฯ ของคุณลักษณะเดียว - และมีอาร์เรย์ของโครงสร้างเหล่านั้นเพื่อแสดงรูปแบบจุดสุดยอดทั้งหมด รับข้อมูลนี้คุณสามารถตั้งค่าสถานะ GL ทั้งหมดที่เกี่ยวข้องกับแอตทริบิวต์ของจุดสุดยอดโดยทางโปรแกรม

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

มีหลายวิธีในการทำเช่นนี้ ตัวอย่างเช่นคุณอาจมีชุดชื่อมาตรฐานสำหรับแอตทริบิวต์ใน shader ("attrPosition", "attrNormal" ฯลฯ ) บวกกับกฎที่ใช้รหัสตายตัวเช่น "ตำแหน่งคือ 3 ลอย" จากนั้นคุณใช้glGetAttribLocationหรือคล้ายกันเพื่อสอบถามว่าคุณลักษณะที่ Shader ใช้และใช้กฎเพื่อสร้างรูปแบบจุดสุดยอด อีกวิธีหนึ่งคือการมีส่วนย่อยของ XML กำหนดรูปแบบฝังอยู่ในความคิดเห็นในแหล่งที่มาของ shader และแยกโดยเครื่องมือของคุณหรือบางสิ่งบางอย่างตามบรรทัดเหล่านั้น

สำหรับชุดถ้าคุณสามารถใช้ OpenGL 3.1 หรือใหม่กว่าขอแนะนำให้ใช้วัตถุบัฟเฟอร์ชุด (OpenGL เทียบเท่ากับบัฟเฟอร์คงที่ของ D3D) อนิจจา GL ES 2.0 ไม่มีสิ่งเหล่านั้นดังนั้นเครื่องแบบต้องได้รับการจัดการแยกกัน วิธีหนึ่งที่จะทำได้คือสร้างโครงสร้างที่มีตำแหน่งเหมือนกันสำหรับแต่ละพารามิเตอร์ที่คุณต้องการตั้งค่าเช่นเมทริกซ์กล้องกำลัง specular เมทริกซ์โลกเป็นต้นตำแหน่งตัวอย่างอาจอยู่ที่นี่ด้วย วิธีการนี้ขึ้นอยู่กับการมีชุดพารามิเตอร์มาตรฐานที่ใช้ร่วมกันระหว่างเครื่องเคลือบเงาทั้งหมด ไม่ใช่ทุก shader ที่ต้องใช้ทุกพารามิเตอร์เดียว แต่พารามิเตอร์ทั้งหมดจะต้องอยู่ใน struct นี้

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

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