Estoy haciendo un juego en 3D en el que pongo un marcador de exclamación sobre los puntos de interés.
Para averiguar en qué lugar de la pantalla 2D debo colocar mi marcador, estoy proyectando manualmente el punto 3D donde debería estar el marcador.
Se parece a esto:
Se ve bastante bien. Cuando el marcador está fuera de la pantalla, simplemente recorto las coordenadas para que quepan en la pantalla. Se parece a esto:
Hasta ahora la idea está yendo bastante bien. Sin embargo, cuando los puntos de interés están detrás de la cámara, las coordenadas X, Y resultantes se invierten (como en positivo / negativo), y obtengo el marcador para que aparezca en la esquina opuesta de la pantalla, así:
(El punto proyectado y luego sujeto es la punta del marcador. No importa la rotación del marcador)
Tiene sentido, ya que las coordenadas detrás del tronco están invertidas en X e Y. Entonces, lo que estoy haciendo es invertir las coordenadas cuando están detrás de la cámara. Sin embargo, todavía no sé cuál es exactamente la condición cuando las coordenadas deben invertirse.
Así es actualmente mi código de proyección (en C # con 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);
}
Como puede ver, mi idea actual es invertir las coordenadas cuando las coordenadas Z o W son negativas. Funciona la mayor parte del tiempo, pero todavía hay algunas ubicaciones de cámara muy específicas donde no funciona. En particular, este punto muestra una coordenada funcionando y la otra no (la ubicación correcta debe ser la esquina inferior derecha):
He intentado invertir cuando:
Z
es negativo (esto es lo que tiene más sentido para mí)W
es negativo (no entiendo el significado de un valor W negativo)- Ya sea
Z
oW
es negativo (lo que está funcionando actualmente la mayor parte del tiempo) Z
yW
son de signo diferente, alias:Z / W < 0
(tiene sentido para mí, aunque no funciona)
Pero todavía no he encontrado una manera consistente con la cual todos mis puntos se proyecten correctamente.
¿Algunas ideas?
fuente
AB
, ¿no estoy convirtiendo la posición de destino de las coordenadas mundiales a las coordenadas de la cámara?Dados los tres vectores
[camera position]
,[camera direction]
y[object position]
. Calcule el producto escalar de[camera direction]
y[object position]-[camera position]
. Si el resultado es negativo, el objeto está detrás de la cámara.Dado que entendí bien su código, sería:
fuente
Y
esPositionY + (y * Scaling)
. Lo intentaré esta nocheZ
ser exactamente0
debe ser muy pequeña, la mayoría de los jugadores nunca lo experimentarán, y el impacto del juego en los pocos casos esperados es un fallo visual insignificante de un solo cuadro. Yo diría que tu tiempo se gasta mejor en otro lado.Solo prueba (proyectado. W <0), no (Z <0 || W <0).
En algunas formulaciones de espacio de clip ( tos OpenGL tos ), el rango visible incluye valores Z positivos y negativos, mientras que W siempre es positivo delante de la cámara y negativo detrás.
fuente
Y quita esta parte
fuente
Pruebe con una valla publicitaria, que hará que la imagen quede automáticamente frente a la cámara, y la dibujará automáticamente en la pantalla en la ubicación adecuada
fuente