Tworzę grę 3D, w której umieszczam wykrzyknik nad interesującymi miejscami.
Aby dowiedzieć się, gdzie na ekranie 2D powinienem umieścić znacznik, ręcznie rzutuję punkt 3D, w którym powinien znajdować się znacznik.
To wygląda tak:
Wygląda całkiem nieźle. Kiedy znacznik znajduje się poza ekranem, po prostu przycinam współrzędne, aby pasowały do ekranu. To wygląda tak:
Jak dotąd pomysł idzie całkiem nieźle. Jednak gdy punkty zainteresowania znajdują się za kamerą, powstałe współrzędne X, Y są odwrócone (jak w dodatnich / ujemnych), a znacznik pojawia się w przeciwległym rogu ekranu, tak jak poniżej:
(Rzutowany następnie zaciśnięty punkt jest końcem markera. Nie przeszkadza to w obrocie markera)
Ma to sens, ponieważ współrzędne za ścięciem są odwrócone w X i Y. Więc robię to, aby odwrócić współrzędne, gdy znajdują się za kamerą. Jednak wciąż nie wiem, jaki jest dokładnie warunek, w którym należy odwrócić współrzędne.
Tak właśnie wygląda mój kod projekcji (w C # z 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);
}
Jak widać, moim obecnym pomysłem jest odwrócenie współrzędnych, gdy współrzędne Z lub W są ujemne. Działa prawie przez większość czasu, ale wciąż istnieją pewne bardzo specyficzne lokalizacje kamer, w których nie działa. W szczególności ten punkt pokazuje jedną współrzędną działającą, a drugą nie (poprawna lokalizacja powinna być w prawym dolnym rogu):
Próbowałem odwrócić, gdy:
Z
jest negatywny (to jest dla mnie najbardziej sensowne)W
jest ujemny (nie rozumiem znaczenia ujemnej wartości W)- Albo
Z
alboW
jest negatywne (co obecnie działa przez większość czasu) Z
iW
mają inny znak, alias:Z / W < 0
(ma dla mnie sens. choć nie działa)
Ale wciąż nie znalazłem spójnego sposobu, w jaki wszystkie moje punkty są poprawnie rzutowane.
Jakieś pomysły?
źródło
AB
, czy nie przekształcam pozycji docelowej ze współrzędnych światowych na współrzędne kamery?Biorąc pod uwagę trzy wektory
[camera position]
,[camera direction]
i[object position]
. Oblicz iloczyn skalarny dla[camera direction]
i[object position]-[camera position]
. Jeśli wynik jest ujemny, obiekt znajduje się za kamerą.Biorąc pod uwagę, że dobrze zrozumiałem twój kod, będzie to:
źródło
Y
jestPositionY + (y * Scaling)
. Spróbuję dziś wieczoremZ
bycia dokładnie0
powinno być bardzo małe, większość graczy nigdy go nie doświadczy, a wpływ rozgrywki w spodziewanych kilku przypadkach jest znikomą usterką wizualną pojedynczej klatki. Powiedziałbym, że twój czas lepiej spędzić gdzie indziej.Tylko test (przewidywany W <0), a nie (Z <0 || W <0).
W niektórych formułach przestrzeni klipu ( kaszel OpenGL kaszel ) widoczny zakres obejmuje dodatnie i ujemne wartości Z, podczas gdy W jest zawsze dodatnie przed kamerą, a ujemne z tyłu.
źródło
I usuń tę część
źródło
Wypróbuj billboard, który automatycznie sprawi, że zdjęcie będzie skierowane w stronę aparatu i automatycznie narysuje zdjęcie na ekranie w odpowiednim miejscu
źródło