Unity在URP环境下实现PlanarReflection的初级方法。

37 篇文章 3 订阅
36 篇文章 1 订阅

首先是C#脚本:

using System;
using UnityEngine;
using UnityEngine.Rendering;

public class PlanarReflection : MonoBehaviour
{
	[SerializeField]
	Color color = Color.black;
	[SerializeField]
	Texture mainTex;
	[SerializeField]
	Vector2 texTiling = Vector2.one;
	[SerializeField]
	Vector2 texOffset = Vector2.zero;
	[SerializeField]
	[Range(0f, 1f)]
	float reflectionFactor = 0.5f;

	Camera m_MainCamera;
	Camera reflectionCam;

	RenderTexture RT_RenderTarget;

	Material mat;

	void Start()
	{
		RT_RenderTarget = new RenderTexture(Screen.width, Screen.height, 24);
		RT_RenderTarget.antiAliasing = 8;
		RT_RenderTarget.name = "RT_Reflection";

		mat = new Material(Shader.Find("Hidden/PlanarReflection"));
		mat.SetColor("_Color", color);
		if (mainTex) mat.SetTexture("_MainTex", mainTex);
		mat.SetTextureScale("_MainTex", texTiling);
		mat.SetTextureOffset("_MainTex", texOffset);
		mat.SetTexture("_ReflectionTex", RT_RenderTarget);
		mat.SetFloat("_ReflectionFactor", reflectionFactor);
		MeshRenderer render = GetComponent<MeshRenderer>();
		render.material = mat;

		m_MainCamera = Camera.main;

		GameObject objCamReflection = new GameObject("objCamReflection");
		reflectionCam = objCamReflection.AddComponent<Camera>();
		reflectionCam.CopyFrom(m_MainCamera);
		reflectionCam.cameraType = CameraType.Reflection;
		reflectionCam.targetTexture = RT_RenderTarget;
	}

	void OnEnable()
	{
		RenderPipelineManager.beginCameraRendering += OnRenderReflection;
	}

	void OnDisable()
	{
		RenderPipelineManager.beginCameraRendering -= OnRenderReflection;
	}

	void OnDestroy()
	{
		RenderPipelineManager.beginCameraRendering -= OnRenderReflection;
	}

	void OnRenderReflection(ScriptableRenderContext context, Camera camera)
	{
		if (camera.cameraType == CameraType.Reflection) RenderReflection();
	}

	void RenderReflection()
	{
		Vector3 cameraDirectionWorldSpace = m_MainCamera.transform.forward;
		Vector3 cameraUpWorldSpace = m_MainCamera.transform.up;
		Vector3 cameraPositionWorldSpace = m_MainCamera.transform.position;

		Vector3 cameraDirectionPlaneSpace = transform.InverseTransformDirection(cameraDirectionWorldSpace);
		Vector3 cameraUpPlaneSpace = transform.InverseTransformDirection(cameraUpWorldSpace);
		Vector3 cameraPositionPlaneSpace = transform.InverseTransformPoint(cameraPositionWorldSpace);

		cameraDirectionPlaneSpace.y *= -1f;
		cameraUpPlaneSpace.y *= -1f;
		cameraPositionPlaneSpace.y *= -1f;

		cameraDirectionWorldSpace = transform.TransformDirection(cameraDirectionPlaneSpace);
		cameraUpWorldSpace = transform.TransformDirection(cameraUpPlaneSpace);
		cameraPositionWorldSpace = transform.TransformPoint(cameraPositionPlaneSpace);

		reflectionCam.transform.position = cameraPositionWorldSpace;
		reflectionCam.transform.LookAt(cameraPositionWorldSpace + cameraDirectionWorldSpace, cameraUpWorldSpace);

		Vector4 viewPlane = CameraSpacePlane(reflectionCam.worldToCameraMatrix, transform.position, transform.up);
		reflectionCam.projectionMatrix = reflectionCam.CalculateObliqueMatrix(viewPlane);
	}

	Vector4 CameraSpacePlane(Matrix4x4 worldToCameraMatrix, Vector3 pos, Vector3 normal)
	{
		Vector3 viewPos = worldToCameraMatrix.MultiplyPoint3x4(pos);
		Vector3 viewNormal = worldToCameraMatrix.MultiplyVector(normal).normalized;
		float w = -Vector3.Dot(viewPos, viewNormal);
		return new Vector4(viewNormal.x, viewNormal.y, viewNormal.z, w);
	}
}

其次是ShaderGraph:

 其中自定义用到的两个hlsl文件如下:

void GetCrossSampleUVs_float(float4 UV,float2 TexelSize,float OffsetMultiPlier,out float2 UVOriginal,out float2 UVTopRight,out float2 UVBottomLeft,out float2 UVTopLeft,out float2 UVBottomRight)
{
	UVOriginal = UV;
	UVTopRight = UV.xy + float2(TexelSize.x,TexelSize.y) * OffsetMultiPlier;
	UVBottomLeft = UV.xy - float2(TexelSize.x,TexelSize.y) * OffsetMultiPlier;
	UVTopLeft = UV.xy + float2(-TexelSize.x,TexelSize.y) * OffsetMultiPlier;
	UVBottomRight = UV.xy + float2(TexelSize.x,-TexelSize.y) * OffsetMultiPlier;
}
void ColorAverage4_float(float3 color01,float3 color02,float3 color03,float3 color04,out float3 color)
{
	color = (color01 + color02 + color03 + color04) * 0.25;
}

有时候Unity会报类似这种错误:

Screen position out of view frustum (screen pos 2339.000000, 0.000000, 1000.000000) (Camera rect 0 0 2339 1315)

出现这个错误需要满足连个条件,一个是反射摄像机位置在平面上,另一个是反射摄像机与平面平行。由于反射摄像机的参数来源于Camera.main,所以只要让Camera.main的初始位置和朝向不与反射平面位置重叠的同时方向平行就可以了,这个不是个完美的解决方法,但是暂时管用,以后有时间继续研究。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值