Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
0
Question by falconfetus8 · Jun 23, 2015 at 02:03 PM · camerarotationrender textureportal

Portal effect using render textures: how should I move the camera?

I'm trying to make a "portal" effect using render textures. I have two quads which are linked to each other and have their own cameras/render textures. My plan was to use some math to make the cameras rotate and shift with the player, but I'm at a loss as to how to do that. The rotation is never quite right no matter what I try.

Here's my code, showing the closest I've come.

 using UnityEngine;
 using System.Collections;
 
 public class PortalBehavior : MonoBehaviour
 {
     private int width = 1000;
     private int height = 1000;
     private int depth = 1;
 
     public PortalBehavior partner;
     public Camera camera;
 
     public RenderTexture texture;
 
     //Events
 
     void Awake()
     {
         texture = new RenderTexture (width, height, depth);
         GetComponent<MeshRenderer> ().material.SetTexture (0, texture);
 
         partner.camera.targetTexture = texture;
     }
 
     void Update ()
     {
         RotateCamera ();
 
         if (Input.GetButtonDown ("Fire1")) {
             GetComponent<MeshRenderer>().enabled = !GetComponent<MeshRenderer>().enabled;
         }
     }
 
     //Misc methods
 
     private void RotateCamera()
     {
         Transform partnerCamera = partner.camera.transform;
         Transform playerCamera = Camera.main.transform;
 
         //Create a reference point
         Vector3 referencePoint = playerCamera.position + playerCamera.forward * 100;
         Vector3 diff = referencePoint - transform.position;
         Vector3 projectedPoint = partner.transform.position + diff;
 
         //Move the partner's camera
         diff = playerCamera.position - transform.position;
         partnerCamera.position = (diff * 0.1f) + partner.transform.position;
 
         //Rotate the partner's camera toward the projected point
         partnerCamera.LookAt (projectedPoint);
     }
 }
 
Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

2 Replies

· Add your reply
  • Sort: 
avatar image
1

Answer by DiegoSLTS · Jun 23, 2015 at 05:00 PM

I did this some weeks ago but the mouse is vertically locked because it was easier to test:

Like you did, each portal has it's own camera, a reference to the other portal and a reference to the player (with the main camera attached).

To set the position of the camera for one portal I first get the player's position but relative to the opposite portal:

 Vector3 pos = oppositePortal.transform.InverseTransformPoint(player.position);

then I set the local position of the camera at the reflected point on x and z:

 cam.transform.localPosition = new Vector3(-pos.x,cam.transform.localPosition.y,-pos.z);

For the rotation I get the angle between the back of the portal and the forward of the player, and set that angle as the "y" local rotation of the camera:

 float angle = SignedAngle(-oppositePortal.transform.forward,player.transform.forward,Vector3.up);
 cam.transform.localRotation = Quaternion.Euler(0f,angle,0f);

My SignedAngle function looks like this:

 float SignedAngle(Vector3 a, Vector3 b, Vector3 n) {
     // angle in [0,180]
     float angle = Vector3.Angle(a,b);
     float sign = Mathf.Sign(Vector3.Dot(n,Vector3.Cross(a, b)));
         
     // angle in [-179,180]
     float signed_angle = angle * sign;
         
     while(signed_angle < 0) signed_angle += 360;
     
     return signed_angle;
 }

This should work to get the renderTexture right, but just setting the render texture wasn't enough to make it look OK, I had to write a custom shader:

 Shader "Custom/TextureCoordinates/PortalView" {
     Properties {
       _MainTex ("Texture", 2D) = "white" {}
     }
     SubShader {
       Tags { "RenderType" = "Opaque" }
       CGPROGRAM
       #pragma surface surf Lambert
       
       struct Input {
           float4 screenPos;
       };
       
       sampler2D _MainTex;
       
       void surf (Input IN, inout SurfaceOutput o) {
           o.Albedo = tex2D (_MainTex, IN.screenPos.xy / IN.screenPos.w).rgb;
       }
       ENDCG
     } 
     Fallback "Diffuse"
 }
Comment
Add comment · Show 4 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image falconfetus8 · Jun 23, 2015 at 07:20 PM 0
Share

Thanks for the help! It didn't work perfectly at first, but after I made a tweak it's flawless. When you're setting the camera's local position, the y value should be set to pos.y. Here's the script, for anyone arriving here from google.

 using UnityEngine;
 using System.Collections;
 
 public class PortalBehavior : $$anonymous$$onoBehaviour
 {
     public PortalBehavior partner;
     public Camera myCamera;
 
     public RenderTexture texture;
 
     //Events
 
     void Awake()
     {
         //Create the render texture
         texture = new RenderTexture (Screen.width, Screen.height, 1);
         GetComponent<$$anonymous$$eshRenderer> ().material.SetTexture (0, texture);
 
         partner.myCamera.targetTexture = texture;
     }
 
     void Update ()
     {
         RotateCamera ();
     }
 
     //$$anonymous$$isc methods
 
     private void RotateCamera()
     {
         Transform playerCam = Camera.main.transform;
         Transform camTrans = myCamera.transform;
         Transform partnerTrans = partner.transform;
 
         //Find the position of the camera
         Vector3 pos = partnerTrans.InverseTransformPoint (playerCam.position);
         camTrans.localPosition = new Vector3 (-pos.x, pos.y, -pos.z);
 
         //Find the rotation
         Vector3 euler = Vector3.zero;
         euler.y = SignedAngle (-partnerTrans.forward, playerCam.forward, Vector3.up);
         //TODO: Find the z-rotation
 
         camTrans.localRotation = Quaternion.Euler (euler);
 
     }
 
     private float SignedAngle(Vector3 a, Vector3 b, Vector3 n) {
         //Code stolen from DiegoSLTS
         //http://answers.unity3d.com/questions/992289/portal-effect-using-render-textures-how-should-i-m.html
 
         // angle in [0,180]
         float angle = Vector3.Angle(a,b);
         float sign = $$anonymous$$athf.Sign(Vector3.Dot(n,Vector3.Cross(a, b)));
         
         // angle in [-179,180]
         float signed_angle = angle * sign;
         
         while(signed_angle < 0) signed_angle += 360;
         
         return signed_angle;
     }
 }
 

