/** Creates a perspective projection matrix suitable for 2D and 3D rendering. * * <p>The first 4 parameters define which area of the stage you want to view (the camera * will 'zoom' to exactly this region). The final 3 parameters determine the perspective * in which you're looking at the stage.</p> * * <p>The stage is always on the rectangle that is spawned up between x- and y-axis (with * the given size). All objects that are exactly on that rectangle (z equals zero) will be * rendered in their true size, without any distortion.</p> * * <p>If you pass only the first 4 parameters, the camera will be set up above the center * of the stage, with a field of view of 1.0 rad.</p> */ public static Matrix3D CreatePerspectiveProjectionMatrix( float x, float y, float width, float height, float stageWidth = 0f, float stageHeight = 0f, float[] cameraPos = null) { Matrix3D outMatrix = Matrix3D.Create(); if (stageWidth <= 0) { stageWidth = width; } if (stageHeight <= 0) { stageHeight = height; } if (cameraPos == null) { cameraPos = new[] { stageWidth / 2f, stageHeight / 2f, // -> center of stage stageWidth / (float)Math.Tan(0.5f) * 0.5f }; // -> fieldOfView = 1.0 rad } float focalLength = Math.Abs(cameraPos[2]); float offsetX = cameraPos[0] - stageWidth / 2f; float offsetY = cameraPos[1] - stageHeight / 2f; float far = focalLength * 20f; const float near = 1f; float scaleX = stageWidth / width; float scaleY = stageHeight / height; // set up general perspective float[] sMatrixData = new float[16]; sMatrixData[0] = 2 * focalLength / stageWidth; // 0,0 sMatrixData[5] = -2 * focalLength / stageHeight; // 1,1 [negative to invert y-axis] sMatrixData[10] = far / (far - near); // 2,2 sMatrixData[14] = -far * near / (far - near); // 2,3 sMatrixData[11] = 1; // 3,2 // now zoom in to visible area sMatrixData[0] *= scaleX; sMatrixData[5] *= scaleY; sMatrixData[8] = scaleX - 1 - 2 * scaleX * (x - offsetX) / stageWidth; sMatrixData[9] = -scaleY + 1 + 2 * scaleY * (y - offsetY) / stageHeight; outMatrix.CopyRawDataFrom(sMatrixData); outMatrix.PrependTranslation( -stageWidth / 2.0f - offsetX, -stageHeight / 2.0f - offsetY, focalLength); return(outMatrix); }