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?
la source
AB
, ne convertis-je pas la position cible des coordonnées du monde en coordonnées de la caméra?Étant donné les trois vecteurs
[camera position]
,[camera direction]
et[object position]
. Calculez le produit scalaire de[camera direction]
et[object position]-[camera position]
. Si le résultat est négatif, l'objet est derrière la caméra.Étant donné que j'ai bien compris votre code, ce serait:
la source
Y
estPositionY + (y * Scaling)
. Je vais essayer ce soirZ
être exactement0
devrait être très faible, la plupart des joueurs ne l'éprouveront jamais, et l'impact du gameplay dans les quelques cas attendus est un problème visuel d'une seule image négligeable. Je dirais que votre temps est mieux utilisé ailleurs.Test uniquement (projeté.W <0), pas (Z <0 || W <0).
Dans certaines formulations d'espace clip ( toux OpenGL toux ), la plage visible comprend des valeurs Z positives et négatives, tandis que W est toujours positif devant la caméra et négatif derrière.
la source
Et supprimez cette partie
la source
Essayez un panneau d'affichage, qui fera automatiquement la photo face à la caméra, et dessinera automatiquement la photo sur l'écran au bon endroit
la source