Now I'm going to try and make it work without the mouse vertically locked. Got any ideas?

Also, I'm curious. What exactly does your shader do? I'm not familiar with whatever language is used to make shaders.

avatar image DiegoSLTS · Jun 23, 2015 at 08:06 PM 0
Share

Glad it worked, to unlock the vertical movement you probably need to set euler.x to the x rotation of the main camera, or at least that's where I would start working.

If you look at the RenderTexture generated you'll see the camera sees more than the portal area, so this shader changes what portion of the RenderTexture is displayed in the portal quad (the whole texture by default). The shader gets the pixel information of a texture, that texture is the RenderTexture generated (you can set it in the inspector). It's a bit long to explain since you need some knowledge of how the rendering pipeline and shaders work, so I don't think here is the best place to explain all that, but IN.screenPos.xy is the position in viewport space of the vertex that's being processed. The "/ IN.screenPos.w"... I'm not really sure how it works, I've seen it in an example then tryed on my code and worked, but again it's related to how 3D rendering works, with 4x4 matrix where the "w" column has some complex meaning.

For some info about shaders in Unity read this: http://docs.unity3d.com/$$anonymous$$anual/SL-SurfaceShaderExamples.html

avatar image falconfetus8 · Jun 23, 2015 at 10:46 PM 0
Share

There is one problem that I can't seem to fix. The render textures are much darker than the rest of the game, so it makes it a little bit too obvious where the portal is. Is it possible to change the brightness of the texture inside that shader you wrote?

avatar image DiegoSLTS · Jun 24, 2015 at 03:11 PM 0
Share

The texture is what the camera sees, but note that any light will also affect the quad. $$anonymous$$aybe you can disable the lights on the shader replacing:

 #pragma surface surf Lambert

with:

 #pragma surface surf NoLighting

Also you can try setting them to not receive nor cast shadows.

avatar image
1

Answer by falconfetus8 · Jun 23, 2015 at 08:33 PM

Managed to solve it with the help of DiegoSLTS. Here is the full working code. It even works with the mouse vertically unlocked.

 using UnityEngine;
 using System.Collections;
 
 public class PortalBehavior : MonoBehaviour
 {
     public PortalBehavior partner;
     public Camera myCamera;
 
     public RenderTexture texture;
 
     //Events
 
     void Awake()
     {
         //Create the render texture
         texture = new RenderTexture (Screen.width, Screen.height, 1);
         GetComponent<MeshRenderer> ().material.SetTexture (0, texture);
 
         partner.myCamera.targetTexture = texture;
     }
 
     void Update ()
     {
         RotateCamera ();
     }
 
     //Misc methods
 
     private void RotateCamera()
     {
         Transform playerCam = Camera.main.transform;
         Transform camTrans = myCamera.transform;
         Transform partnerTrans = partner.transform;
 
         Vector3 cameraEuler = Vector3.zero;
 
 
         //Find the position of the camera
         Vector3 pos = partnerTrans.InverseTransformPoint (playerCam.position);
         camTrans.localPosition = new Vector3 (-pos.x, pos.y, -pos.z);
 
 
         //Find the x-rotation
         Transform prevParent = playerCam.parent;
         playerCam.SetParent (transform);
 
         cameraEuler.x = playerCam.localEulerAngles.x;
 
         playerCam.SetParent (prevParent);
 
 
         /*Find the y-rotation*/
 
         //Temporarily rotate the player cam so it's flat
         Vector3 oldPlayerRot = playerCam.localEulerAngles;
         playerCam.localRotation = Quaternion.Euler (0, oldPlayerRot.y, oldPlayerRot.z);
 
         //Use DiegoSLTS's method for finding the y-rot.
         cameraEuler.y = SignedAngle (-partnerTrans.forward, playerCam.forward, Vector3.up);
 
         //Restore the player cam
         playerCam.localRotation = Quaternion.Euler (oldPlayerRot);
 
         //Apply the rotation
         camTrans.localRotation = Quaternion.Euler (cameraEuler);
 
     }
 
     private float SignedAngle(Vector3 a, Vector3 b, Vector3 n) {
         //Code stolen from DiegoSLTS
         //http://answers.unity3d.com/questions/992289/portal-effect-using-render-textures-how-should-i-m.html
 
         // angle in [0,180]
         float angle = Vector3.Angle(a,b);
         float sign = Mathf.Sign(Vector3.Dot(n,Vector3.Cross(a, b)));
         
         // angle in [-179,180]
         float signed_angle = angle * sign;
         
         while(signed_angle < 0) signed_angle += 360;
         
         return signed_angle;
     }
 }
Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image BigSquare · Dec 17, 2015 at 03:07 AM 0
Share

This works really excellently. However, I'm having issues using it with the Unity 5 FPS Controller. It's inverting the Y angle of the camera (and possibly the Z angle) but otherwise it's working really well for me. How would I get it so that this angle inversion isn't happening? alt text

screenshot-79.png (298.1 kB)

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

24 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Making Portal-Like Objects 2 Answers

Creating portal camera view with render textur 0 Answers

True Portal Effect 1 Answer

Need help on the 3ds max style camera control 0 Answers

Slowly rotating camera to face same direction as player 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges