Yes, so quick answer. The drawClass is for debugging so it’s not really needed for functionality.

As for the pixelation problem and the extreme angles issue. It’s my understanding (of my own calculations) that this is because of a low crop aspect ratio.

I’ll explain in more detail the process that led to this calculation:

I figured the best way to start was to go with a case that I knew was 100% possible and then build up from there. This case was when the camera is axis aligned to the surface and only goes forward and backwards.

I figured this out by asking myself what would be the literal perfect position for my camera to be such that I didn’t even need to make an adjustment to the viewportframe? The answer to that is the cframe that causes the top and bottom of the surface to perfectly line up with my camera viewport.

This distance “perfect distance” is calculated as:

```
local pDist = window.Size.y/2 / math.tan(math.rad(nCamera.FieldOfView)/2)
```

As for why. It’s all about how cameras use the FOV angle.

Right. So I now knew the ideal distance, but how could I make this work for any distance? Well I could visually see that I just needed to adjust how I scaled the viewport frame to solve for non-perfect distance cases.

So I next calculated the “real distance” of the camera from the surface using the following:

```
local rDist = (camCF.p - surfaceCF.p):Dot(surfaceCF.LookVector)
```

I then found the ratio of the real over the perfect and used that to scale the viewport frame’s y size. This fully handles the case of depth.

The next, thing I asked was: How can I extend this such that I’m not yet rotating, but I am translating my camera? I.e. the rotation is still axis aligned but I can now go up and down and left and right.

Well the key here is to move translate the viewport frame, not the camera. So I converted the camera position to object space and found the scale values it would take to move from the center to the camera point projected on the surface.

```
local p = surfaceCF:PointToObjectSpace(camCF.p)
local s = p / window.Size
vpf.Position = UDim2.new(0.5 - s.x, 0, 0.5 - s.y, 0)
```

That solves for that translation. The last thing is rotation. So far I’d been using the unmodified camera CFrame and that worked perfectly when it was axis-aligned, not so much when it isn’t. At first I was scratching my head, but then I realized something: how I rotate my camera shouldn’t effect what’s through the portal. With that eureka moment I realized I could just calculate and set a CFrame that was in the camera’s position, but axis aligned.

```
nCamera.CFrame = CFrame.new(camCF.p) * (surfaceCF - surfaceCF.p) * CFrame.Angles(0, math.pi, 0)
```

I hope all that makes sense, because now I can talk about the problem, which is this line:

```
vpf.Size = UDim2.new(4, 0, adjust, 0)
```

You see when `adjust < 1`

it seems a number of problems arise. When at extreme angles both `adjust < 1`

and thus the viewport frame is really small and thus doesn’t fit the whole part (similar thing happens with the x-axis with far away frame translations).

Similarity when you’re really close to the surface the `adjust`

value is also small and if you’re not at an extreme angle it may not see like it’s getting squished cause it matches the camera viewport height, but that’s what’s causing the blur.

So I think the solution is to as I mentioned above do some perspective fudgery to make further away parts seem closer (as mentioned in the video). This should allow us to use a higher aspect value.

Idk it’s def a tricky problem hence why I put it down for now.