Planar reflection clipping problem

Hello. Can someone tell me the possible cause of the problem seen in the video and how I can get rid of it?

1 Like

Looks like your not setting the camera clip plane to cut at the water level , this would give you artifacts like this.

1 Like

Thank you. I tried to do this by reviewing the article here, but I was unsuccessful.

I used to use DX9 based Acknex engine. I am unfamiliar with DX11. I was using a method like below to overcome this issue in Acknex:

//RENDER EVENT
function render_event()
{
	terrain_material.skill1 = floatv(render_view.portal_z);
	terrain_material.skill2 = floatv(render_view.pnormal_z);

	//if the material is rendered by the reflection camera
	if(render_view==view_reflection)
	{
		terrain_material.skill3 = 1;
	}
	else
	{	
		terrain_material.skill3 = 0;
	}
}
MATERIAL* terrain_material =
{

	flags=ENABLE_TREE ;
	event=render_event;
	effect="terrain.fx";
}


//////////////////////////////
// HLSL terrain.fx
//////////////////////////////
//vertex shader
float4 PosWorld = mul(inPos, matWorld); 

//if the material is rendered by the reflection camera
if(skill3 == 1.0)
{
	Out.Tex1.z = (PosWorld.y-skill1)*skill2;
	//Out.Tex1.z=(WorldPosition-render_view.portal_z)*render_view.pnormal_z;
}

//pixel shader
clip(In.Tex1.z);

In the example: When the terrain was rendered by the reflection camera, the plane was clipped with the clip function in the hlsl of the terrain.

In Flax, on the other hand, I don’t know how to check if a material is rendered by a specific camera. Is there a way to do this? Or maybe this method is useless for DX11? Do I need to use a completely different method?

I’ve tried a lot of things since yesterday, but I guess the real problem is that I don’t know what method to follow. I would be glad if someone could guide me.

Well I think I’ve made some progress.

Now all I need is to be able to check if the object is rendered by a specific (planar) camera and clip it only when rendering by that.

As far as i understand, Unity has the OnWillRenderObject() function for that. Is there a similar function in Flax?

1 Like

There is no OnWillRenderObject equivalent and culling data is internal to renderer.

So there is no solution to this problem?

You could manually perform Frustum Culling fro the planar camera viewpoint (Camera.Frustum).

1 Like

I think achieving that is beyond my abilities. I don’t even know how to adapt the Unity codes I found to Flax. CalculateObliqueMatrix etc… Thanks anyway.

1 Like

Hello again. I found an example on the Flax Discord channel and at this link. It’s supposed to clip everything below the water. I am trying to use it with OnPreRender but no success. Can anyone tell me what’s wrong/missing with this code:

using System;
using FlaxEngine;

namespace Game
{
	public class Planar : Script
	{
			
		public override void OnEnable()
		{
			..............
			_task.PreRender += OnPreRender;
			...............	
		}
		private static float sgn(float a)
		{
			if (a > 0.0f) return 1.0f;
			if (a < 0.0f) return -1.0f;
			return 0.0f;
		}

		static Vector4 CameraSpacePlane(Camera cam, Vector3 pos, Vector3 normal, float sideSign)
		{
			var renderView = new RenderView();
			renderView.CopyFrom(cam);

			Vector3 offsetPos = pos + normal * 0.07f;
			Matrix m = renderView.View;

			Vector3 point = MultiplyPoint(m,new Vector3(0.0f, 0.0f, 0.0f)).Negative; //(inverse?)
			Vector3 cpos = MultiplyPoint(m, offsetPos);
			cpos -= new Vector3(0.0f, point.Y, 0.0f);

			Vector3 cnormal = MultiplyVector(m, normal).Normalized * sideSign;
			return new Vector4(cnormal.X, cnormal.Y, cnormal.Z, -Vector3.Dot(cpos, cnormal));
		}
		public static Vector3 MultiplyPoint(Matrix matr, Vector3 point)
		{
			Vector3 res;
			float w;
			res.X = matr.M11 * point.X + matr.M12 * point.Y + matr.M13 * point.Z + matr.M14;
			res.Y = matr.M21 * point.X + matr.M22 * point.Y + matr.M23 * point.Z + matr.M24;
			res.Z = matr.M31 * point.X + matr.M32 * point.Y + matr.M33 * point.Z + matr.M34;
			w = matr.M41 * point.X + matr.M42 * point.Y + matr.M43 * point.Z + matr.M44;

			w = 1F / w;
			res.X *= w;
			res.Y *= w;
			res.Z *= w;
			return res;
		}
		public static Vector3 MultiplyVector(Matrix matr, Vector3 vector)
		{
			Vector3 res;
			res.X = matr.M11 * vector.X + matr.M12 * vector.Y + matr.M13 * vector.Z;
			res.Y = matr.M21 * vector.X + matr.M22 * vector.Y + matr.M23 * vector.Z;
			res.Z = matr.M31 * vector.X + matr.M32 * vector.Y + matr.M33 * vector.Z;
			return res;
		}

		static void CalculateObliqueMatrix(ref Matrix projection, Vector4 clipPlane)
		{
			Vector4 q = Vector4.Transform(new Vector4(
			sgn(clipPlane.X),
			sgn(clipPlane.Y),
			1.0f,
			1.0f
			), Matrix.Invert(projection));
			Vector4 c = clipPlane * (2.0f / (Vector4.Dot(clipPlane, q)));
			// third row = clip plane - fourth row
			projection[2] = c.X - projection[3];
			projection[6] = c.Y - projection[7];
			projection[10] = c.Z - projection[11];
			projection[14] = c.W - projection[15];
		}

		private void OnPreRender(GPUContext context, ref RenderContext renderContext)
		{
			Matrix view = _task.View.View;
			Matrix proj = _task.View.Projection;
			Vector4 clipPlaneCameraSpace = CameraSpacePlane(_task.Camera, Actor.Position, Actor.Transform.Up, 1.0f);
			CalculateObliqueMatrix(ref proj, clipPlaneCameraSpace);
			renderContext.View.SetUp(ref view, ref proj);
		}

	}
}
1 Like