- Home /
Can Someone Help Me Figure Out a VR Problem?
Maybe someone can help me as I've searched the internet for many hours and have yet to find any clear method for this that works.
I am trying to make portal rendering work in my current VR project. The portals work similarly to those in the Portal games. When I am playing the game without the VR set on the portals work fine as seen in the image below.
When I try to use VR with the same methods, the rendering ends up looking like the image below (seen from the left eye).
On top of this, the portal renders as though the player is cross-eyed when they are looking at it.
I have tried placing overlapping portals and using a culling mask on the camera to make each eye only see one set of portals, but culling mask seems to not work in OVR cameras for Unity.
Here is the script I am using for placing and rendering the camera:
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
using RenderPipeline = UnityEngine.Rendering.RenderPipelineManager;
public class PortalCamera : MonoBehaviour
{
[SerializeField]
private Portal[] portals = new Portal[2];
[SerializeField]
private Camera portalCamera;
[SerializeField]
private int iterations = 7;
private RenderTexture tempTexture1;
private RenderTexture tempTexture2;
public Camera mainCamera;
private void Awake()
{
tempTexture1 = new RenderTexture(Screen.width, Screen.height, 24, RenderTextureFormat.ARGB32);
tempTexture2 = new RenderTexture(Screen.width, Screen.height, 24, RenderTextureFormat.ARGB32);
}
private void Start()
{
portals[0].Renderer.material.mainTexture = tempTexture1;
portals[1].Renderer.material.mainTexture = tempTexture2;
}
private void OnEnable()
{
RenderPipeline.beginCameraRendering += UpdateCamera;
}
private void OnDisable()
{
RenderPipeline.beginCameraRendering -= UpdateCamera;
}
void UpdateCamera(ScriptableRenderContext SRC, Camera camera)
{
if (!portals[0].IsPlaced || !portals[1].IsPlaced)
{
return;
}
if (portals[0].Renderer.isVisible)
{
portalCamera.targetTexture = tempTexture1;
for (int i = iterations - 1; i >= 0; --i)
{
RenderCamera(portals[0], portals[1], i, SRC);
}
}
if(portals[1].Renderer.isVisible)
{
portalCamera.targetTexture = tempTexture2;
for (int i = iterations - 1; i >= 0; --i)
{
RenderCamera(portals[1], portals[0], i, SRC);
}
}
}
private void RenderCamera(Portal inPortal, Portal outPortal, int iterationID, ScriptableRenderContext SRC)
{
Transform inTransform = inPortal.transform;
Transform outTransform = outPortal.transform;
Transform cameraTransform = portalCamera.transform;
cameraTransform.position = transform.position;
cameraTransform.rotation = transform.rotation;
for(int i = 0; i <= iterationID; ++i)
{
// Position the camera behind the other portal.
Vector3 relativePos = inTransform.InverseTransformPoint(cameraTransform.position);
relativePos = Quaternion.Euler(0.0f, 180.0f, 0.0f) * relativePos;
cameraTransform.position = outTransform.TransformPoint(relativePos);
// Rotate the camera to look through the other portal.
Quaternion relativeRot = Quaternion.Inverse(inTransform.rotation) * cameraTransform.rotation;
relativeRot = Quaternion.Euler(0.0f, 180.0f, 0.0f) * relativeRot;
cameraTransform.rotation = outTransform.rotation * relativeRot;
}
// Set the camera's oblique view frustum.
Plane p = new Plane(-outTransform.forward, outTransform.position);
Vector4 clipPlaneWorldSpace = new Vector4(p.normal.x, p.normal.y, p.normal.z, p.distance);
Vector4 clipPlaneCameraSpace =
Matrix4x4.Transpose(Matrix4x4.Inverse(portalCamera.worldToCameraMatrix)) * clipPlaneWorldSpace;
var newMatrix = mainCamera.CalculateObliqueMatrix(clipPlaneCameraSpace);
portalCamera.projectionMatrix = newMatrix;
// Render the camera to its render target.
UniversalRenderPipeline.RenderSingleCamera(SRC, portalCamera);
}
}
Here is the custom shader I am using:
Shader "Portals/PortalMask"
{
Properties
{
_MainTex("Main Texture", 2D) = "white" {}
}
SubShader
{
Tags
{
"RenderType" = "Opaque"
"Queue" = "Geometry"
"RenderPipeline" = "UniversalPipeline"
}
HLSLINCLUDE
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
ENDHLSL
Pass
{
Name "Mask"
Stencil
{
Ref 1
Pass replace
}
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
struct appdata
{
float4 vertex : POSITION;
};
struct v2f
{
float4 vertex : SV_POSITION;
float4 screenPos : TEXCOORD0;
};
v2f vert(appdata v)
{
v2f o;
o.vertex = TransformObjectToHClip(v.vertex.xyz);
o.screenPos = ComputeScreenPos(o.vertex);
return o;
}
uniform sampler2D _MainTex;
float4 frag(v2f i) : SV_Target
{
float2 uv = i.screenPos.xy / i.screenPos.w;
float4 col = tex2D(_MainTex, uv);
return col;
}
ENDHLSL
}
}
}
If anyone can help me, it would be greatly appreciated. Thanks.
Answer by JeezumsDev · Jan 07 at 01:00 AM
For anyone that might have this problem in the future, I ended up fixing this by changing the script I used for rendering the portals to one similar to the one Sebastian Lague made on YouTube and I went from there. There was another problem I encountered which I discovered was cause by URP. I removed URP from my project and the portals seemed to work fine visually in VR as well as not in VR. I also changed the way I was doing VR by removing the OVR prefabs from the project entirely and using the XR default one.