Tôi muốn vẽ một đường trong không gian 3D luôn rộng chính xác một pixel trên màn hình, bất kể nó cách camera bao xa. (Và tương tự cho các điểm duy nhất quá).
Bất kỳ gợi ý về làm thế nào tôi có thể làm điều đó?
Tôi muốn vẽ một đường trong không gian 3D luôn rộng chính xác một pixel trên màn hình, bất kể nó cách camera bao xa. (Và tương tự cho các điểm duy nhất quá).
Bất kỳ gợi ý về làm thế nào tôi có thể làm điều đó?
Câu trả lời:
Kết xuất đường - Phương pháp 1 (Nguyên thủy)
Đối với các đường đơn giản trong không gian 3D, bạn có thể vẽ chúng bằng cách sử dụng LineList
hoặc LineStrip
nguyên thủy. Đây là số lượng mã tối thiểu bạn phải thêm vào một dự án XNA trống để nó vẽ một dòng từ (0,0,0) đến (0,0, -50). Đường kẻ có vẻ như có cùng chiều rộng cho dù camera được đặt ở đâu.
// 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);
Về cơ bản, tôi đã tạo một đơn giản BasicEffect
để giữ các phép biến đổi góc nhìn và phép chiếu của mình và truyền hai đỉnh (vị trí lưu trữ và màu sắc) cho GraphicsDevice.DrawUserPrimitives
phương thức được hiển thị là a LineList
.
Tất nhiên, có nhiều cách để tối ưu hóa nó, hầu hết trong số đó liên quan đến việc tạo một VertexBuffer
để lưu trữ tất cả các đỉnh và gộp càng nhiều dòng càng tốt vào một lệnh gọi Draw nhưng không liên quan đến câu hỏi.
Kết xuất điểm - Phương pháp 1 (SpriteBatch)
Đối với các điểm vẽ, điều này được sử dụng dễ dàng bằng cách sử dụng các họa tiết điểm nhưng chúng đã bị xóa khỏi XNA 4.0 . Có một vài lựa chọn thay thế mặc dù. Cách dễ nhất là tạo một Texture2D
đối tượng trắng 1x1 và hiển thị nó bằng cách sử dụng SpriteBatch
đúng vị trí màn hình mà bạn có thể dễ dàng tìm thấy bằng phương thức Viewport.Project .
Bạn có thể tạo Texture2D
đối tượng cần thiết như thế này:
Texture2D pixel = new Texture2D(GraphicsDevice, 1, 1);
pixel.SetData(new [] { Color.White });
Và kết xuất nó tại vị trí (x, y, z) như thế này:
// 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();
Kết xuất đường - Phương pháp 2 (SpriteBatch)
Ngoài ra, bạn cũng có thể vẽ các đường bằng SpriteBatch
cách sử dụng kỹ thuật được mô tả ở đây . Trong trường hợp này, bạn chỉ cần tìm tọa độ không gian màn hình cho cả hai đầu của dòng 3D (một lần nữa sử dụng Viewport.Project
) và sau đó vẽ một đường thẳng thông thường giữa chúng.
Kết xuất điểm - Phương pháp 2 (Đường nhỏ với nguyên thủy)
Trong các ý kiến, eBusiness đưa ra câu hỏi sau:
Điều gì về một dòng có cùng điểm bắt đầu và điểm kết thúc, sẽ không tạo ra một điểm? Hay đơn giản là nó sẽ vô hình?
Tôi đã thử và hiển thị LineList
bằng cách sử dụng cùng một điểm bắt đầu và điểm kết thúc mà không có gì được rút ra. Tôi đã tìm thấy một cách xung quanh nó mặc dù vậy tôi sẽ mô tả nó ở đây cho đầy đủ.
Bí quyết là không sử dụng cùng một điểm bắt đầu và điểm kết thúc, mà thay vào đó là vẽ một đường kẻ quá nhỏ, nó chỉ xuất hiện dưới dạng một pixel khi được vẽ. Vì vậy, để chọn điểm kết thúc chính xác, trước tiên tôi chiếu điểm không gian thế giới vào không gian màn hình, di chuyển nó đúng một pixel trong không gian màn hình và cuối cùng chiếu nó trở lại không gian thế giới. Đó là điểm cuối của dòng của bạn để làm cho nó trông giống như một dấu chấm. Một cái gì đó như thế này:
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);
}
Tiếp theo là hiển thị nó như một dòng nguyên thủy bình thường.
Trình diễn
Đây là những gì tôi đã vẽ một đường trắng trong không gian 3D bằng cách sử dụng danh sách đường nguyên thủy và các chấm đỏ ở hai đầu của đường bằng kết cấu 1x1 và SpriteBatch. Mã được sử dụng là khá nhiều những gì tôi đã viết ở trên. Tôi cũng đã phóng to để bạn có thể xác nhận rằng chúng chính xác rộng một pixel:
Điều này được gắn thẻ là XNA vì vậy tôi cho rằng đó là những gì bạn đang hỏi về?
Nếu vậy, bài viết này sẽ hữu ích cho các dòng:
http://msdn.microsoft.com/en-us/l Library / bb196414 (v = xnagamestudio.40) .aspx
Tất nhiên bạn có thể sử dụng ma trận chế độ xem / chiếu của riêng bạn thay vì của chúng. Về cơ bản, PrimitiveType.LineList
hoặc LineStrip
là làm thế nào để vẽ các đường ở cấp độ GPU.
Đối với điểm, bạn không còn có thể sử dụng PrimitiveType.PointList để vẽ điểm nữa trong XNA 4.0. Thay vào đó bạn sẽ phải làm những hình tam giác rất nhỏ. Mẫu này cung cấp một đường cơ sở tốt:
http://create.msdn.com/education/catalog/sample/primologists_3d
Đối với các phiên bản XNA trước đây, nếu bạn đang sử dụng một trong những phiên bản đó, bạn có thể tiếp tục và đọc phần Điểm của phiên bản XNA 3.0 của bài viết được đăng ở trên:
http://msdn.microsoft.com/en-us/l Library / bb196414 (v = xnagamestudio.30) .aspx
Lưu ý liên kết có:
graphics.GraphicsDevice.RenderState.PointSize = 10;
Rõ ràng thay đổi điều đó thành 1
.