OpenGL รับร่างของวัตถุที่ทับซ้อนกันหลายรายการ


10

ฉันเพิ่งมีความคิดเกี่ยวกับเกมที่กำลังทำของฉันที่ทำด้วย opengl ใน c ++: ฉันต้องการมีโครงร่างขนาดใหญ่ (5-6 พิกเซล) บนวัตถุที่ทับซ้อนกันหลายอย่างเมื่อผู้เล่นชนะบางสิ่ง

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

นี่คือสิ่งที่ฉันต้องการได้รับ:

ป้อนคำอธิบายรูปภาพที่นี่

ความคิดใด ๆ


ใช้ตัวกรองตรวจจับขอบเติมขอบด้วยเส้นสีหนาแล้วแยกภาพที่แสดงของรูปร่างและภาพซ้อนทับที่ด้านบนของเลเยอร์เส้นสีหรือไม่
ปืนลูกซอง Ninja

คุณมีความหมายอย่างไรกับตัวกรองตรวจจับขอบ Shader หรือไม่? ตัวกรองการประมวลผลภาพ? เช่น opencv (แสดงกับพื้นผิวใช้ตัวกรองกับพื้นผิวแล้วกดพื้นหลังที่ถูกดัดแปลง) หรือไม่
nkint

ฉันไม่รู้; ฉันไม่ค่อยเชี่ยวชาญในการเรนเดอร์ 3 มิติเพื่อเริ่มต้น
ปืนลูกซอง Ninja

คุณมีตัวอย่างของ stencil buffer อย่างนี้บ้างไหม? ฉันคิดว่าการใช้ stencil buffer นั้นจะเป็นวิธีที่สะอาดกว่า แต่ฉันไม่สามารถใช้ stencil buffer ทำงานได้
nkint

คำตอบ:


4
  1. เปิดใช้งานและล้างบัฟเฟอร์ stencil
  2. วาดวัตถุการตั้งค่าบัฟเฟอร์ stencil วัตถุสามารถกึ่งโปร่งใสเป็นต้น
  3. ตอนนี้ตั้งค่าโหมด stencil เป็นเขียนพิกเซลเท่านั้นที่ไม่ได้ตั้ง stencil
  4. และวาดวัตถุแต่ละชิ้นอีกครั้งปรับขนาดขึ้นเล็กน้อยในสีเส้นขอบที่ต้องการและไม่มีพื้นผิว
  5. ปิดการใช้งานบัฟเฟอร์ลายฉลุ

นี่คือรหัสที่ดัดแปลงมาจากโค้ดลายฉลุ webGL บางตัวที่ฉันใช้งาน:

// drawing will set stencil stencil
    gl.enable(gl.STENCIL_TEST);
    gl.stencilFunc(gl.ALWAYS,1,1);
    gl.stencilOp(gl.KEEP,gl.KEEP,gl.REPLACE);
    gl.stencilMask(1);
    gl.clearStencil(0);
    gl.clear(gl.STENCIL_BUFFER_BIT);
// draw objects
for(var object in objects)
  objects[object].draw();
// set stencil mode to only draw those not previous drawn
    gl.stencilFunc(gl.EQUAL,0,1);
    gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP);
    gl.stencilMask(0x00);
// draw object halo
for(var object in objects)
  objects[object].drawHalo(1.1,red); // each mesh should be individually scaled e.g. by 1.1
// done
    gl.disable(gl.STENCIL_TEST);

ฉันคิดว่าฉันใช้วิธีนี้ในเกม RTS เพื่อวาดรัศมีรอบ ๆ ยูนิตที่เลือก แต่มันนานมาแล้วและฉันจำไม่ได้ว่ามี gotchas และความแตกต่างทั้งหมดหรือไม่


คุณมีตัวอย่างของ stencil buffer อย่างนี้บ้างไหม? ผมคิดว่าการใช้บัฟเฟอร์ลายฉลุจะเป็นวิธีการทำความสะอาด แต่ฉันไม่สามารถใด ๆ ให้ทำงานลายฉลุบัฟเฟอร์
nkint

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

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

2

เริ่มต้นด้วยการค้นหากลุ่มวัตถุทั้งหมดโดยที่กลุ่มวัตถุคือกลุ่มของวัตถุที่ทับซ้อนกัน การตรวจจับการชนกันของมาตรฐานควรทำงาน กำหนดสีพิเศษให้แต่ละกลุ่ม สีใดจะทำ

แสดงวัตถุทั้งหมดของคุณเป็นสีทึบโดยใช้สีกลุ่มเป็นพื้นผิว

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

ในที่สุดนำเนื้อโครงร่างนี้มาวางไว้เหนือส่วนบนของภาพที่คุณต้องการวาดบนหน้าจอ (แน่นอนว่าคุณสามารถทำได้ในเวลาเดียวกับการตรวจจับขอบในส่วนที่แยกส่วนและหลีกเลี่ยงการสร้างพื้นผิวของขอบในครั้งแรก สถานที่).

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

ส่วนที่ทำหน้าที่ตรวจจับขอบนี้อาจมีลักษณะเช่นนี้

precision mediump float;

uniform sampler2D s_texture;

varying vec2 v_texCoord;

void main()
{
    gl_FragColor = vec4(0.0);

    vec4 baseColor = texture2D(s_texture, v_texCoord);
    gl_FragColor += baseColor - texture2D(s_texture, top);
    gl_FragColor += baseColor - texture2D(s_texture, topRight);
    gl_FragColor += baseColor - texture2D(s_texture, right);
    gl_FragColor += baseColor - texture2D(s_texture, bottomRight);
    gl_FragColor += baseColor - texture2D(s_texture, bottom);
    gl_FragColor += baseColor - texture2D(s_texture, bottomLeft);
    gl_FragColor += baseColor - texture2D(s_texture, left);
    gl_FragColor += baseColor - texture2D(s_texture, topLeft);
}

โดยที่ค่าที่สองในการค้นหา texture2D เป็นพิกัด 2d ที่สัมพันธ์กับ v_texCoord คุณจะใช้สิ่งนี้โดยการเรนเดอร์เป้าหมายการเรนเดอร์แรกเป็นพื้นผิวในรูปแบบเต็มหน้าจอ สิ่งนี้คล้ายกับวิธีที่คุณใช้เอฟเฟ็กต์การเบลอภาพแบบเต็มหน้าจอเช่นภาพเบลอ guassian

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


2
ขออภัยคุณหมายถึงอะไรด้วย "สแกนผ่านแต่ละ texel" ห่วงสำหรับแต่ละพิกเซล? ในซีพียู? ดังนั้นมันจึงเป็นเช่น: เรนเดอร์ด้วยสีทึบไปยังพื้นผิว, ถ่ายโอนรูปภาพไปยัง cpu, ทำการสแกน, วางมันลงในพื้นผิวอีกครั้งหรือไม่? หรือทำมันใน Shader?
nkint

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