// Builds a tessellated grid of quads across the provided bounds with three sets of UVs used to account for // lens distortion and chromatic aberration. public static Mesh CreateDistortMesh(SteamVR.IHmd hmd, SteamVR.Hmd_Eye eye, int resU, int resV, Rect bounds) { int numVerts = resU * resV; var vertices = new Vector3[numVerts]; var redUVs = new Vector3[numVerts]; var greenUVs = new Vector2[numVerts]; var blueUVs = new Vector2[numVerts]; int iTri = 0; int resUm1 = resU - 1; int resVm1 = resV - 1; var triangles = new int[2 * 3 * resUm1 * resVm1]; for (int iV = 0; iV < resV; iV++) { float v = (float)iV / resVm1; float y = SteamVR_Utils.Lerp(bounds.yMax, bounds.yMin, v); // ComputeDistortion expects 0,0 in upper left for (int iU = 0; iU < resU; iU++) { float u = (float)iU / resUm1; float x = SteamVR_Utils.Lerp(bounds.xMin, bounds.xMax, u); var coords = hmd.ComputeDistortion(eye, u, v); int idx = iV * resU + iU; vertices[idx] = new Vector3(x, y, 0.1f); redUVs[idx] = new Vector3(coords.rfRed[0], 1.0f - coords.rfRed[1], 0); greenUVs[idx] = new Vector2(coords.rfGreen[0], 1.0f - coords.rfGreen[1]); blueUVs[idx] = new Vector2(coords.rfBlue[0], 1.0f - coords.rfBlue[1]); if (iV > 0 && iU > 0) { int a = (iV - 1) * resU + (iU - 1); int b = (iV - 1) * resU + iU; int c = iV * resU + (iU - 1); int d = iV * resU + iU; triangles[iTri++] = a; triangles[iTri++] = b; triangles[iTri++] = d; triangles[iTri++] = a; triangles[iTri++] = d; triangles[iTri++] = c; } } } var mesh = new Mesh(); mesh.vertices = vertices; mesh.normals = redUVs; // stuff data in normals since only two uv sets exposed mesh.uv = greenUVs; mesh.uv2 = blueUVs; mesh.triangles = triangles; return(mesh); }
public void Init(SteamVR_Camera tracker, SteamVR.Hmd_Eye eye, float depth) { this.tracker = tracker; this.eye = eye; var hmd = SteamVR.IHmd.instance; var i = (int)eye; uint x = 0, y = 0, w = 0, h = 0; hmd.GetEyeOutputViewport(eye, ref x, ref y, ref w, ref h); overlaySettings.kernel = new Vector3[] { // AA sub-pixel sampling (2x2 RGSS) new Vector3(0.125f / w, -0.375f / h, 0), new Vector3(0.375f / w, 0.125f / h, 0), new Vector3(-0.125f / w, 0.375f / h, 0), new Vector3(-0.375f / w, -0.125f / h, 0) }; float left = 0.0f, right = 0.0f, top = 0.0f, bottom = 0.0f; hmd.GetProjectionRaw(eye, ref left, ref right, ref top, ref bottom); var camera = GetComponent <Camera>(); float zFar = camera.farClipPlane; float zNear = camera.nearClipPlane; var m = Matrix4x4.identity; float idx = 1.0f / (right - left); float idy = 1.0f / (bottom - top); float idz = 1.0f / (zFar - zNear); float sx = right + left; float sy = bottom + top; m[0, 0] = 2 * idx; m[0, 1] = 0; m[0, 2] = sx * idx; m[0, 3] = 0; m[1, 0] = 0; m[1, 1] = 2 * idy; m[1, 2] = sy * idy; m[1, 3] = 0; m[2, 0] = 0; m[2, 1] = 0; m[2, 2] = -zFar * idz; m[2, 3] = -zFar * zNear * idz; m[3, 0] = 0; m[3, 1] = 0; m[3, 2] = -1.0f; m[3, 3] = 0; camera.projectionMatrix = m; camera.depth = depth; // enforce rendering order camera.eventMask = 0; // disable mouse events camera.orthographic = false; // force perspective camera.aspect = (float)w / h; // Use fov of projection matrix (which is grown to account for non-linear undistort) camera.fieldOfView = (Mathf.Atan(bottom) - Mathf.Atan(top)) * Mathf.Rad2Deg; // Copy and clear clearFlags to avoid duplicate work. if ((int)clearFlags == 0) { clearFlags = camera.clearFlags; camera.clearFlags = CameraClearFlags.Nothing; } camera.targetTexture = SteamVR_Camera.sceneTexture; overlaySettings.invProj = m.inverse; transform.parent = tracker.offset; transform.localScale = Vector3.one; var t = new SteamVR_Utils.RigidTransform(hmd.GetHeadFromEyePose(eye)); transform.localPosition = t.pos; transform.localRotation = t.rot; if (distortMesh[i] == null) { var viewportWidth = SteamVR_Camera.viewportTexture.width; var viewportHeight = SteamVR_Camera.viewportTexture.height; var eyeViewport = new Rect( 2.0f * x / viewportWidth - 1.0f, 2.0f * y / viewportHeight - 1.0f, 2.0f * w / viewportWidth, 2.0f * h / viewportHeight); distortMesh[i] = SteamVR_Utils.CreateDistortMesh(hmd, eye, 32, 32, eyeViewport); } }