ฉันจะฉายจุดหลังกล้องได้อย่างถูกต้องได้อย่างไร?


10

ฉันกำลังสร้างเกม 3 มิติโดยใส่เครื่องหมายอัศเจรีย์เหนือจุดสนใจ

เพื่อที่จะหาว่าในหน้าจอ 2D ที่ฉันควรวางเครื่องหมายของฉันฉันกำลังฉายจุด 3D ด้วยตนเองที่เครื่องหมายควร

ดูเหมือนว่านี้:

เครื่องหมายดูดีมาก

ดูดีทีเดียว เมื่อเครื่องหมายอยู่นอกหน้าจอฉันเพียงแค่คลิปพิกัดเพื่อให้พอดีกับหน้าจอ ดูเหมือนว่านี้:

เครื่องหมายที่ดูยอดเยี่ยมยิ่งขึ้น

จนถึงตอนนี้ความคิดก็ไปได้สวย อย่างไรก็ตามเมื่อจุดที่น่าสนใจอยู่ด้านหลังกล้องพิกัด X, Y ที่ได้จะกลับด้าน (เหมือนเป็นบวก / ลบ) และฉันก็ได้เครื่องหมายที่ปรากฏบนมุมตรงข้ามของหน้าจอดังนี้:

เครื่องหมายไม่น่ากลัวนัก

(จุดที่คาดการณ์ไว้จากนั้นเป็นจุดปลายของเครื่องหมายไม่ต้องคำนึงถึงการหมุนของเครื่องหมาย)

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

