Anti Aliasing ถูกนำไปใช้ในการติดตาม Ray อย่างไร


13

หลังจากที่ได้อ่านบทความไม่กี่ออนไลน์ผมมั่นใจได้ว่าผม clueless เกี่ยวกับวิธีการทำงานป้องกันนามแฝงเมื่อใช้ Ray Tracing

ทั้งหมดที่ฉันเข้าใจว่าโสดพิกเซล / เรย์ถูกแบ่งออกเป็น 4 ย่อยพิกเซลและ 4 รังสีมากกว่า 1

มีใครช่วยอธิบายวิธีการนี้ให้สำเร็จ (ควรมีรหัส)?


2
ฉันสามารถเพียงแค่แนะนำให้คุณดูที่ "supersampling" en.wikipedia.org/wiki/Supersamplingและบางทีอาจจะยัง en.wikipedia.org/wiki/Distributed_ray_tracing ?
Simon F

2
ฉันยังสามารถแนะนำให้อ่านบทนี้ของ PBRT pbrt.org/chapters/pbrt_chapter7.pdfและอ่านกระดาษนี้lgdv.cs.fau.de/get/785 (ซึ่งอธิบายเทคนิคที่แตกต่างจากที่ใช้ใน pbrt)
Tom van Bussel

1
foreach pixel : p{acc = 0; foreach subsample : s { acc+=sample_scene(s);} store(p, acc);}
วงล้อประหลาด

คำตอบ:


12

ฉันคิดว่ามันปลอดภัยที่จะบอกว่ามีสองวิธีที่แตกต่างกันในการทำ AA ในการถ่ายภาพรังสี:

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

2: วิธีที่สองคือการพิจารณาหลายรังสีสำหรับแต่ละพิกเซลแล้วเฉลี่ยผล สำหรับรุ่นที่ง่ายมากลองคิดแบบนี้:

  • คุณแสดงภาพแรกที่มีขนาด 1024x1024 หนึ่งเรย์สำหรับแต่ละพิกเซล (ตัวอย่าง)
  • หลังจากการเรนเดอร์คุณปรับขนาดภาพเป็น 512x512 (แต่ละพิกเซลมีค่าเฉลี่ยอยู่ที่หนึ่ง) และคุณสามารถสังเกตเห็นว่าขอบเรียบกว่า วิธีนี้คุณใช้ 4 รังสีอย่างมีประสิทธิภาพสำหรับแต่ละพิกเซลในภาพสุดท้ายขนาด 512x512

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

ตรวจสอบลิงก์ในความคิดเห็นด้านบน


ดังนั้นโดยทั่วไปฉันแสดงภาพเป็นขนาดใหญ่และเมื่อบันทึกลงในรูปภาพให้ลดขนาดลงเป็นขนาดต่ำกว่าหรือไม่ ดูเหมือนง่ายมาก :)! นี่เป็นวิธีการสุ่มตัวอย่างแบบพิเศษหรือไม่?
Arjan Singh

1
@Arjan Singh ใช่มันเป็นen.wikipedia.org/wiki/Supersamplingแต่นี่คือสิ่งที่ช้าที่สุดของพวกเขาทั้งหมด raytracing ช่วยให้คุณทำ supersampling แบบปรับตัวได้อย่างง่ายดายซึ่งสามารถทำงานได้ดีขึ้นมาก
Raxvan

14

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

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

ดังที่ Julien กล่าวหากคุณต้องการทำตัวอย่างต่อพิกเซลคุณสามารถแบ่งพิกเซลออกเป็นจุดตัวอย่างที่กระจายตัวอย่าง (บนตารางโดยทั่วไป) และทำการสุ่มตัวอย่างเหล่านั้นโดยเฉลี่ยNNN

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

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

เมื่อคุณใช้ตัวเลขสุ่ม "ปกติ" อย่างที่คุณได้รับจาก rand () หรือ std :: uniform_int_distribution ที่เรียกว่า "สัญญาณรบกวนสีขาว" เนื่องจากมีความถี่ทั้งหมดเช่นแสงสีขาวประกอบด้วยสีอื่น ๆ ทั้งหมด (ความถี่ ) ปิดไฟ.

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

