Skip to content

Instantly share code, notes, and snippets.

@hecomi
Last active February 3, 2019 08:13
Show Gist options
  • Save hecomi/76f9f7094195d054de4ea5220a808f96 to your computer and use it in GitHub Desktop.
Save hecomi/76f9f7094195d054de4ea5220a808f96 to your computer and use it in GitHub Desktop.
A test version of Raymarching.cginc@uRaymarching
inline float DistanceFunction(float3 wpos, RaymarchInfo ray)
{
float3 scenePos = ray.startPos + (ray.sceneDepth - ray.totalLength) * ray.rayDir;
float d1 = Sphere(wpos - scenePos, 0.01);
float d2 = Sphere(wpos - unity_ObjectToWorld._m03_m13_m23, 0.5);
return SmoothMin(d1, d2, 1.0);
}
#ifndef RAYMARCHING_CGINC
#define RAYMARCHING_CGINC
#include "UnityCG.cginc"
#include "./Camera.cginc"
#include "./Utils.cginc"
#ifdef USE_RAYMARCH_INFO_IN_DISTANCE_FUNCTION
#define DISTANCE_FUNCTION_ARGS_DECL float3 pos, RaymarchInfo ray
#define DISTANCE_FUNCTION_ARGS_PASS(pos) pos, ray
#else
#define DISTANCE_FUNCTION_ARGS_DECL float3 pos
#define DISTANCE_FUNCTION_ARGS_PASS(pos) pos
#endif
#ifndef DISTANCE_FUNCTION
inline float _DefaultDistanceFunction(DISTANCE_FUNCTION_ARGS_DECL)
{
return Box(pos, 1.0);
}
#define DISTANCE_FUNCTION _DefaultDistanceFunction
#endif
inline float _DistanceFunction(RaymarchInfo ray)
{
#ifdef WORLD_SPACE
return DISTANCE_FUNCTION(DISTANCE_FUNCTION_ARGS_PASS(ray.endPos));
#else
#ifdef OBJECT_SCALE
return DISTANCE_FUNCTION(DISTANCE_FUNCTION_ARGS_PASS(ToLocal(ray.endPos)));
#else
return DISTANCE_FUNCTION(DISTANCE_FUNCTION_ARGS_PASS(ToLocal(ray.endPos) * GetScale()));
#endif
#endif
}
inline float3 GetDistanceFunctionNormal(RaymarchInfo ray)
{
const float d = 0.0001;
float3 pos = ray.endPos;
float d0 = _DistanceFunction(ray);
ray.endPos = pos + float3( d, 0.0, 0.0);
float dx = _DistanceFunction(ray);
ray.endPos = pos + float3(0.0, d, 0.0);
float dy = _DistanceFunction(ray);
ray.endPos = pos + float3(0.0, 0.0, d);
float dz = _DistanceFunction(ray);
return normalize(float3(dx - d0, dy - d0, dz - d0));
}
inline bool _ShouldRaymarchFinish(RaymarchInfo ray)
{
if (ray.lastDistance < ray.minDistance || ray.totalLength > ray.maxDistance) return true;
#if defined(OBJECT_SHAPE_CUBE) && !defined(FULL_SCREEN)
if (!IsInnerObject(ray.endPos)) return true;
#endif
return false;
}
inline void InitRaymarchFullScreen(out RaymarchInfo ray, float4 projPos)
{
UNITY_INITIALIZE_OUTPUT(RaymarchInfo, ray);
ray.projPos = projPos;
ray.rayDir = GetCameraDirection(projPos);
#if defined(USING_STEREO_MATRICES)
float3 cameraPos = unity_StereoWorldSpaceCameraPos[unity_StereoEyeIndex];
cameraPos += float3(1., 0, 0) * unity_StereoEyeIndex;
#else
float3 cameraPos = _WorldSpaceCameraPos;
#endif
ray.startPos = cameraPos + GetCameraNearClip() * ray.rayDir;
ray.maxDistance = GetCameraFarClip();
}
inline void InitRaymarchObject(out RaymarchInfo ray, float4 projPos, float3 worldPos, float3 worldNormal)
{
UNITY_INITIALIZE_OUTPUT(RaymarchInfo, ray);
ray.projPos = projPos;
ray.rayDir = normalize(worldPos - GetCameraPosition());
ray.startPos = worldPos;
ray.polyNormal = worldNormal;
ray.maxDistance = GetCameraFarClip();
#ifdef CAMERA_INSIDE_OBJECT
float3 startPos = GetCameraPosition() + GetDistanceFromCameraToNearClipPlane(projPos) * ray.rayDir;
if (IsInnerObject(startPos)) {
ray.startPos = startPos;
ray.polyNormal = -ray.rayDir;
}
#endif
}
inline void InitRaymarchParams(inout RaymarchInfo ray, int maxLoop, float minDistance)
{
ray.maxLoop = maxLoop;
ray.minDistance = minDistance;
}
#ifdef USE_CAMERA_DEPTH_TEXTURE
UNITY_DECLARE_DEPTH_TEXTURE(_CameraDepthTexture);
inline void UseCameraDepthTextureForMaxDistance(inout RaymarchInfo ray, float4 projPos)
{
float depth = LinearEyeDepth(SAMPLE_DEPTH_TEXTURE_PROJ(_CameraDepthTexture, UNITY_PROJ_COORD(projPos)));
float dist = depth / dot(ray.rayDir, GetCameraForward());
ray.maxDistance = dist;
}
#endif
#if defined(FULL_SCREEN)
#define INITIALIZE_RAYMARCH_INFO(ray, i, loop, minDistance) \
InitRaymarchFullScreen(ray, i.projPos); \
InitRaymarchParams(ray, loop, minDistance);
#elif defined(USE_CAMERA_DEPTH_TEXTURE)
#define INITIALIZE_RAYMARCH_INFO(ray, i, loop, minDistance) \
InitRaymarchObject(ray, i.projPos, i.worldPos, i.worldNormal); \
InitRaymarchParams(ray, loop, minDistance); \
UseCameraDepthTextureForMaxDistance(ray, i.projPos);
#else
#define INITIALIZE_RAYMARCH_INFO(ray, i, loop, minDistance) \
InitRaymarchObject(ray, i.projPos, i.worldPos, i.worldNormal); \
InitRaymarchParams(ray, loop, minDistance);
#endif
#ifdef USE_DEPTH_TEXTURE_IN_DISTANCE_FUNCTION
UNITY_DECLARE_DEPTH_TEXTURE(_CameraDepthTexture);
#endif
inline bool _Raymarch(inout RaymarchInfo ray)
{
ray.endPos = ray.startPos;
ray.lastDistance = 0.0;
ray.totalLength = length(ray.startPos - GetCameraPosition());
#ifdef USE_DEPTH_TEXTURE_IN_DISTANCE_FUNCTION
ray.sceneDepth = LinearEyeDepth(SAMPLE_DEPTH_TEXTURE_PROJ(_CameraDepthTexture, UNITY_PROJ_COORD(ray.projPos)));
#endif
for (ray.loop = 0; ray.loop < ray.maxLoop; ++ray.loop) {
ray.lastDistance = _DistanceFunction(ray);
ray.totalLength += ray.lastDistance;
ray.endPos += ray.rayDir * ray.lastDistance;
if (_ShouldRaymarchFinish(ray)) break;
}
return ray.lastDistance < ray.minDistance;// && ray.totalLength < ray.maxDistance;
}
void Raymarch(inout RaymarchInfo ray)
{
if (!_Raymarch(ray)) discard;
#ifdef FULL_SCREEN
float3 normal = GetDistanceFunctionNormal(ray);
ray.normal = EncodeNormal(normal);
ray.depth = EncodeDepth(ray.endPos);
return;
#endif
#ifdef CAMERA_INSIDE_OBJECT
if (IsInnerObject(GetCameraPosition()) && ray.totalLength < GetCameraNearClip()) {
ray.normal = EncodeNormal(-ray.rayDir);
ray.depth = EncodeDepth(ray.startPos);
return;
}
#endif
float initLength = length(ray.startPos - GetCameraPosition());
if (ray.totalLength - initLength < ray.minDistance) {
ray.normal = EncodeNormal(ray.polyNormal);
ray.depth = EncodeDepth(ray.startPos) - 1e-6;
} else {
float3 normal = GetDistanceFunctionNormal(ray);
ray.normal = EncodeNormal(normal);
ray.depth = EncodeDepth(ray.endPos);
}
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment