DirectX と OpenGL には異なるカメラ規則があります。
ビューポート 2.0 は、カメラのプロジェクションの行列を設定するときに右手の座標系を使用することで、Maya の他の部分との一貫性を維持しています。ただし、ニア クリップ プレーンとファー クリップ プレーンは Z の[0,1]範囲にマッピングされます。
そのため、
kViewDirection (方向)、kViewUp (上)、kViewRight (右)列挙型を MFrameContext::getTuple()メソッドに渡すことで、ワールド空間のカメラ ベクトルを照会することができます。これらの 3 つのベクトルは、右手の座標系の基礎を形成します。
また、MDrawContext はアクティブ カメラへのアクセスを提供します。MFnCamera インタフェースを介してそのプロパティを照会すると、同じ一貫したカメラ ベクトル値を照会することができます。オブジェクト空間のベクトルが返された場合、値は Z- ビュー方向の一貫した右手の座標系を示します。
次のような照会に使用できるいくつかの便利なメソッドがあります。
旧式の既定ビューポート(ビューポート 1)では、アクティブ カメラがカメラ セットに属する場合に、OpenGL で追加クリップ プレーンを直接設定することができました。
ビューポート 2.0 では、固定機能のユーザ クリップ プレーンが特定の描画 API で使用できない可能性があるため、デバイスを直接照会することはお勧めできません。そのため、ビューポート 1 の動作はビューポート 2.0 では既定で無効にされていますが、OpenGL (ENABLE_DEFAULT_VIEWPORT_CAMERA_SETS)の実行時に必要な場合には環境変数を介してアクセスできます。
ワールド空間のクリップ プレーンを取得するための、描画 API に依存しないオプションを以下に示します。カメラは MDrawContext から取得しますが、すべてのカメラ シェイプにできます。クリップ プレーンを照会するための正規化されていないメソッドの使用に注目してください。
MDrawContext context; // Get the current camera from the context MFnCamera activeCamera(context.getCurrentCameraPath()); // Get relative near and far clip values with respect to the camera position // You should ignore any override values set when using a // camera set; therefore, do not use the nearClippingPlane() and farClippingPlane() // methods on MFnCamera. double nearD = activeCamera.unnormalizedNearClippingPlane(); double farD = activeCamera.unnormalizedFarClippingPlane(); // Get world space camera information MPoint eyePoint = activeCamera.eyePoint(MSpace::kWorld); MVector viewDirection = activeCamera.viewDirection(MSpace::kWorld); // Positive value double dist = eyePoint[0]*viewDirection[0] + eyePoint[1]*viewDirection[1] + eyePoint[2]*viewDirection[2]; // Compute near clip plane facing away from the camera direction (for OpenGL) double distNear = -1.0 * (dist + nearD); MVector OpenGL_NearClipPlaneVector( viewDirection[0], viewDirection[1], viewDirection[2], distNear); // Compute far clip plane facing towards the camera direction (for OpenGL) double distFar = dist + farD; MVector OpenGL_FarClipPlaneVector( -viewDirection[0], -viewDirection[1], -viewDirection[2], distFar);
MDrawContext のみを使用する場合の同等のコードは次のようになります。
// Query the camera coordinate system MDoubleArray vPos = context.getTuple(MHWRender::MFrameContext::kViewPosition); MDoubleArray vDir = context.getTuple(MHWRender::MFrameContext::kViewDirection); MDoubleArray vNear = context.getTuple(MHWRender::MFrameContext::kViewUnnormlizedNearClipValue); MDoubleArray vFar = context.getTuple(MHWRender::MFrameContext::kViewUnnormalizedFarClipValue); // Compute the world space planes for the near and far clip planes // The near plane is pointing away from the camera and is thus pointing in the // negative direction, while the far plane is pointing towards the camera (positive // direction. double distW = vPos[0]*vDir[0] + vPos[1]*vDir[1] + vPos[2]*vDir[2]; // Near clip plane faces away from the camera double distNearW = -1.0 * (distW + vNear[0]); MVector OpenGL_NearPlane(vDir[0], vDir[1], vDir[2], distNearW); // Far clip plane faces torwards the camera double distFarW = distW + vFar[0]; MVector OpenGL_NearPlane(-vDir[0], -vDir[1], -vDir[2], distFarW);
シェーダは、ビュー方向に沿ったジオメトリの位置をオフセットするために深度の優先順位を使用できます。シェーダ コード内での計算は、実際のデバイスの深度範囲に関連するため、OpenGL と DirectX で異なります。depthPriority と呼ばれるユニフォーム パラメータが適切に設定されている場合は、次のサンプル コードが DirectX と OpenGL でのオフセットを実行します。
// DX range is [0,1] or 1 in size. float4 iPcPriority( float3 pm, float depthPriority, float4x4 worldViewProjectionC ) { float4 P = mul( float4(pm,1), worldViewProjectionC ); P.z -= P.w * depthPriority; return P; } // OpenGL range is [-1,1] or 2 in size vec4 iPcPriority( vec3 pm, float depthPriority, mat4 worldViewProjectionC ) { vec4 P = worldViewProjectionC * vec4(pm,1.0f); P.z -= P.w * 2.0 * depthPriority; return P; }
(ジオメトリ シェーダを使用して生成された)太い線およびポイント、またはスクリーン位置合わせジオメトリでは、反時計回りの巻上げ方向が前に向いたジオメトリを示すことに注目してください。これは DirectX と OpenGL の両方で一貫しています。
たとえば、次の DirectX コードでは、4 つの点は次のように定義されます。
static const float4 cQuadPts[4] = { float4( -1.0, 1.0, 0, 0 ), float4( -1.0, -1.0, 0, 0 ), float4( 1.0, 1.0, 0, 0 ), float4( 1.0, -1.0, 0, 0 )};
ジオメトリ シェーダの展開が先に進む順序でポイントを横切り、それぞれが反時計回りの方向を持つ三角形を備えた三角ストリップが作成されます。
void point2ScreenQuad( geometryInS inputs[1], float2 pointSz, float2 screenSize, float4x4 viewProjInverse, float depthPriorityUnit, bool orthographic, float DPThresholdInView, inout TriangleStream<geometryInS> outStream ) { geometryInS outS = inputs[0]; float size = max(0, max(pointSz.x, pointSz.y)); float dpScale = orthographic ? 1.0f : -DPThresholdInView; float dp = 2.0f * size * cDepthPriorityUnit * dpScale; float4 sizeInZ = float4(pointSz.xy / screenSize.xy, 0, 0) * outS.Pc.w; [unroll] for( int i = 0; i < 4; ++i ) { outS.Pc = inputs[0].Pc + sizeInZ * cQuadPts[i]; outS.Pc.z = inputs[0].Pc.z - dp; outStream.Append( outS ); } outStream.RestartStrip(); }
フラグメントは、次のいずれかの方法を使用して検討することができます。