Forum

#1 2018-04-02 14:13:57

logna
New member

Reverse perspective

Hi to all, I'm trying to find ways to implement reverse perspective into Maya/Guerilla. Here are a few examples of what i'd like to reproduce:

https://www.youtube.com/watch?v=q3nwdQxriLM
https://vimeo.com/200733239

I've never set foot in anything like this before, do you have any clues if this might be scriptable in python or api even?

I'm unable to find schematics for the rare lens that do exist, so I'm actually unsure on the optical level how to create such an image. I've heard some close to the team may or may not have masters degrees in optics, so I figured I'd try my luck.

To me there are two possibilities:

1. scripting a custom diverging lens.

2. multiple camera views, disposed in a bowl shape (to somewhat reproduce divergent lens) blended together somehow.

Doesn't matter if the result is physically perfect, the point is really to mess with perspective, so aberrations are welcome!

Thanks a bunch!

Offline

 

#2 2018-04-06 04:57:57

Ben
Guerilla dev, the guy to hug

Re: Reverse perspective

Hi logna,

I'm not too sure about the maths for this kind of lens, but if you can get something related to it, you may then write a lens shader smile

This page https://en.wikipedia.org/wiki/Reverse_perspective gives some cues about how to implement that ...


Benjamin 'Ben' Legros
Guerilla developer
http://www.guerillarender.com

Offline

 

#3 2018-04-09 16:09:15

logna
New member

Re: Reverse perspective

Hey Ben, thx for the answer smile


I did a bit of looking around, and there is an add-on for Unity that does this, it's in C# though, so it's taking a little time for me to figure out what it's saying. I'll link it below.


Looking up the rsl language based on my profs advice, I came accross mental ray lens shaders. It seems, based on the description they make, that the rays from the camera may be told to refract so that they converge rather than diverge. What do you think?


http://docs.autodesk.com/MENTALRAY/2014 … de124.html


Hope you find something of interest in here. I'm kind of struggling for the math as well, but I'll update you guys if I get something solid. If ever you know of a site that has good info on optics and that kind of stuff, I'm interested.


Thanks again for checking this out, hope we can get something out of it.


here is the Unity code if you guys wanna check it out:

https://drive.google.com/file/d/1onstUa … sp=sharing








or in straight text:






using UnityEngine;
using System.Collections;

[RequireComponent(typeof(Camera))]
public class RPCamera : MonoBehaviour {

    [Tooltip("objects located here stay the same size on perspective distortion")]
    public Transform pivot = null;

    [Tooltip("zero for parallel projection, negative for reverse perspective")]
    [Range(-10.0f, 10.0f)]
    public float perspective = 0.0f;

    private Camera m_camera;

    private float m_m00;
    private float m_m11;

    void Reset()
    {
        m_camera = GetComponent<Camera>();
        if (!m_camera.orthographic) {
            m_camera.orthographic = true;
        }

        UpdateProjection(true);
    }

    void Start()
    {
        m_camera = GetComponent<Camera>();
        if (!m_camera.orthographic) {
            throw new System.Exception("Camera projection should be orthographic");
        }

        UpdateProjection(true);
    }

    void OnValidate() // to not set projection on each Update
    {
        m_camera = GetComponent<Camera>();

        UpdateProjection(true);
    }

    public void UpdateProjection(bool prepare)
    {
        if (prepare) {
            PrepareProjection();
        }

        float distance = GetCameraDistance();

        Matrix4x4 matrix = GetProjectionMatrix(-perspective * 0.01f, -distance); // convert 'perspective' from percent

        m_camera.projectionMatrix = matrix;
    }

    private float GetCameraDistance() {
        if (pivot != null) {
            return (pivot.position - this.transform.position).magnitude;
        } else {
            return this.transform.position.magnitude;
        }
    }

    private void PrepareProjection()
    {
        m_m00 = 1f / m_camera.orthographicSize / m_camera.aspect;
        m_m11 = 1f / m_camera.orthographicSize;
    }

    private Matrix4x4 GetProjectionMatrix(float p, float d)
    {
        //  sx   0    0      0
        //  0   sy    0      0
        //  0    0   -0.001  p
        //  0    0    p      1 - d*p
        //
        //  X =         sx * x  / (1 + p*(z-d))
        //  Z = (p - 0.001 * z) / (1 + p*(z-d))
        //
        // Here is a discontinuity of projected Z coordinate near p==0
        //  http://www.wolframalpha.com/input/?i=plot+(p+-+0.001*z)%2F(1%2Bp*(z-30))+p%3D-0.5..0.5+z%3D-3..3
        // So Z-buffer may glitch in that place.
        // Workaround is to play with 'perspective' and 'distance' values.

        var m = new Matrix4x4();
        m.m00 =  m_m00;
        m.m11 =  m_m11;
        m.m22 = -0.000001f; m.m23 = p;
        m.m32 =  p;         m.m33 = 1.0f - d * p;

        return m;
    }