นี่คือสิ่งที่รหัสการคาดการณ์ของฉันดูเหมือน (ใน C # กับ SharpDX):

    public override PointF ProjectPosition(float viewportWidth, float viewportHeight, float y)
    {
        var projectionMatrix = Matrix.PerspectiveFovRH(GetCalibratedFOV(Camera.FOV, viewportWidth, viewportHeight), viewportWidth / viewportHeight, Camera.Near, Camera.Far);
        var viewMatrix = Matrix.LookAtRH(new Vector3(Camera.PositionX, Camera.PositionY, Camera.PositionZ), new Vector3(Camera.LookAtX, Camera.LookAtY, Camera.LookAtZ), Vector3.UnitY);
        var worldMatrix = Matrix.RotationY(Rotation) * Matrix.Scaling(Scaling) * Matrix.Translation(PositionX, PositionY, PositionZ);
        var worldViewProjectionMatrix = worldMatrix * viewMatrix * projectionMatrix;

        Vector4 targetVector = new Vector4(0, y, 0, 1);
        Vector4 projectedVector = Vector4.Transform(targetVector, worldViewProjectionMatrix);

        float screenX = (((projectedVector.X / projectedVector.W) + 1.0f) / 2.0f) * viewportWidth;
        float screenY = ((1.0f - (projectedVector.Y / projectedVector.W)) / 2.0f) * viewportHeight;
        float screenZ = projectedVector.Z / projectedVector.W;

        // Invert X and Y when behind the camera
        if (projectedVector.Z < 0 ||
            projectedVector.W < 0)
        {
            screenX = -screenX;
            screenY = -screenY;
        }

        return new PointF(screenX, screenY);
    }

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

เครื่องหมายครึ่งหนึ่งที่ยอดเยี่ยม

ฉันได้ลองกลับด้านเมื่อ:

  • Z เป็นลบ (นี่คือสิ่งที่สมเหตุสมผลที่สุดสำหรับฉัน)
  • W เป็นลบ (ฉันไม่เข้าใจความหมายของค่า W เชิงลบ)
  • ไม่ว่าจะเป็นZหรือWเป็นเชิงลบ (ขณะนี้ทำงานได้เกือบตลอดเวลา)
  • ZและWเป็นสัญญาณที่แตกต่างกัน aka: Z / W < 0(ทำให้รู้สึกถึงฉันไม่ทำงานแม้ว่า)

แต่ก็ยังไม่พบวิธีที่สอดคล้องกับที่ทุกจุดของฉันถูกฉายอย่างถูกต้อง

ความคิดใด ๆ

คำตอบ:


2

วิธีการทำมันแตกต่างกันเล็กน้อย?

เริ่มตามปกติและแสดงเครื่องหมายทั้งหมดภายในวิวพอร์ต หากเครื่องหมายอยู่นอกวิวพอร์ต - ดำเนินการต่อ:

  1. รับตำแหน่งของเครื่องหมาย A
  2. รับตำแหน่งของกล้องB(อาจอยู่ด้านหน้าเล็กน้อย)
  3. คำนวณเวกเตอร์ 3 มิติABระหว่างสองสิ่งนี้
  4. แปลงและทำให้เวกเตอร์ปกติเป็นขอบเขตหน้าจอ 2D (Aจะอยู่ในศูนย์กลางการดูและBจะตีกรอบมุมมอง)

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

เส้นสีเป็นABเวกเตอร์ เส้นสีดำบางเป็นความสูงของตัวอักษร ด้านขวาคือหน้าจอ 2D

  1. อาจเพิ่มกฎว่าทุกอย่างที่อยู่ด้านหลังกล้องจะไปที่ขอบล่างเสมอ
  2. วาดเครื่องหมายในพื้นที่หน้าจอเกี่ยวกับขนาดเครื่องหมายและทับซ้อน

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


ขั้นตอนที่ 4 นั้นจะทำงานอย่างไร
แพนด้า Pyjama

@PandaPajama: ฉันได้เพิ่มคำตอบเล็กน้อย ชัดเจนขึ้นแล้วหรือ
Kromster

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

@PandaPajama: เท่าที่ฉันเข้าใจว่าคุณกำลังทำในพื้นที่กล้อง (ดังนั้นปัญหา ZW เชิงลบ) ฉันแนะนำให้ทำในพื้นที่โลกแล้วแปลงเป็น space-screen เท่านั้น
Kromster

แต่โดยการคำนวณABฉันไม่ได้แปลงตำแหน่งเป้าหมายจากพิกัดโลกเป็นพิกัดกล้องหรือไม่
แพนด้า Pyjama

1

ได้รับสามเวกเตอร์[camera position], และ[camera direction] [object position]คำนวณคูณจุดของและ[camera direction] [object position]-[camera position]หากผลลัพธ์เป็นลบวัตถุจะอยู่ด้านหลังกล้อง

เนื่องจากฉันเข้าใจรหัสของคุณถูกต้อง:

if((PositionX - Camera.PositionX) * Camera.LookAtX
    + (PositionY - Camera.PositionY) * Camera.LookAtY
    + (PositionZ - Camera.PositionZ) * Camera.LookAtZ
    < 0)

YPositionY + (y * Scaling)เป็น คืนนี้ฉันจะลองดูนะ
แพนด้า Pajama

ด้วยสิ่งนี้ฉันสามารถรู้ได้อย่างแน่นอนว่าเมื่อใดที่จุดอยู่ด้านหลังกล้อง อย่างไรก็ตามสิ่งนี้ไม่ได้ป้องกันการฉายภาพให้ถึงภาวะเอกฐานที่ Z = 0
Panda Pyjama

@PandaPajama นั่นเป็นปัญหาที่เกิดขึ้นจริงเหรอ? ความน่าจะZเป็นที่แน่นอน0ควรจะเล็กมากผู้เล่นส่วนใหญ่จะไม่มีวันได้สัมผัสและผลกระทบจากการเล่นเกมในบางกรณีที่คาดว่าจะเป็นความผิดพลาดเล็กน้อยที่มองเห็นได้ของเฟรมเดี่ยว ฉันจะบอกว่าเวลาของคุณดีกว่าที่อื่น
aaaaaaaaaaaa

0

ทดสอบเท่านั้น (คาดการณ์ W <0) ไม่ใช่ (Z <0 || W <0)

ในบางสูตรพื้นที่คลิป ( ไอ OpenGL ไอ ) ซึ่งเป็นช่วงที่มองเห็นรวมถึงค่า Z บวกและลบในขณะที่ W เป็นบวกเสมอในด้านหน้าของกล้องและเบื้องหลังเชิงลบ


ฉันได้ลองด้วย W <0 เท่านั้น แต่ยังมีสถานที่ที่ฉายไม่ถูกต้อง
แพนด้า Pyjama

0
float screenX = (((projectedVector.X / abs(projectedVector.W)) + 1.0f) / 2.0f) * viewportWidth;
float screenY = ((1.0f - (projectedVector.Y / abs(projectedVector.W))) / 2.0f) * viewportHeight;

และลบส่วนนี้

// Invert X and Y when behind the camera
if (projectedVector.Z < 0 || projectedVector.W < 0)
{
    screenX = -screenX;
    screenY = -screenY;
}

-2

ลองป้ายโฆษณาซึ่งจะทำให้รูปหันหน้าไปทางกล้องโดยอัตโนมัติและจะวาดรูปลงบนหน้าจอในตำแหน่งที่เหมาะสมโดยอัตโนมัติ


3
คุณอ่านคำถามหรือไม่
Kromster

ขออภัยให้ฉันอธิบาย - มันเป็นไปได้ที่จะเอาท์พุทของบิลบอร์ดกำจัดสเกล (ดังนั้นมันคือ 2D แต่เป็นไปตามตำแหน่ง 3 มิติ) จากนั้นเก็บมันไว้ในขอบเขตของหน้าจอโดยใช้คณิตศาสตร์เมทริกซ์
Michael Langford

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