การเรนเดอร์พิกเซลที่สมบูรณ์แบบสำหรับชุดเรนเดอร์เป้าหมายด้วย Quad เต็มหน้าจอ


9

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

ตัวอย่าง: ฉันแสดงผลเป็นพื้นผิว 4x4 และตัวแบ่งส่วนในกรณีนี้เพียงแค่แสดงพิกัดพื้นผิว (u, v) ในช่องสีแดงและสีเขียว:

return float4(texCoord.rg, 0, 1);

สิ่งที่ฉันต้องการออกจากมันคือพื้นผิวที่พิกเซลที่ด้านซ้ายบนคือ RGB (0,0,0) และทำให้เป็นสีดำพิกเซลที่ด้านบนขวาคือ RGB (255,0,0) และสว่าง สีแดงและพิกเซลที่ด้านล่างซ้ายคือ RGB (0,255,0) - สีเขียวสดใส

อย่างไรก็ตามฉันได้รับที่นี่แทน

(การเรนเดอร์รูปสี่เหลี่ยมตรงไม่มีการแก้ไข)
การเรนเดอร์แบบตรงไม่มีการแก้ไข

พิกเซลด้านบนซ้ายเป็นสีดำ แต่ฉันได้สีแดงเข้มและเขียวเข้มที่มุมอื่น ๆ เท่านั้น ค่า RGB ของพวกเขาคือ (191,0,0) และ (0,191,0) ฉันสงสัยอย่างยิ่งว่ามันเกี่ยวข้องกับตำแหน่งการสุ่มตัวอย่างของรูปสี่เหลี่ยม: พิกเซลด้านบนซ้ายอย่างถูกต้องสุ่มตัวอย่างที่มุมบนซ้ายของรูปสี่เหลี่ยมและได้รับ (0,0) เป็นพิกัด UV แต่พิกเซลมุมอื่น ๆ ไม่ได้ตัวอย่างจาก อีกมุมหนึ่งของรูปสี่เหลี่ยม ฉันได้แสดงสิ่งนี้ในภาพด้านซ้ายโดยมีกล่องสีน้ำเงินแสดงถึงรูปสี่เหลี่ยมและจุดสีขาวของพิกัดสุ่มตัวอย่างด้านบน

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

(รูปสี่เหลี่ยมที่แสดงด้วยออฟเซ็ตครึ่งพิกเซลของ DX9)
รูปสี่เหลี่ยมที่แสดงด้วยออฟเซ็ตครึ่งพิกเซล

สีแดงและสีเขียวสว่างขึ้น แต่ก็ไม่ถูกต้อง: 223 เป็นจำนวนสูงสุดที่ฉันได้รับจากช่องสีแดงหรือสีเขียว แต่ตอนนี้ฉันไม่ได้มีสีดำบริสุทธิ์อีกต่อไป แต่แทนที่จะเป็นสีเทาอมเหลืองกับ RGB (32,32,0) แทน!

สิ่งที่ฉันต้องการจริง ๆ ก็คือการเรนเดอร์แบบนี้:

(การเรนเดอร์เป้าหมายลดขนาดรูปสี่เหลี่ยม)
สีดำบริสุทธิ์สีเขียวและสีแดงด้วยการแก้ไขที่ถูกต้อง

ดูเหมือนว่าฉันจะต้องเลื่อนไปทางขวาและขอบด้านล่างของรูปสี่เหลี่ยมของฉันหนึ่งพิกเซลขึ้นไปทางซ้ายเมื่อเทียบกับรูปแรก จากนั้นคอลัมน์ด้านขวาและแถวด้านล่างของพิกเซลทั้งหมดควรได้รับพิกัด UV อย่างถูกต้องจากขอบของรูปสี่เหลี่ยม:

VertexPositionTexture[] quad = new VertexPositionTexture[]
{
    new VertexPositionTexture(new Vector3(-1.0f,  1.0f, 1f), new Vector2(0,0)),
    new VertexPositionTexture(new Vector3(1.0f - pixelSize.X,  1.0f, 1f), new Vector2(1,0)),
    new VertexPositionTexture(new Vector3(-1.0f, -1.0f + pixelSize.Y, 1f), new Vector2(0,1)),
    new VertexPositionTexture(new Vector3(1.0f - pixelSize.X, -1.0f + pixelSize.Y, 1f), new Vector2(1,1)),
};

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

Vector2 pixelSize = new Vector2((2f / textureWidth) - 0.001f, (2f / textureHeight) - 0.001f);

(ฉันแก้ไขการคำนวณ pixelSize 0.001f - สำหรับพื้นผิวขนาดเล็กเช่นตารางการค้นหา 1D สิ่งนี้ไม่ทำงานและฉันต้องเพิ่มเป็น 0.01f หรือใหญ่กว่า)

แน่นอนว่านี่เป็นตัวอย่างเล็ก ๆ น้อย ๆ และฉันสามารถทำการคำนวณนี้ได้ง่ายขึ้นบน CPU โดยไม่ต้องกังวลเกี่ยวกับการทำแผนที่ UV ไปยังจุดศูนย์กลางพิกเซล ... 1] ช่วงถึงพิกเซลในชุดตรวจสอบเป้าหมาย!?