    void OnDrawGizmosSelected()
    {
        Matrix4x4 oldGizmosMatrix = Gizmos.matrix;

        Gizmos.matrix = this.transform.localToWorldMatrix;
        Gizmos.color = new Color(0.6f, 0.6f, 0.9f, 0.5f);

        float d = GetCameraDistance();
        float p = perspective * 0.01f;
        float s = m_camera.orthographicSize;
        float n = m_camera.nearClipPlane;
        float f = m_camera.farClipPlane;
        float a = m_camera.aspect;
        float nx = s * (1.0f + p * (n-d));
        float fx = s * (1.0f + p * (f-d));
        var points = new [] {
            new Vector3( nx, nx/a, n),
            new Vector3(-nx, nx/a, n),
            new Vector3(-nx,-nx/a, n),
            new Vector3( nx,-nx/a, n),
            new Vector3( fx, fx/a, f),
            new Vector3(-fx, fx/a, f),
            new Vector3(-fx,-fx/a, f),
            new Vector3( fx,-fx/a, f),
            new Vector3(  s,  s/a, d),
            new Vector3( -s,  s/a, d),
            new Vector3( -s, -s/a, d),
            new Vector3(  s, -s/a, d),
        };
        var lines = new [] {
            0,1, 1,2, 2,3, 3,0,
            0,4, 1,5, 2,6, 3,7,
            4,5, 5,6, 6,7, 7,4,
            8,9, 9,10, 10,11, 11,8,
        };
        for (int i = 0; i < lines.Length; i += 2) {
            Gizmos.DrawLine(points[lines[i]], points[lines[i+1]]);
        }

        Gizmos.matrix = oldGizmosMatrix;
    }
}

Offline

 

#4 2018-04-10 05:43:46

Ben
Guerilla dev, the guy to hug

Re: Reverse perspective

Hi,

Guerilla lens shaders translate the image space (2d coordinates from 0,0 to width,height) into camera space (3d space, centered on the camera position with the z axis pointing forward and x,y axis on the classic image plane.)

The mental ray lens shader seems to change the ray direction, in the case you give, to appear as a fisheye lens.

I think the Unity shader has something of interest here:

//  X =         sx * x  / (1 + p*(z-d))
//  Z = (p - 0.001 * z) / (1 + p*(z-d))

with x (resp. y) and z are in camera space, while X (resp. Y) and Z are in homogeneous space (that is X Y in image space)

I've tried solving for x (the camera space coordinate) with X (the screen space coordinate), this gives:

x = X * (1+p*(z-d)) / sx

The problem now is that x not an affine function of z, which means that it can't be properly raytraced -- that is the reversed perspective is not aligned on straight rays.

I've tried substituting z with Near and Far to obtain the ray start and end points, but that does not really do the trick, we're more or less stuck to a kind of flipped perspective, but not really the intended effect.

Here is my lend shader, just in case:

Code:

void LensRP (
    float Perspective = 1;
    float Distance = 1;
    vector Scale = vector (1,1,1);

    output point P;
    output vector D)
{
    // read the default camera args
    float    Near = renderattr ("Near", 1);
    float    Far = renderattr ("Far", 100000);

    vector    defraster = vector (s, t, 0);

    point    p = transform ("raster", "camera", point (xcomp (defraster), ycomp (defraster), 1));

    float    xNear = (1+Perspective*(Near-Distance)) * p[0] / Scale[0];
    float    yNear = (1+Perspective*(Near-Distance)) * p[1] / Scale[1];

    float    xFar = (1+Perspective*(Far-Distance)) * p[0] / Scale[0];
    float    yFar = (1+Perspective*(Far-Distance)) * p[1] / Scale[1];

    point    pNear = point (xNear, yNear, Near);
    point    pFar = point (xFar, yFar, Far);

    P = pNear;
    D = pFar - pNear;

    //printf ("pNear=%f pFar=%f P=%f D=%f", pNear, pFar, P, D);
}

My 2 cents.

Ben


Benjamin 'Ben' Legros
Guerilla developer
http://www.guerillarender.com

Offline

 

#5 2018-04-10 14:14:10

logna
New member

Re: Reverse perspective

Thanks you so much Ben! I'll look into implementing this.

I'll try to keep updating you all if I get anything smile

Offline

 

Board footer

Powered by PunBB
© Copyright 2002–2008 PunBB