카메라 뒤의 점을 올바르게 투사하려면 어떻게합니까?


10

관심 장소 위에 느낌표를 표시하는 3D 게임을 만들고 있습니다.

2D 화면에서 마커를 어디에 놓아야하는지 확인하기 위해 마커가 있어야 할 3D 포인트를 수동으로 투영하고 있습니다.

다음과 같이 보입니다 :

멋진 찾고 마커

꽤 좋아 보인다. 마커가 화면 바깥에 있으면 좌표를 화면에 맞추기 위해 단순히 좌표를 자릅니다. 다음과 같이 보입니다 :

훨씬 더 멋진 마커

지금까지 아이디어는 꽤 잘 진행되고 있습니다. 그러나 관심 지점이 카메라 뒤에있을 때 결과 X, Y 좌표가 양수 / 음수로 반전되어 다음과 같이 화면의 반대편 모서리에 마커가 나타납니다.

굉장하지 않은 마커

(프로젝션 된 클램프 지점은 마커의 끝입니다. 마커의 회전은 신경 쓰지 마십시오)

절두체 뒤의 좌표가 X와 Y로 반전되기 때문에 의미가 있습니다. 따라서 내가하고있는 것은 좌표가 카메라 뒤에서 좌표를 뒤집는 것입니다. 그러나 좌표를 반전 해야하는 조건이 무엇인지 여전히 알지 못합니다.

이것은 현재 프로젝션 코드의 모습입니다 (C #에서 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);
    }

보시다시피, 현재 아이디어는 Z 또는 W 좌표가 음수 일 때 좌표를 반전시키는 것입니다. 대부분의 경우 작동하지만 여전히 작동하지 않는 매우 구체적인 카메라 위치가 있습니다. 특히이 점은 하나의 좌표가 작동하고 다른 하나는 작동하지 않음을 나타냅니다 (올바른 위치는 오른쪽 아래 여야 함).

반 대단한 마커

나는 때 반전을 시도했다 :

  • Z 부정적 (이것이 나에게 가장 의미가있는 것입니다)
  • W 음수 (음수 W 값의 의미를 이해하지 못함)
  • 하나 Z또는 W음수 (현재 대부분의 시간을 작동하고 무엇을)
  • Z그리고 W다른 표시가 있습니다. 일명 : Z / W < 0(나에게 이해가됩니다.하지만 작동하지 않습니다)

그러나 여전히 내 모든 포인트가 올바르게 투영되는 일관된 방법을 찾지 못했습니다.

어떤 아이디어?

답변:


2

조금 다르게하는 것은 어떻습니까?

평소대로 시작하고 뷰포트 내에서 모든 마커를 렌더링합니다. 마커가 뷰포트 외부에있는 경우 다음을 수행하십시오.

  1. 마커의 위치를 ​​얻는다 A
  2. 카메라의 위치를 ​​잡습니다 B( 카메라 앞에 약간있을 수 있음)
  3. AB이 둘 사이의 3D 벡터 계산
  4. 벡터를 2D 화면 경계로 변환하고 정규화합니다 ( A뷰 중앙에 있고 B뷰 경계에 부딪 힙니다).

여기에 이미지 설명을 입력하십시오

컬러 라인은 AB벡터입니다. 가는 검은 선은 문자 높이입니다. 오른쪽은 2D 화면입니다

  1. 카메라 뒤에있는 모든 것이 항상 아래쪽 가장자리로 진행된다는 규칙을 추가하십시오.
  2. 마커 크기 및 오버랩과 관련하여 화면 공간에 마커를 그립니다.

뷰포트를 끄는 마커가 위치간에 점프하는지 확인하기 위해 시도해야 할 수도 있습니다. 이 경우 마커가 뷰포트의 경계에 접근 할 때 위치를 파악할 수 있습니다.


4 단계는 정확히 어떻게 작동합니까?
Panda Pajama

@ PandaPajama : 대답에 약간을 추가했습니다. 지금은 더 명확합니까?
Kromster

실제로는 아닙니다. 벡터를 어떻게 "변환하고 정규화"합니까? 만약 그것이 프로젝션 매트릭스를 적용하는 것이라면, 내가하고있는 것과 똑같은 일을하는 것입니다
Panda Pajama

@ PandaPajama : 내가 당신이 카메라 공간에서하고 있다는 것을 이해하는 한 (따라서 부정적인 ZW 문제). 월드 공간에서 그런 다음 화면 공간으로 변환하는 것이 좋습니다.
Kromster

그러나를 계산 AB하여 대상 위치를 월드 좌표에서 카메라 좌표로 변환하지 않습니까?
Panda Pajama

1

세 벡터 감안할 때 [camera position], [camera direction]하고 [object position]. [camera direction]및 의 내적을 계산합니다 [object position]-[camera position]. 결과가 음수이면 물체가 카메라 뒤에 있습니다.

귀하의 코드를 올바르게 이해했다면 다음과 같습니다.

if((PositionX - Camera.PositionX) * Camera.LookAtX
    + (PositionY - Camera.PositionY) * Camera.LookAtY
    + (PositionZ - Camera.PositionZ) * Camera.LookAtZ
    < 0)

Y입니다 PositionY + (y * Scaling). 오늘 밤에 시험해 볼게요
Panda Pajama

이것으로 언제 포인트가 카메라 뒤에 있는지 알 수 있습니다. 그러나 이것이 Z = 0에서 투영이 특이점에 도달하는 것을 막지는 않습니다.
Panda Pajama

@PandaPajama 이것이 실제적인 문제입니까? Z정확하게 0될 확률은 매우 작아야하며, 대부분의 플레이어는이를 경험하지 못할 것이며, 예상되는 소수의 경우 게임 플레이 영향은 무시할 수있는 단일 프레임 비주얼 글리치입니다. 나는 당신의 시간이 다른 곳에서 더 잘 소비된다고 말하고 싶습니다.
aaaaaaaaaaaa

0

(Z <0 || W <0)이 아닌 테스트 만 (투영 된 W <0).

일부 클립 공간 공식 ( 기침 OpenGL 기침 )에서 가시 범위는 양수 및 음수 Z 값을 포함하지만 W는 항상 카메라 앞에서 양수이고 음수는 음수입니다.


W <0으로 만 시도했지만 여전히 잘못 투영되는 곳이 있습니다.
Panda Pajama

0
float screenX = (((projectedVector.X / abs(projectedVector.W)) + 1.0f) / 2.0f) * viewportWidth;
float screenY = ((1.0f - (projectedVector.Y / abs(projectedVector.W))) / 2.0f) * viewportHeight;

그리고이 부분을 제거

// Invert X and Y when behind the camera
if (projectedVector.Z < 0 || projectedVector.W < 0)
{
    screenX = -screenX;
    screenY = -screenY;
}

-2

빌보드를 사용해보십시오. 그러면 자동으로 사진이 카메라를 향하게하고 자동으로 적절한 위치의 화면에 사진이 그려집니다


3
질문을 읽었습니까?
Kromster

죄송합니다, 설명하겠습니다-빌보드의 출력을 가져와 스케일링을 제거하고 (2D이지만 3D 위치를 따릅니다) 매트릭스 수학을 사용하여 화면 경계에 유지할 수 있습니다.
Michael Langford

질문은 "이 다음에 대해 구체적이고 화면의 경계에 보관 일부 매트릭스 수학을 사용하여 "
Kromster
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.