ไม่ใช่ว่ามันเป็นความช่วยเหลือ แต่ฉันมีปัญหาเดียวกันแน่นอน
IUsedToBeAPygmy

1
อย่าลืมปิดการใช้งานการสุ่มตัวอย่างเชิงเส้นด้วย
r2d2rigo

ดูเหมือนว่าระบบพิกัดที่คุณใช้ตรงกับพิกเซลของหน้าจอ - ถ้าเป็นเช่นนั้นดูเหมือนว่าคุณจะวาดแค่ 2 × 2 พิกเซลที่นี่ ปัญหาแรกที่ฉันจะแก้ไขคือการทำให้โครงการและการฝึกอบรมการดูแบบจำลองปรับขนาดเพื่อให้ +1 ในพื้นที่ประสานงานมีการเปลี่ยนแปลง 1 พิกเซลบนหน้าจอ
Slipp D. Thompson

คำตอบ:


4

ปัญหาของคุณคือ UV ได้รับการออกแบบให้เป็นพิกัดพื้นผิว พิกัด 0,0 คือมุมซ้ายบนของพิกเซลซ้ายบนในพื้นผิวซึ่งไม่ใช่ตำแหน่งที่คุณต้องการอ่านพื้นผิว สำหรับ 2D คุณต้องการอ่านพื้นผิวที่อยู่ตรงกลางของพิกเซลนั้น

หากคณิตศาสตร์ของฉันถูกต้องคุณต้องทำอะไรเพื่อหลีกเลี่ยงปัญหานั่นคือ:

return float4((texCoord.rg - (0.5f/textureSize)) * (textureSize/(textureSize-1)), 0, 1);

นั่นคือคุณลบออฟเซ็ตที่เหมาะสมเพื่อให้ได้พิกเซลซ้ายบนที่ 0,0 แล้วใช้สเกลเพื่อให้ได้มุมล่างขวาที่ถูกต้อง

สิ่งเดียวกันก็สามารถทำได้โดยการขยายพิกัด UV สำหรับเรขาคณิตนอกช่วง 0-1


หากต้องการอธิบายอย่างละเอียดเกี่ยวกับประโยคสุดท้าย: คุณสามารถนำการแปลงนี้ไปใช้กับ UV ในบัฟเฟอร์จุดสุดยอดสำหรับมุมทั้งสี่ของรูปสี่เหลี่ยมจากนั้นในพิกเซลที่จะreturn float4(texCoord.rg, 0, 1);ใช้
Nathan Reed

ฉันลองสูตรที่แนะนำข้างต้นและมันไม่ได้ผล: ใน 4x4 ตัวอย่างชุดตรวจสอบของฉันจากด้านบนฉันได้ 0, 42, 127 และ 212 ในช่อง R และ G จากซ้ายไปขวาหรือบนลงล่าง อย่างไรก็ตามฉันต้องการค่าตั้งแต่ 0 ถึง 255 ในขั้นตอนที่เว้นระยะเท่ากัน (สำหรับพื้นผิว 4x4 ที่เป็น 0, 85, 170 และ 255) ฉันพยายามเปลี่ยนค่า UV แต่ก็ยังไม่พบค่าชดเชยที่เหมาะสม
มาริโอ

0

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

เกือบ แต่เพียงครึ่งหนึ่งของพิกเซล เพียงแค่ลบ 0.5 ออกจากจุดยอดสี่แกนของคุณ เช่นคุณต้องการ 256x256 quad ที่มีพื้นผิวเดียวกันนี่คือคะแนนของคุณ:

p1 = (-0.5, -0.5)
p2 = (-0.5, 255-0.5)
p3 = (255-0.5, 255-0.5)
p4 = (255-0.5, -0.5)

หรือคุณอาจเพิ่มครึ่งหนึ่งของ texel ใน pixel shader แทน (texCoord.rg + 0.5 * (1.0 / texSize))

ชดเชยพิกเซลครึ่งหนึ่งเป็นข้อเท็จจริงที่รู้จักใน DX9 นี้และนี้บทความอาจช่วยให้คุณได้เป็นอย่างดี


0

นี่เกิดจากการสุ่มตัวอย่างเชิงเส้น หากคุณดูที่เท็กซัสทางด้านขวาและด้านล่างพิกเซลเต็มซ้ายดำคุณจะเห็นว่าพวกเขามี 63 ในช่อง R และ / หรือ G และ 2 ในนั้นมี 2 ใน B ตอนนี้ดูที่ โคลนสีเหลืองเข้มที่คุณได้รับ; มันคือ 31 ใน R และ G และ 1 ใน B นั่นเป็นผลมาจากการหาค่าเฉลี่ยของข้อความในกลุ่ม 2x2 ดังนั้นวิธีแก้ปัญหาคือการตั้งค่าตัวกรองพื้นผิวของคุณให้ชี้ไปที่


-2

นั่นเป็นเพียงเพราะคุณใช้ texCoords จากเอาท์พุทจุดสุดยอดซึ่งถูกแก้ไขโดยฮาร์ดไดรฟ์หลังจากการประมวลผลจุดสุดยอด

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