พื้นที่หน้าจอสู่อวกาศโลก


10

ฉันกำลังเขียนเกม 2D ที่โลกของเกมของฉันมีแกนxวิ่งจากซ้ายไปขวาแกนyวิ่งจากบนลงล่างและแกนzออกจากหน้าจอ:

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

ในขณะที่โลกของเกมของฉันอยู่บนลงล่างเกมจะแสดงผลในลักษณะเอียงเล็กน้อย:

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

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

var viewport = new Viewport(0, 0, this.ScreenWidth, this.ScreenHeight);
var screenPoint = viewport.Project(worldPoint.NegateY(), this.ProjectionMatrix, this.ViewMatrix, this.WorldMatrix);

NegateY()วิธีขยายไม่ตรงกับสิ่งที่ดูเหมือนตั้งแต่ XNA ของYแกนวิ่งล่างขึ้นบนแทนบนลงล่าง ภาพหน้าจอด้านบนแสดงว่าสิ่งนี้ทำงานได้ทั้งหมด โดยทั่วไปฉันมีหลายจุดในพื้นที่ 3 มิติที่ฉันแสดงในพื้นที่หน้าจอ ฉันสามารถแก้ไขคุณสมบัติกล้องแบบเรียลไทม์และดูว่ามันเคลื่อนไหวไปยังตำแหน่งใหม่ได้อย่างไร เห็นได้ชัดว่าเกมจริงของฉันจะใช้สไปรท์แทนที่จะเป็นจุดและตำแหน่งกล้องจะได้รับการแก้ไข แต่ฉันแค่พยายามทำให้คณิตศาสตร์ทั้งหมดเข้าที่ก่อนที่จะถึงสิ่งนั้น

ตอนนี้ฉันพยายามที่จะแปลงกลับในทางอื่น นั่นคือกำหนดxและyในพื้นที่หน้าจอด้านบนกำหนดจุดที่สอดคล้องกันในพื้นที่โลก ดังนั้นถ้าฉันชี้เคอร์เซอร์ไปที่มุมล่างซ้ายของรูปสี่เหลี่ยมคางหมูสีเขียวฉันต้องการอ่านพื้นที่โลก (0, 480) Zประสานงานที่ไม่เกี่ยวข้อง หรือค่อนข้างพิกัดzจะเป็นศูนย์เสมอเมื่อทำแผนที่กลับสู่อวกาศโลก เป็นหลักฉันต้องการใช้ลายเซ็นวิธีการนี้:

public Vector2 ScreenPointToWorld(Vector2 point)

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

ใครสามารถชี้ให้ฉันในทิศทางที่ถูกต้องเกี่ยวกับวิธีการบรรลุเป้าหมายนี้?

คำตอบ:


4

ฉันคิดว่าความคิดของคุณเป็นจุดบนมาก! อันดับแรกให้คำนวณเรย์สำหรับเคอร์เซอร์ของคุณโดยใช้ทั้งระนาบใกล้และระนาบไกลเป็นค่า Z สำหรับพิกัด 2D ของคุณ (เช่นใช้ 0 และ 1 สำหรับพิกัด Z ของคุณ) นี่คือวิธีการช่วยเหลือที่จะจัดการกับสิ่งนั้น:

public Ray GetScreenRay(Vector2 screenPosition, Viewport viewport, Matrix projectionMatrix, Matrix viewMatrix, Matrix worldMatrix)
{
    Vector3 nearPoint = viewport.Unproject(new Vector3(screenPosition, 0f), projectionMatrix, viewMatrix, worldMatrix);
    Vector3 farPoint = viewport.Unproject(new Vector3(screenPosition, 1f), projectionMatrix, viewMatrix, worldMatrix);
    return new Ray(nearPoint, Vector3.Normalize(farPoint - nearPoint));
}

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

Plane groundPlane = new Plane(ground.Vertices[0], ground.Vertices[1], ground.Vertices[2]);

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

float? result;
mouseRay.Intersects(ref groundPlane, out result);
if(result != null)
    Vector3 worldPoint = mouseRay.Position + mouseRay.Direction * result.Value;

คุณอาจต้องทำอะไรบางอย่างเกี่ยวกับNegateYวิธีการเช่นกัน แต่ฉันไม่แน่ใจว่าอยู่ที่ไหน


สิ่งนี้มีประโยชน์มาก - ขอบคุณมาก มันเป็นบรรทัดสุดท้ายที่ฉันหายไป ฉันไม่สามารถคิดได้ว่าจะทำอย่างไรกับทุ่นเมื่อฉันมีมัน! ฉันคิดว่าฉันจะต้องมีชื่อของคุณในเครดิตเกม :)
ฉัน -

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