How to render just part of a cam's view, to the full screen?

How would I render just 2/3 of the width/height of the camera’s view,–the bottom-right 2/3–but have that fill the screen?

My goal is to have the vanishing point of the rendered perspective be off center, shifted toward the top left. So that, for instance, HUD stuff can overlay the bottom and right portions, leaving the vanishing point properly centered in the remaining open screen.

A custom camera projection matrix sounds like the answer, but I can’t figure it out.

I first attempted to do this using the translation ability of Matrix4x4.TRS (see below) but that actually translates the whole camera, it doesn’t shift the rendered view. And so the vanishing point (the one place that objects have no fish-eye distortion) stays at dead center of the screen.

camera.projectionMatrix = camera.projectionMatrix * Matrix4x4.TRS( Vector3(HOffset,VOffset,0) , Quaternion.identity , Vector3.one );

That doesn’t work.

Can this be done? I’m not much of a Matrix4x4 whiz!

(Question inspired by this thread.)

You’re on the right track - it DOES involve modifying the projection matrix.

Have you tried simply swapping the order you’re mulitplying stuff?

Here is a script that constructs an off-center projection matrix directly. Attach it to the camera and tweak left/right/top/bottom values.

// This defines near plane size, that is how offset are
// corners of camera's near plane. Tweak values in play
// mode and you can see camera's frustum change.

var left = -0.2;
var right = 0.2;
var top = 0.2;
var bottom = -0.2;

function LateUpdate()
{
    var cam = camera;
    var m = PerspectiveOffCenter(
        left, right, bottom, top,
        cam.nearClipPlane, cam.farClipPlane );
    cam.projectionMatrix = m;
}

static function PerspectiveOffCenter(
    left : float, right : float,
    bottom : float, top : float,
    near : float, far : float ) : Matrix4x4
{        
    var x =  (2.0 * near)       / (right - left);
    var y =  (2.0 * near)       / (top - bottom);
    var a =  (right + left)     / (right - left);
    var b =  (top + bottom)     / (top - bottom);
    var c = -(far + near)       / (far - near);
    var d = -(2.0 * far * near) / (far - near);
    var e = -1.0;

    var m : Matrix4x4;
    m[0,0] =   x;  m[0,1] = 0.0;  m[0,2] = a;   m[0,3] = 0.0;
    m[1,0] = 0.0;  m[1,1] =   y;  m[1,2] = b;   m[1,3] = 0.0;
    m[2,0] = 0.0;  m[2,1] = 0.0;  m[2,2] = c;   m[2,3] =   d;
    m[3,0] = 0.0;  m[3,1] = 0.0;  m[3,2] = e;   m[3,3] = 0.0;
    return m;
}

Thanks! I’ll come back and post a sample in a day or so.

I don’t know how people can even READ my questions as fast as they do around here, much less ANSWER them :shock:

(I’m not sure I fully grasp the variables. I always seem to end up with a really wide FOV and distorted aspect ratio. What values would I enter to make a standard unmodified view? I tried all 0s and all 1s.)

EDIT: The distorted aspect seems to go away if I use a square render window–which it just so happens I planned to do anyway. But for future reference, can this be made to work with screens of unknown aspect, such as if someone sends a WebPlayer to full-screen?

You’ll have to adjust the values to match screen aspect so that (right-left)/(top-bottom) matches screen aspect.

The values just define the near plane. If right-left == top-bottom, then near plane is square in the world (it’s easy to see that in scene view where it draws camera’s frustum). Now, if you put that square on a non-square window, then obviously everything is stretched.

I see–a little extra scripting will take care of that.

A sample is underway. I’m using this now to render an object with a shadow, in such a way that the object and shadow fill the view fully, with the vanishing point offset so the object is undistorted. Works great!

OK, here’s an example of this in action (kind of going for an Apple-esque glossy-floor look):
http://adamsi.com/3dfurniture.html

The chair is (more or less) centered on the screen–and its perspective is undistorted because it’s right on the vanishing point. But the surrounding Unity viewport is intentionally NOT centered, so that there can be a shadow on the right, yet leave room for HTML text on the left.

Just 324k. Who needs QTVR? :slight_smile:

(One odd thing: every now and then when I load the page, the Unity portion renders upside down!)

Hey Morgan,

Im pretty sure it started upside down for me…although I was fiddling with other windows while it loaded in the backround. Looks nice.

733mhtz/ Radeon9800pro(128mb)

AC

OK - I think I fixed the upside down thing, which would result when moving the mouse REALLY fast during loading. Unity seems to sometimes start off with crazy mouse input on the first frame (I’ve noticed it in other games). Maybe it’s reporting a mouse movement you did during the load screen? Whatever the cause, I THINK it helps that I programmed mouse input to be ignored until .1 seconds have passed since the game loaded.

I also fixed fullscreen mode. The game now compensates for aspect ratio automatically (locking the vertical FOV as usual), with the following tweaks to the above script, defining left1 and right1 initially, and then calculating the actual current left and right values on the fly:

var left1 = -0.2; 
var right1 = 0.2; 
var top = 0.2; 
var bottom = -0.2;

function LateUpdate() 
{ 
	//Added to compensate for aspect ratio; assumed left1/right1/top/bottom are set to be square:
	left = left1 * camera.aspect;
	right = right1 * camera.aspect;

Updated: ignoring early mouse input didn’t fix that problem totally. I ended up clamping the mouse axes to ±3. We’ll see if that helps. I can’t get the cam to spin upside down anymore. Knock on wood.

That’s really nice Morgan. How did you do the two shadows? Is the floor reflection a reflective shader or a duplicate model? Again, very nice use of what Unity can do!

Thanks. It’s all done with Pro render-to-texture, using Aras’ shadow and reflection packages found on the Unify Wiki. (Which are quite simple to use.)

Shadow:
http://www.unifycommunity.com/wiki/index.php?title=Character_Shadow

Reflection:
http://www.unifycommunity.com/wiki/index.php?title=MirrorReflection
(I thought of a dupe model, and I still may do that since it would reflect on some lower-end GPUs that don’t support RTT, and would look better full-screen without needing a giant render texture.)

And to keep the viewport small without having the reflection get cut off at the bottom, I applied an Apple-style gradient fade. It’s simply a GUI texture. When you’re looking from above it’s irrelevant, but the rest of the time it keeps the bottom edge from being distracting.

I’m going to jazz it up with some browser communication next, as a demo of a store page.

Dabbling in furniture design was fun, but I won’t quit my day job :slight_smile:

that’s a pretty cool approach for presentation, morgan. looks good and the vanishing point trick will come in handy. thanks aras! wikiwikiwiki… :slight_smile:

Thanks, I had forgotten that you’ve got Pro now. Very nicely done!

Sorry to awake this thread from the dead, but Aras, is it possible to convert the FOV or whatever else of a camera to get that near plane size?

I’m not sure I’d count on Aras seeing this thread :wink: But, I’m sure someone else can answer your question.

I only skimmed the thread, but are you asking how to get the width and height of the frustum at the near plane given a field of view, aspect ratio, and near plane distance?

In general, it’s fairly straightforward to compute certain camera/frustum parameters from other camera/frustum parameters if needed; if you can specify exactly what conversion you want to perform, someone should be able to point you in the right direction.