วาดเส้นกว้างหนึ่งพิกเซลในพื้นที่ 3 มิติ


10

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

มีคำแนะนำใด ๆ เกี่ยวกับวิธีที่ฉันสามารถทำได้?

คำตอบ:


24

เส้นการแสดงผล - วิธีที่ 1 (ดั้งเดิม)

สำหรับเส้นที่เรียบง่ายในพื้นที่ 3D คุณสามารถวาดพวกเขาใช้LineListหรือLineStripดั้งเดิม นี่คือจำนวนโค้ดขั้นต่ำที่คุณต้องเพิ่มลงในโปรเจ็กต์ XNA ที่ว่างเพื่อให้วาดเส้นจาก (0,0,0) ถึง (0,0, -50) เส้นควรมีความกว้างประมาณเดียวกันไม่ว่าจะวางกล้องไว้ที่ใด

// Inside your Game class
private BasicEffect basicEffect;
private Vector3 startPoint = new Vector3(0, 0, 0);
private Vector3 endPoint = new Vector3(0, 0, -50);

// Inside your Game.LoadContent method
basicEffect = new BasicEffect(GraphicsDevice);
basicEffect.View = Matrix.CreateLookAt(new Vector3(50, 50, 50), new Vector3(0, 0, 0), Vector3.Up);
basicEffect.Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45f), GraphicsDevice.Viewport.AspectRatio, 1f, 1000f);

// Inside your Game.Draw method
basicEffect.CurrentTechnique.Passes[0].Apply();
var vertices = new[] { new VertexPositionColor(startPoint, Color.White),  new VertexPositionColor(endPoint, Color.White) };
GraphicsDevice.DrawUserPrimitives(PrimitiveType.LineList, vertices, 0, 1);

ฉันเป็นพื้นสร้างง่ายBasicEffectที่จะถือมุมมองและประมาณการของฉันแปลงและผ่านจุดสอง (จัดเก็บตำแหน่งและสี) กับวิธีการที่จะแสดงผลเป็นGraphicsDevice.DrawUserPrimitivesLineList

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


คะแนนการแสดงผล - วิธีที่ 1 (SpriteBatch)

สำหรับจุดที่วาดภาพนี้ใช้เพื่อจะได้ง่ายโดยใช้สไปรท์จุด แต่พวกเขาจะถูกลบออกจาก XNA 4.0 มีทางเลือกเล็กน้อยว่า วิธีที่ง่ายที่สุดคือการสร้าง 1x1 สีขาวTexture2Dวัตถุและทำให้มันใช้SpriteBatchในตำแหน่งที่หน้าจอที่ถูกต้องที่คุณสามารถหาได้ง่ายโดยใช้วิธี Viewport.Project

คุณสามารถสร้างTexture2Dวัตถุที่ต้องการเช่นนี้:

Texture2D pixel = new Texture2D(GraphicsDevice, 1, 1);
pixel.SetData(new [] { Color.White });

และทำให้มันอยู่ในตำแหน่ง (x, y, z) เช่นนี้:

// Find screen equivalent of 3D location in world
Vector3 worldLocation = new Vector3(0, 0, 50);
Vector3 screenLocation = GraphicsDevice.Viewport.Project(worldLocation, projectionMatrix, viewMatrix, Matrix.Identity);

// Draw our pixel texture there
spriteBatch.Begin();
spriteBatch.Draw(pixel, new Vector2(screenLocation.X, screenLocation.Y), Color.White);
spriteBatch.End();

เส้นการแสดงผล - วิธีที่ 2 (SpriteBatch)

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


จุดแสดงผล - วิธีที่ 2 (เส้นย่อยที่มีค่าดั้งเดิม)

ในความคิดเห็น eBusiness ยกคำถามต่อไปนี้:

สิ่งที่เกี่ยวกับเส้นที่มีจุดเริ่มต้นและจุดสิ้นสุดเหมือนกันนั่นจะไม่สร้างจุดหรือไม่ หรือว่ามันจะมองไม่เห็น?

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

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

Vector3 GetEndPointForDot(Vector3 start)
{
    // Convert start point to screen space
    Vector3 screenPoint = GraphicsDevice.Viewport.Project(start, projection, view, Matrix.Identity);

    // Screen space is defined in pixels so adding (1,0,0) moves it right one pixel
    screenPoint += Vector3.Right;

    // Finally unproject it back into world space
    return GraphicsDevice.Viewport.Unproject(screenPoint, projection, view, Matrix.Identity);
}

ตามด้วยการเรนเดอร์มันเป็นสายดั้งเดิมดั้งเดิม


สาธิต

นี่คือสิ่งที่ฉันได้วาดเส้นสีขาวในพื้นที่ 3 มิติโดยใช้รายการบรรทัดดั้งเดิมและจุดสีแดงที่ปลายทั้งสองของบรรทัดโดยใช้พื้นผิว 1x1 และ SpriteBatch รหัสที่ใช้นั้นสวยมากที่ฉันเขียนไว้ด้านบน ฉันได้ขยายเข้าไปด้วยดังนั้นคุณจึงสามารถยืนยันได้ว่ามีความกว้างเพียงหนึ่งพิกเซล:

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


สิ่งที่เกี่ยวกับเส้นที่มีจุดเริ่มต้นและจุดสิ้นสุดเหมือนกันนั่นจะไม่สร้างจุดหรือไม่ หรือว่ามันจะมองไม่เห็น?
aaaaaaaaaaaa

@eBusiness เป็นคำถามที่ดี! ฉันแค่ลองทำดูและมันก็ไม่ได้ช่วยอะไรเลย
David Gouveia

@eBusiness ฉันเพิ่งค้นพบวิธีการ แต่ฉันคิดว่ามันค่อนข้างโง่ ฉันจะเพิ่มเพื่อความสมบูรณ์ต่อไป
David Gouveia

2

สิ่งนี้ถูกแท็กเป็น XNA ดังนั้นฉันคิดว่านั่นคือสิ่งที่คุณถาม

ถ้าเป็นเช่นนั้นบทความนี้ควรมีประโยชน์สำหรับบรรทัด:

http://msdn.microsoft.com/en-us/library/bb196414(v=xnagamestudio.40).aspx

แน่นอนว่าคุณสามารถใช้เมทริกซ์มุมมอง / การฉายภาพของคุณเองแทนที่จะเป็นเมทริกซ์ โดยทั่วไปPrimitiveType.LineListหรือLineStripเป็นวิธีการวาดเส้นที่ระดับ GPU

สำหรับคะแนนคุณไม่สามารถใช้ PrimitiveType.PointList เพื่อดึงคะแนนอีกต่อไปใน XNA 4.0 คุณจะต้องทำสามเหลี่ยมเล็ก ๆ แทน ตัวอย่างนี้ให้พื้นฐานที่ดี:

http://create.msdn.com/education/catalog/sample/primitives_3d

สำหรับ XNA รุ่นก่อนหน้าหากคุณใช้หนึ่งในนั้นคุณสามารถไปข้างหน้าและอ่านส่วนจุดของรุ่น XNA 3.0 ของบทความที่โพสต์ข้างต้น:

http://msdn.microsoft.com/en-us/library/bb196414(v=xnagamestudio.30).aspx

หมายเหตุลิงค์มี:

graphics.GraphicsDevice.RenderState.PointSize = 10;

1เห็นได้ชัดว่าการเปลี่ยนแปลงที่

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