- Home /
Custom camera projection matrix of orthographic camera
I am trying to add reflection to my game. It is in 3d but places the main cameras worldToCameraMatrix in a pixel perfect grid. However when i apply the same technique to try and get a pixel perfect reflection the reflection jumps up and down moving away from the camera.
What is happening is that moving the reflection camera in the grid makes it never lineup because of the 30 degree rotation. Kinda like this if it clarifies:
How do i make it so that the reflection camera share theese four red points dependent on main camera and water plain. Reflection camera near clipping plane is already working.
Answer by abbsimoga · Sep 18, 2021 at 12:13 PM
I solved it by casting rays of the bottom of my screen twords the water and reconstructing the orthographic view after that:
// This code snippet is attatched to the main camera
// Create rays for bottom corners of the camera
Ray bot_right_ray = Camera.main.ViewportPointToRay(new Vector3(1, 0, 0));
Ray bot_left_ray = Camera.main.ViewportPointToRay(new Vector3(0, 0, 0));
// Move camera after main camera
planar_reflection_manager.ConstructMatrix4X4Ortho(bot_right_ray, bot_left_ray, 2f * m_camera.orthographicSize, transform.rotation * Quaternion.Euler(-60f, 0f, 0f));
planar_reflection_manager.SetCameraNearClippingPlane();
planar_reflection_manager script (attatched to the reflection camera):
public void SetCameraNearClippingPlane()
{
Vector4 clipPlaneWorldSpace = new Vector4(0f, 1f, 0f, -Water.water_level);
Vector4 clipPlaneCameraSpace = Matrix4x4.Transpose(Matrix4x4.Inverse(reflection_camera.worldToCameraMatrix)) * clipPlaneWorldSpace;
reflection_camera.projectionMatrix = Camera.main.CalculateObliqueMatrix(clipPlaneCameraSpace);
}
public void ConstructMatrix4X4Ortho(Ray bot_right_ray, Ray bot_left_ray, float camera_orthographic_height, Quaternion camera_rotation)
{
// Construct plane representing the water level
Plane plane = new Plane(Vector3.up, -Water.water_level);
// Assign floats of ray distance for bottom corners
float bot_right_distance;
float bot_left_distance;
// Raycast to plain
plane.Raycast(bot_right_ray, out bot_right_distance);
plane.Raycast(bot_left_ray, out bot_left_distance);
// Get each position of all four camera corners where they hit the water plain
Vector3 top_right_position = bot_right_ray.GetPoint(bot_right_distance);
Vector3 top_left_position = bot_left_ray.GetPoint(bot_left_distance);
// Get sidebar of new camera
Vector3 camera_sidebar_direction = camera_rotation * Vector3.down;
Vector3 camera_sidebar = camera_sidebar_direction * camera_orthographic_height;
// Create the vectors representing bottom corners of our new worldToCameraMatrix.
Vector3 bot_right_position = top_right_position + camera_sidebar;
Vector3 bot_left_position = top_left_position + camera_sidebar;
// Assign that point to the camera position and rotate camera
// Get middle point of our four points
Vector3 middle = (top_right_position + top_left_position + bot_right_position + bot_left_position) * 0.25f;
reflection_camera.transform.position = middle;
reflection_camera.transform.rotation = camera_rotation;
//Matrix4x4 world_to_camera_matrix = Matrix4x4.Ortho(-10, 10, -10, 10, 0, 10); // You could probably create an ortho matrix from theese cords but i do not now how
}
The code should be self explanatory with the comments but ill also leave this OnDrawGizmos code snippet with its representing image.
private void OnDrawGizmos()
{
// Construct plane representing the water level
Plane plane = new Plane(Vector3.up, -Water.water_level);
// Create rays for bottom corners of the camera
Ray bot_right_ray = Camera.main.ViewportPointToRay(new Vector3(1, 0, 0));
Ray bot_left_ray = Camera.main.ViewportPointToRay(new Vector3(0, 0, 0));
// Assign floats of ray distance for bottom corners
float bot_right_distance;
float bot_left_distance;
// Raycast to plain
plane.Raycast(bot_right_ray, out bot_right_distance);
plane.Raycast(bot_left_ray, out bot_left_distance);
// Get each position of all four camera corners where they hit the water plain
Vector3 top_right_position = bot_right_ray.GetPoint(bot_right_distance);
Vector3 top_left_position = bot_left_ray.GetPoint(bot_left_distance);
// Draw red raycasts twords those points
Gizmos.color = Color.red;
Gizmos.DrawRay(bot_right_ray.origin, bot_right_ray.direction * bot_right_distance);
Gizmos.DrawRay(bot_left_ray.origin, bot_left_ray.direction * bot_left_distance);
// Draw a yellow sphere at the hit location
Gizmos.color = Color.yellow;
Gizmos.DrawSphere(top_right_position, 1);
Gizmos.DrawSphere(top_left_position, 1);
// Get height of orthographic camera
float camera_height = 2f * m_camera.orthographicSize;
// Get sidebar of new camera
Vector3 camera_sidebar_direction = transform.rotation * Quaternion.Euler(-60f, 0f, 0f) * Vector3.down;
Vector3 camera_sidebar = camera_sidebar_direction * camera_height;
// Continue drawing magenta raycast that represent the bottom screen edges
Gizmos.color = Color.magenta;
Gizmos.DrawRay(top_right_position, camera_sidebar);
Gizmos.DrawRay(top_left_position, camera_sidebar);
// Create the vectors representing each corner of our new worldToCameraMatrix.
Vector3 bot_right_position = top_right_position + camera_sidebar;
Vector3 bot_left_position = top_left_position + camera_sidebar;
// Draw
Gizmos.color = Color.green;
Gizmos.DrawSphere(bot_right_position, 1);
Gizmos.DrawSphere(bot_left_position, 1);
// Yellow points are now representing the top right and top left corners of our new camera whilst the green points represent bottom right and bottom left corners.
}
Your answer
Follow this Question
Related Questions
How to set ortho projection / model view matrix without a camera? 2 Answers
How to make bullets pass through each other. 1 Answer
Getting CustomPropertyDrawer from SerializedProperty 1 Answer
Object type System.Boolean cannot be converted to target type: System.Int32 ? 0 Answers
Getting all component types (even those not on the scene) 1 Answer