วิธีที่ดีกว่าคือการใช้สิ่งที่เรียกว่าสัญญาณรบกวนสีน้ำเงินซึ่งมีส่วนประกอบความถี่สูงเท่านั้น (เช่นแสงสีฟ้าเป็นแสงความถี่สูง)

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

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

โปรดทราบว่านี่เป็นรูปแบบหนึ่งของการสุ่มตัวอย่างแบบแบ่งชั้นและการสุ่มตัวอย่างดิสก์ปัวซองก็เป็นรูปแบบหนึ่งเช่นกันซึ่งเป็นวิธีการสร้างเสียงรบกวนสีน้ำเงิน: https://www.jasondavies.com/poisson-disc/

หากคุณสนใจที่จะเจาะลึกคุณอาจต้องการตรวจสอบคำถามและคำตอบนี้!

อะไรคือเหตุผลพื้นฐานในการต่อต้าน aliasing โดยใช้ตัวอย่างสุ่มจำนวนมากภายในพิกเซล

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

http://blog.demofox.org/2016/09/21/path-tracing-getting-started-with-diffuse-and-emissive/


ทันทีที่ฉันเห็นชื่อของคุณฉันรู้ว่าคุณจะต้องมีบางสิ่งบางอย่างในเสียงสีฟ้า :)
ฮับเบิล

เนื่องจากสิ่งนี้เปิดใช้งานอีกครั้ง: เพื่ออธิบายว่าทำไมนี่คือรูปแบบการสุ่มตัวอย่างสัญญาณรบกวนสีฟ้าที่ยอดเยี่ยมเมื่อรวมฟังก์ชั่นเข้ากับพลังงานส่วนใหญ่กระจุกตัวในความถี่ต่ำ ดังนั้นด้วยการใช้รูปแบบเสียงรบกวนสีฟ้าคุณจึงสันนิษฐานได้ว่าสัญญาณของคุณส่วนใหญ่จะราบรื่น / มีความถี่ต่ำ สำหรับสัญญาณความถี่สูงสิ่งนี้อาจต่อต้านได้จริง โชคดีที่ภาพธรรมชาติมีพลังงานรวมอยู่ที่ความถี่ต่ำ ดูรายละเอียดเพิ่มเติมได้ที่: sampling.mpi-inf.mpg.de/2019-singh-fourier.html
lightxbulb

7

สมมติว่าการวนรอบหลักแบบ raytracing ค่อนข้างปกติ:

struct Ray
{
    vec3 origin;
    vec3 direction;
};

RGBColor* image = CreateImageBuffer(width, height);

for (int j=0; j < height; ++i)
{
    for (int i=0; i < width; ++i)
    {
        float x = 2.0 * (float)i / (float)max(width, height) - 1.0;
        float y = 2.0 * (float)j / (float)max(width, height) - 1.0;

        vec3 dir = normalize(vec3(x, y, -tanHalfFov));
        Ray r = { cameraPosition, dir };

        image[width * j + i] = ComputeColor(r);
    }
}

หนึ่งการปรับเปลี่ยนที่เป็นไปได้ของการทำ 4 ตัวอย่าง MSAA คือ:

float jitterMatrix[4 * 2] = {
    -1.0/4.0,  3.0/4.0,
     3.0/4.0,  1.0/3.0,
    -3.0/4.0, -1.0/4.0,
     1.0/4.0, -3.0/4.0,
};

for (int j=0; j < height; ++i)
{
    for (int i=0; i < width; ++i)
    {
        // Init the pixel to 100% black (no light).
        image[width * j + i] = RGBColor(0.0);

        // Accumulate light for N samples.
        for (int sample = 0; sample < 4; ++sample)
        {
            float x = 2.0 * (i + jitterMatrix[2*sample]) / (float)max(width, height) - 1.0;
            float y = 2.0 * (i + jitterMatrix[2*sample+1]) / (float)max(width, height) - 1.0;

            vec3 dir = normalize(vec3(x, y, -tanHalfFov) + jitter);
            Ray r = { cameraPosition, dir };

            image[width * j + i] += ComputeColor(r);
        }

        // Get the average.
        image[width * j + i] /= 4.0;
    }
}

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

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

PS: ฉันเขียนโค้ดด้านบนทันทีดังนั้นฉันคาดหวังข้อผิดพลาดเล็กน้อยในนั้น มันมีไว้เพื่อแสดงความคิดพื้นฐานเท่านั้น


คำตอบที่ดี! สิ่งที่เป็นประโยชน์ของการใช้วิธีนี้ตรงข้ามกับวิธีการ @Raxvan ใช้? ฉันจะได้ผลลัพธ์เดียวกันด้วยการแสดงผลที่มีขนาดใหญ่แล้วลดขนาดให้เล็กลงหรือไม่
Arjan Singh

โดยพื้นฐานแล้วด้วยการติดตามรังสีคุณไม่จำเป็นต้องแสดงภาพที่ใหญ่ขึ้นแล้วย่อขนาดลง นั่นหมายความว่าคุณมีความยืดหยุ่นมากขึ้น: คุณสามารถมีตัวอย่างจำนวนมากคุณสามารถเปลี่ยนแปลงจำนวนตัวอย่างขึ้นอยู่กับภูมิภาคและเพียงแค่คุณไม่ต้องเพิ่มขั้นตอนการขายซ้ำ
Julien Guertault

2
ในหัวข้อของการกระวนกระวายใจสิ่งนี้กลายเป็นหัวข้อที่ค่อนข้างซับซ้อน นี่เป็นบทความที่ยอดเยี่ยมเกี่ยวกับการวิเคราะห์กราฟิกที่
Mikkel Gjoel

ตัวอย่างโค้ดข้างต้นใช้ MSAA 4 ตัวอย่างถ้าฉันต้องการทำ 8x MSAA เมทริกซ์จะเป็นอย่างไร ฉันจะต้องเปลี่ยนแปลงอะไรในเมทริกซ์ที่กระวนกระวายใจที่แสดงด้านบน
Arjan Singh เมื่อ

คุณพูดว่า "4 ตัวอย่าง MSAA น่าจะ:" สมมุติว่าคุณหมายถึง SSAA MSAA ที่ใช้ในการแรสเตอร์ไรซ์เป็นการแลกเปลี่ยนต้นทุน / คุณภาพอันดับแรกให้พิจารณาว่าวัตถุใด (อ่านสามเหลี่ยม) แต่ละตัวอย่างที่พบ หากพวกเขาทั้งหมดชนวัตถุเดียวกันจะมีการดำเนินการแรเงาเพียงครั้งเดียว หากพบวัตถุที่แตกต่างกัน 2 รายการจะมีการดำเนินการแรเงา 2 ครั้งและผลลัพธ์จะถูกถ่วงน้ำหนักและรวมด้วยจำนวนตัวอย่างที่กระทบแต่ละวัตถุและอื่น ๆ สำหรับวัตถุ 3 ฯลฯ สิ่งที่คุณอธิบายคือมาตรฐานการสุ่มตัวอย่างแบบ AA, i, e, SSAA
Simon F

1

เพียงเพิ่มคำตอบด้านบน:

กระจายการติดตามเรย์ (Cook, Porter, & Carpenter) ช่วยให้คุณสามารถทำ AA เชิงพื้นที่, AA ชั่วขณะ (เคลื่อนไหวเบลอ) และโฟกัส / ความชัดลึก ดีที่สุดในการอ่านกระดาษ แต่โดยทั่วไปแล้วรังสีเอกซ์ที่คุณยิงต่อพิกเซลสามารถกำหนดได้ด้วยการสุ่มหลอก (สำหรับการเคลื่อนไหวเบลอ) และตำแหน่งบนเลนส์ (เพื่อรับเอฟเฟกต์โฟกัส)

Adaptive Supersampling: คุณเริ่มยิงรังสีจำนวนหนึ่งต่อพิกเซล แต่ถ้ารังสีในผลตอบแทนที่ใกล้เคียงในท้องถิ่นอย่างมีนัยสำคัญผลลัพธ์ที่แตกต่างจากนั้นคุณสามารถทั้งในประเทศเพิ่มอัตราการสุ่มตัวอย่าง (พูด 2x) เพื่อปรับปรุงผล คุณสามารถเลือกที่จะทำซ้ำขั้นตอน มันไม่สมบูรณ์แบบเนื่องจากวัตถุยังสามารถ 'ตกอยู่ระหว่างกลุ่มตัวอย่าง' แต่อาจมีราคาถูกกว่าการสุ่มตัวอย่างอย่างสม่ำเสมอในอัตราที่สูงขึ้น

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

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