Je fais un jeu en 3D dans lequel je place un marqueur d'exclamation au-dessus des points d'intérêt.
Afin de savoir où sur l'écran 2D dois-je placer mon marqueur, je projette manuellement le point 3D où le marqueur doit être.
Cela ressemble à ceci:
Ça a l'air plutôt bien. Lorsque le marqueur est en dehors de l'écran, je coupe simplement les coordonnées pour qu'elles s'insèrent dans l'écran. Cela ressemble à ceci:
Jusqu'à présent, l'idée se passe plutôt bien. Cependant, lorsque les points d'intérêt sont derrière la caméra, les coordonnées X, Y résultantes sont inversées (comme en positif / négatif), et je fais apparaître le marqueur dans le coin opposé de l'écran, comme ceci:
(Le point projeté puis fixé est la pointe du marqueur. Ne vous souciez pas de la rotation du marqueur)
Cela a du sens, car les coordonnées derrière le tronc sont inversées en X et Y. Donc, ce que je fais, c'est inverser les coordonnées quand elles sont derrière la caméra. Cependant, je ne sais toujours pas quelle est exactement la condition lorsque les coordonnées doivent être inversées.
Voici à quoi ressemble mon code de projection (en C # avec 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);
}
Comme vous pouvez le voir, mon idée actuelle est d'inverser les coordonnées lorsque les coordonnées Z ou W sont négatives. Cela fonctionne la plupart du temps, mais il existe encore des emplacements de caméra très spécifiques où cela ne fonctionne pas. En particulier, ce point montre une coordonnée qui fonctionne et l'autre non (l'emplacement correct doit être en bas à droite):
J'ai essayé d'inverser quand:
Z
est négatif (c'est ce qui a le plus de sens pour moi)W
est négatif (je ne comprends pas la signification d'une valeur W négative)- Soit
Z
ouW
est négatif (ce qui fonctionne actuellement la plupart du temps) Z
etW
sont de signe différent, alias:Z / W < 0
(est logique pour moi. ne fonctionne pas cependant)
Mais je n'ai toujours pas trouvé de manière cohérente avec laquelle tous mes points sont correctement projetés.
Des idées?