Instantly share code, notes, and snippets.

Embed
What would you like to do?
Behaviour that modifies a renderers position during the render process to prevent it being culled
using UnityEngine;
using System.Collections;
[ExecuteInEditMode]
[RequireComponent(typeof(MeshRenderer))]
public class RefractedBounds : MonoBehaviour {
MeshRenderer renderer;
void OnEnable() {
renderer = GetComponent<MeshRenderer>();
Camera.onPreCull -= OnCameraPreCull;
Camera.onPreRender -= OnCameraPreRender;
Camera.onPreCull += OnCameraPreCull;
Camera.onPreRender += OnCameraPreRender;
}
void OnDisable() {
Camera.onPreCull -= OnCameraPreCull;
Camera.onPreRender -= OnCameraPreRender;
}
Vector3 positionBeforeOnPreCull;
void OnCameraPreCull(Camera camera) {
Vector4 surface = renderer.sharedMaterial.GetVector("_Surface");
float refraction = renderer.sharedMaterial.GetFloat("_RefractiveIndex");
positionBeforeOnPreCull = transform.position;
transform.position = Refract(transform.position, camera.transform.position, surface, 1 / refraction, Vector3.zero);
}
void OnCameraPreRender(Camera camera) {
transform.position = positionBeforeOnPreCull;
}
void OnWillRenderObject() {
transform.position = positionBeforeOnPreCull;
}
bool IsBelowSurface(Vector3 position, Vector4 surface) {
Vector3 surfaceNorm = new Vector3(surface.x, surface.y, surface.z);
return Vector3.Dot(position - surfaceNorm * surface.w, surfaceNorm) < 0;
}
Vector3 Refract(Vector3 position, Vector3 viewerPosition, Vector4 surface, float refractionIndex, Vector3 surfaceNormalOffset) {
//ray end is the vertex's undistorted position
Vector3 vertexPosition = position;
//get the vector from the camera to the vertex
Vector3 worldRay = vertexPosition - viewerPosition;
//normalize it for direction
Vector3 worldRayDir = worldRay.normalized;
//surface is a vector4 that defines a plane
Vector3 worldPlaneNormal = new Vector3(surface.x, surface.y, surface.z);
//define a known position on the plane
Vector3 worldPlaneOrigin = worldPlaneNormal * surface.w;
//get the vector result of the worldRay entering the water
Vector3 refraction = Refract(worldRayDir, (worldPlaneNormal + surfaceNormalOffset).normalized, refractionIndex);
//raycast from the vertex, backwards along the refraction vector
float denom = Vector3.Dot(-worldPlaneNormal, -refraction);
Vector3 p010 = worldPlaneOrigin - vertexPosition;
float t = Vector3.Dot(p010, -worldPlaneNormal) / denom;
Vector3 intersection = vertexPosition + refraction * -t;
//get the vector from the camera to the intersection, this is the perceived position
Vector3 originToIntersection = intersection - viewerPosition;
//starting from the camera, move the vector along the perceived position vector by the original ray length
return viewerPosition + originToIntersection.normalized * worldRay.magnitude;
}
Vector3 Refract(Vector3 inDir, Vector3 surface, float indexOfRefraction){
float c1 = -Vector3.Dot(surface, inDir);
float c2 = Mathf.Sqrt(1 - indexOfRefraction * indexOfRefraction * (1 - c1 * c1));
Vector3 result;
result.x = (indexOfRefraction * inDir.x) + (indexOfRefraction * c1 - c2) * surface.x;
result.y = (indexOfRefraction * inDir.y) + (indexOfRefraction * c1 - c2) * surface.y;
result.z = (indexOfRefraction * inDir.z) + (indexOfRefraction * c1 - c2) * surface.z;
return result;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment