diff --git a/Assets/pen/Pen.unity b/Assets/pen/Pen.unity index 8b29eef..26e65cd 100644 --- a/Assets/pen/Pen.unity +++ b/Assets/pen/Pen.unity @@ -246,7 +246,7 @@ TrailRenderer: textureMode: 0 shadowBias: 0.5 generateLightingData: 0 - m_MinVertexDistance: 0.001 + m_MinVertexDistance: 0.003 m_Autodestruct: 0 m_Emitting: 0 --- !u!1 &217324300 diff --git a/Assets/raymarched/Interactive.meta b/Assets/raymarched/Interactive.meta new file mode 100644 index 0000000..8d86b8e --- /dev/null +++ b/Assets/raymarched/Interactive.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6417ef9aa4572bf43b276704a8d3b794 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/raymarched/Interactive/Raymarch_multi.mat b/Assets/raymarched/Interactive/Raymarch_multi.mat new file mode 100644 index 0000000..7491234 --- /dev/null +++ b/Assets/raymarched/Interactive/Raymarch_multi.mat @@ -0,0 +1,81 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 6 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Raymarch_multi + m_Shader: {fileID: 4800000, guid: d9b470f9858f75d04aa12fe1b15b6ccb, type: 3} + m_ShaderKeywords: + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 0.5 + - _GlossyReflections: 1 + - _MaxDist: 100 + - _MaxSteps: 256 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _SurfDist: 0.001 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 1, g: 1, b: 1, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + - _ObjectA: {r: -0.07, g: 0, b: 0, a: 1} diff --git a/Assets/raymarched/Interactive/Raymarch_multi.mat.meta b/Assets/raymarched/Interactive/Raymarch_multi.mat.meta new file mode 100644 index 0000000..9025667 --- /dev/null +++ b/Assets/raymarched/Interactive/Raymarch_multi.mat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 035a99d20f5635cd7a7cbba57b7068bc +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/raymarched/Raymarch_origin.mat b/Assets/raymarched/Interactive/Raymarch_origin.mat similarity index 100% rename from Assets/raymarched/Raymarch_origin.mat rename to Assets/raymarched/Interactive/Raymarch_origin.mat diff --git a/Assets/raymarched/Raymarch_origin.mat.meta b/Assets/raymarched/Interactive/Raymarch_origin.mat.meta similarity index 100% rename from Assets/raymarched/Raymarch_origin.mat.meta rename to Assets/raymarched/Interactive/Raymarch_origin.mat.meta diff --git a/Assets/raymarched/Raymarch_secondary.mat b/Assets/raymarched/Interactive/Raymarch_secondary.mat similarity index 98% rename from Assets/raymarched/Raymarch_secondary.mat rename to Assets/raymarched/Interactive/Raymarch_secondary.mat index 1f52bc5..8dbb8ae 100644 --- a/Assets/raymarched/Raymarch_secondary.mat +++ b/Assets/raymarched/Interactive/Raymarch_secondary.mat @@ -13,7 +13,7 @@ Material: m_LightmapFlags: 4 m_EnableInstancingVariants: 0 m_DoubleSidedGI: 0 - m_CustomRenderQueue: -1 + m_CustomRenderQueue: 3000 stringTagMap: {} disabledShaderPasses: [] m_SavedProperties: diff --git a/Assets/raymarched/Raymarch_secondary.mat.meta b/Assets/raymarched/Interactive/Raymarch_secondary.mat.meta similarity index 100% rename from Assets/raymarched/Raymarch_secondary.mat.meta rename to Assets/raymarched/Interactive/Raymarch_secondary.mat.meta diff --git a/Assets/raymarched/raymarch_origin.shader b/Assets/raymarched/Interactive/raymarch_origin.shader similarity index 100% rename from Assets/raymarched/raymarch_origin.shader rename to Assets/raymarched/Interactive/raymarch_origin.shader diff --git a/Assets/raymarched/raymarch_origin.shader.meta b/Assets/raymarched/Interactive/raymarch_origin.shader.meta similarity index 100% rename from Assets/raymarched/raymarch_origin.shader.meta rename to Assets/raymarched/Interactive/raymarch_origin.shader.meta diff --git a/Assets/raymarched/raymarch_secondary.shader b/Assets/raymarched/Interactive/raymarch_secondary.shader similarity index 100% rename from Assets/raymarched/raymarch_secondary.shader rename to Assets/raymarched/Interactive/raymarch_secondary.shader diff --git a/Assets/raymarched/raymarch_secondary.shader.meta b/Assets/raymarched/Interactive/raymarch_secondary.shader.meta similarity index 100% rename from Assets/raymarched/raymarch_secondary.shader.meta rename to Assets/raymarched/Interactive/raymarch_secondary.shader.meta diff --git a/Assets/raymarched/raymarcher.cginc b/Assets/raymarched/Interactive/raymarcher.cginc similarity index 94% rename from Assets/raymarched/raymarcher.cginc rename to Assets/raymarched/Interactive/raymarcher.cginc index 08201b6..dc6776f 100644 --- a/Assets/raymarched/raymarcher.cginc +++ b/Assets/raymarched/Interactive/raymarcher.cginc @@ -171,14 +171,18 @@ fragOut frag (v2f i) { // col.rgb = max(dot(n, normalize(float3(1,0.5,1))), 0.05f); - col.rgb = lerp(0, float3(0,1,1), pow(1 - dot(-rd, n), 2)); + col.rgb = lerp(0, float3(0,1,1), pow(1 - dot(-rd, n), 3)); // col *= float4(d, 1, 1, 1); fragOut o; o.col = col; // o.col = _LightColor0; float4 vClipPos = mul(UNITY_MATRIX_VP, mul(unity_ObjectToWorld, float4(p, 1))); - o.depth = (vClipPos.z / vClipPos.w + 1.0) * 0.5; + float zDepth = vClipPos.z / vClipPos.w; + #if !defined(UNITY_REVERSED_Z) // basically only OpenGL (unity editor on linux) + zDepth = zDepth * 0.5 + 0.5; // remap -1 to 1 range to 0.0 to 1.0 + #endif + o.depth = zDepth; return o; } diff --git a/Assets/raymarched/raymarcher.cginc.meta b/Assets/raymarched/Interactive/raymarcher.cginc.meta similarity index 100% rename from Assets/raymarched/raymarcher.cginc.meta rename to Assets/raymarched/Interactive/raymarcher.cginc.meta diff --git a/Assets/raymarched/Interactive/rm_combined.shader b/Assets/raymarched/Interactive/rm_combined.shader new file mode 100644 index 0000000..a9a39cf --- /dev/null +++ b/Assets/raymarched/Interactive/rm_combined.shader @@ -0,0 +1,192 @@ +Shader "CrispyPin/RaymarchMultiObject" +{ + Properties + { + [Header(Object positions)] + _ObjectA ("Object A", Vector) = (0, 0, 0) + [Header(Raymarcher Properties)] + _MaxSteps ("Max steps", Int) = 256 + _MaxDist ("Max distance", Float) = 100 + _SurfDist ("Surface distance threshold", Range(0.00001, 0.05)) = 0.001 + } + SubShader + { + Tags { "RenderType"="Opaque" } + Cull Off + LOD 100 + Pass + { + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + + + #include "UnityCG.cginc" + #include "UnityLightingCommon.cginc" + + struct appdata + { + float4 vertex : POSITION; + }; + + struct v2f + { + float4 vertex : SV_POSITION; + float3 ro : TEXCOORD1; + float3 hitPos : TEXCOORD2; + }; + + struct fragOut + { + fixed4 col : SV_Target; + float depth : SV_Depth; + }; + + int _MaxSteps; + float _MaxDist; + float _SurfDist; + float3 _ObjectA; + + v2f vert (appdata v) { + v2f o; + o.vertex = UnityObjectToClipPos(v.vertex); + //object space + o.ro = mul(unity_WorldToObject, float4(_WorldSpaceCameraPos, 1)); + o.hitPos = v.vertex; + //world space + //o.ro = _WorldSpaceCameraPos; + //o.hitPos = mul(unity_ObjectToWorld, v.vertex); + return o; + } + + float smin(float a, float b, float k) { + return min(a, b) - pow(max(k - abs(a-b), 0), 3)/(6*k*k); + } + + float sdSphere(float3 p, float3 o, float r) { + return length(p - o) - r; + } + + float sdBox(float3 p, float3 dim) { + return length(float3( + max(abs(p.x) - dim.x/2.0, 0), + max(abs(p.y) - dim.y/2.0, 0), + max(abs(p.z) - dim.z/2.0, 0))); + } + + float sdLine(float3 p, float3 a, float3 b, float r) { + float3 pa = p - a; + float3 ba = b - a; + float h = clamp(dot(pa, ba) / dot(ba, ba), 0, 1); + return length(pa - ba * h) - r; + } + + float sdCappedTorus( float3 p, float2 sc, float ra, float rb) { + p.x = abs(p.x); + float k = (sc.y*p.x>sc.x*p.y) ? dot(p.xy,sc) : length(p.xy); + return sqrt( dot(p,p) + ra*ra - 2.0*ra*k ) - rb; + } + + float3 RotateY(float3 p, float a) { + return mul(float3x3(cos(a), 0, sin(a), 0, 1, 0, -sin(a), 0, cos(a)), p); + } + + float Kijetesantakalu(float3 p, float r) { + float d = sdSphere(p, float3(0, 0, 0.2f), r);// left eye + d = min(d, sdSphere(p, float3(0.15f, 0, 0.2f), r)); // right eye + d = min(d, sdLine(p, float3(0, 0, -0.4f), float3(-0.35f, 0, -0.4f), r)); // bottom line + d = smin(d, sdLine(p, float3(0, 0, -0.4f), float3(-0.1f, 0, -0.15f), r), 0.003f); // leg hook + d = min(d, sdLine(p, float3(0.15f, 0, -0.4f), float3(0.15f, 0, -0.1f), r)); // middle leg + d = min(d, sdLine(p, float3(0.3f, 0, -0.4f), float3(0.3f, 0, 0), r)); // front leg + d = smin(d, sdLine(p, float3(0.45f, 0, 0.1f), float3(0.3f, 0, 0), r), 0.003f); // lower snout + d = smin(d, sdLine(p, float3(0.45f, 0, 0.1f), float3(0.2f, 0, 0.35f), r), 0.003f); // upper snout + d = smin(d, sdLine(p, float3(0.2f, 0, 0.45f), float3(0.2f, 0, 0.35f), r), 0.003f); // ear + float an = 0.9; + d = smin(d, sdCappedTorus((RotateY(p, 0.8f) - float3(0.15f, 0, -0.05f)).xzy, float2(sin(an),cos(an)), 0.4, r), 0.003f); // ear + d = smin(d, sdLine(p, float3(-0.25f, 0, 0), float3(-0.25f, 0, -0.4f), r), 0.003f); // back + d = smin(d, sdLine(p, float3(-0.25f, 0, -0.1f), float3(-0.35f, 0, -0.1f), r), 0.003f); // tail top + d = smin(d, sdLine(p, float3(-0.35f, 0, -0.1f), float3(-0.35f, 0, -0.4f), r), 0.003f); // stripe + an = 3.1415f*0.5; + d = smin(d, sdCappedTorus((RotateY(p, an) - float3(-0.25f, 0, 0.35f)).xzy, float2(sin(an),cos(an)), 0.15f, r), 0.003f); // tail + + return d; + } + + float FirstShape(float3 p) { + return Kijetesantakalu(p, 0.05f); + } + + float SecondShape(float3 p) { + // return sdBox(p, 0.3f) - 0.01f; + // return Kijetesantakalu(p, 0.04f) - 0.01f; + return sdSphere(p, 0, 0.3f); + } + + + float GetDist(float3 p) { + + float first = FirstShape(p); + // float3 second_pos = mul(unity_WorldToObject, _WorldSpaceLightPos0); + float second = SecondShape(p - _ObjectA); + return smin(first, second, 0.15f); + + } + + //marches a ray through the scene + float Raymarch(float3 ro, float3 rd) { + float rayLen = 0;// total distance marched / distance from origin + float dist; // distance from the raymarched scene + for ( int i = 0; i < _MaxSteps; i++) + { + //position = origin + distance * direction + float3 p = ro + rayLen * rd; + dist = GetDist(p); + rayLen += dist;// move forward + if (dist < _SurfDist || rayLen > _MaxDist) { + break; + } + } + + return rayLen; + } + + float3 GetNormal(float3 p) { + float2 e = float2(0.001, 0); + float3 n = GetDist(p) - float3( + GetDist(p-e.xyy), + GetDist(p-e.yxy), + GetDist(p-e.yyx)); + return normalize(n); + } + + fragOut frag (v2f i) { + float3 ro = i.ro; + float3 rd = normalize(i.hitPos - ro); + + float d = Raymarch(ro, rd); + fixed4 col = 1; + + if (d >= _MaxDist) + { + discard; + } + float3 p = ro + rd * d; + float3 n = GetNormal(p); + + // col.rgb = max(dot(n, normalize(float3(1,0.5,1))), 0.05f); + + col.rgb = lerp(0, float3(0,1,1), pow(1 - dot(-rd, n), 2)); + + // col *= float4(d, 1, 1, 1); + fragOut o; + o.col = col; + // o.col = _LightColor0; + float4 vClipPos = mul(UNITY_MATRIX_VP, mul(unity_ObjectToWorld, float4(p, 1))); + o.depth = (vClipPos.z / vClipPos.w + 1.0) * 0.5; + return o; + } + + ENDCG + } + } +} \ No newline at end of file diff --git a/Assets/raymarched/Interactive/rm_combined.shader.meta b/Assets/raymarched/Interactive/rm_combined.shader.meta new file mode 100644 index 0000000..ac9dea8 --- /dev/null +++ b/Assets/raymarched/Interactive/rm_combined.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: d9b470f9858f75d04aa12fe1b15b6ccb +ShaderImporter: + externalObjects: {} + defaultTextures: [] + nonModifiableTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/raymarched/Raymarching.unity b/Assets/raymarched/Raymarching.unity index 9e839ce..e3fe342 100644 --- a/Assets/raymarched/Raymarching.unity +++ b/Assets/raymarched/Raymarching.unity @@ -121,6 +121,133 @@ NavMeshSettings: debug: m_Flags: 0 m_NavMeshData: {fileID: 0} +--- !u!1 &453749071 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 453749072} + - component: {fileID: 453749075} + - component: {fileID: 453749074} + - component: {fileID: 453749073} + - component: {fileID: 453749077} + - component: {fileID: 453749076} + m_Layer: 0 + m_Name: Cube (1) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &453749072 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 453749071} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0.623, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 779234489} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!65 &453749073 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 453749071} + m_Material: {fileID: 0} + m_IsTrigger: 1 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!23 &453749074 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 453749071} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &453749075 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 453749071} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!114 &453749076 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 453749071} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 39d87b8783794dfd81ce396483019cbb, type: 3} + m_Name: + m_EditorClassIdentifier: + type: RaymarcherObjectA +--- !u!114 &453749077 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 453749071} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 12974925555b471580cacf5d2d5fa9e3, type: 3} + m_Name: + m_EditorClassIdentifier: + gripType: 1 + gripOrigin: {fileID: 0} + disallowTheft: 0 + maximumGrabDistance: 0 + snappingReferences: [] + autoHold: 0 + ikReference: {fileID: 0} --- !u!1 &695617482 GameObject: m_ObjectHideFlags: 0 @@ -213,6 +340,84 @@ Transform: m_Father: {fileID: 0} m_RootOrder: 5 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &779234488 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 779234489} + - component: {fileID: 779234491} + - component: {fileID: 779234490} + m_Layer: 0 + m_Name: MultiObject + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!4 &779234489 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 779234488} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0.044, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 453749072} + - {fileID: 884043982} + - {fileID: 2089960366} + m_Father: {fileID: 0} + m_RootOrder: 6 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &779234490 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 779234488} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 990f6f4efb7f4ec98ad99f6dff1bc6f6, type: 3} + m_Name: + m_EditorClassIdentifier: + type: 3 + objectId: d51b36f3-30c8-4e23-9277-34168a3024b4 +--- !u!114 &779234491 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 779234488} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a37fd8d654d5c2840a0ab3a5ad65a5ae, type: 3} + m_Name: + m_EditorClassIdentifier: + spawnHeight: 0 + useAdditionalValues: 1 + syncValues: + - name: + startValue: 0 + updatedBy: 0 + updateMethod: 1 + animator: {fileID: 0} + animatorParameterName: -none- + propPrivacy: 1 + subSyncs: + - transform: {fileID: 453749072} + syncedValues: 0 + precision: 4 + syncBoundary: 0.5 + spawnableType: 0 + preGeneratedInstanceId: --- !u!1 &845829380 GameObject: m_ObjectHideFlags: 0 @@ -305,6 +510,99 @@ Transform: m_Father: {fileID: 0} m_RootOrder: 1 m_LocalEulerAnglesHint: {x: 124.6, y: -30, z: 0} +--- !u!1 &884043981 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 884043982} + - component: {fileID: 884043985} + - component: {fileID: 884043984} + - component: {fileID: 884043983} + m_Layer: 0 + m_Name: Main + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &884043982 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 884043981} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 779234489} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!135 &884043983 +SphereCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 884043981} + m_Material: {fileID: 0} + m_IsTrigger: 1 + m_Enabled: 1 + serializedVersion: 2 + m_Radius: 0.5 + m_Center: {x: 0, y: 0, z: 0} +--- !u!23 &884043984 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 884043981} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 035a99d20f5635cd7a7cbba57b7068bc, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &884043985 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 884043981} + m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} --- !u!1 &1450495540 GameObject: m_ObjectHideFlags: 0 @@ -449,7 +747,7 @@ Transform: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1450495540} m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0.844, y: -0.907, z: 0.117} + m_LocalPosition: {x: 0.844, y: 0.389, z: 0.117} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 0} @@ -602,7 +900,7 @@ Transform: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1485771011} m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: -0.452, y: 0.221, z: -0.124} + m_LocalPosition: {x: -0.452, y: 0.221, z: -0.984} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 0} @@ -833,9 +1131,68 @@ Transform: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1651833084} m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0.265, y: -0.757, z: 0} + m_LocalPosition: {x: 0.525, y: 0.463, z: -0.326} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 0} m_RootOrder: 2 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &2089960365 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2089960366} + - component: {fileID: 2089960367} + m_Layer: 0 + m_Name: GameObject + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &2089960366 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2089960365} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 779234489} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &2089960367 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2089960365} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 81194749cc874e87b95c7b486517c3a9, type: 3} + m_Name: + m_EditorClassIdentifier: + areaSize: {x: 10, y: 0.05, z: 0} + areaOffset: {x: 0, y: 0, z: 0} + settingIndex: -1 + settingValue: 0 + useAdvancedTrigger: 1 + allowedTypes: + - RaymarcherObjectA + allowParticleInteraction: 0 + enterTasks: [] + exitTasks: [] + stayTasks: + - settingIndex: -1 + minValue: 0 + maxValue: 1 + updateMethod: 1 + sampleDirection: 0 diff --git a/Assets/test/Demo3.shader b/Assets/test/Demo3.shader new file mode 100644 index 0000000..5c78b28 --- /dev/null +++ b/Assets/test/Demo3.shader @@ -0,0 +1,92 @@ +Shader "Demo/pulsating" +{ + Properties + { + [Header(Lighting)] + _SunPos ("Sun position", Vector) = (8, 4, 2) + + [Header(Raymarcher Properties)] + _MaxSteps ("Max steps", Int) = 256 + _MaxDist ("Max distance", Float) = 256 + _SurfDist ("Surface distance threshold", Range(0.00001, 0.05)) = 0.001 + + } + SubShader + { + Tags { "RenderType"="Opaque" } + Cull Off + LOD 100 + + Pass + { + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + + // #define USE_WORLD_SPACE + #define DYNAMIC_QUALITY + #define USE_REFLECTIONS + // #define CONSTRAIN_TO_MESH + #define MAX_REFLECTIONS 1 + #include "RayMarchLib.cginc" + + float3 _SunPos; + + sdfData gyroid(float3 p, float scale, float bias, material mat = DEFMAT) + { + sdfData o; + o.dist = abs(dot(sin(p * scale), cos(p.zxy * scale))+bias) - 0.2; + o.dist *= .75 / scale; + o.mat = mat; + return o; + } + + + sdfData scene(float3 p) + { + sdfData o; + material mRed = mat(.12, 0.01, 0.01, sin(_Time*100)*0.1+0.6); + float3 bias = -pow(sin(_Time*60 + p.y*0.1), 8)*.5+1.3; + o = gyroid(p, .5, bias, mRed); + //o = sdfTorus(p, 10 + pow(sin(_Time*50), 4)*5, bias+sin(100*_Time + .1*p.x)*0.5+.5, cRed); + float3 gp = p + sin(_Time + p*0.1); + o.dist -= gyroid(gp, 1.63, .5).dist * 0.3; + o.dist += gyroid(gp, 3.327, 0).dist * 0.1; + o.dist += gyroid(gp, 7.351, .5).dist * 0.1; + o.dist -= gyroid(gp, 17.351, .5).dist * 0.05; + o.dist -= gyroid(gp, 23.521, .2).dist * 0.05; + o = sdfAdd(p, o, sdfSphere(p, 6 + bias*3, mRed), 5); + + // o = sdfInter(p, o, sdfSphere(p, 50, mat(0.04, 0.005, 0.035)), 1.1); + o = sdfInter(p, o, sdfBox(p, 20, mRed)); + //sdfData bobby = sdfSphere(p, 51, col(0.5, 0.25, 0.001)); + //bobby = sdfAdd(p, bobby, sdfSphere(p, 50.5, col(.5,.01,.01))); + //bobby = sdfSub(p, bobby, sdfSphere(p, 50)); + //o = sdfAdd(p, o, bobby); + //o = sdfAdd(p, o, sdfPlane(p, -50)); + return o; + } + + fixed4 lightPoint(rayData ray) + { + float3 vSunDir = normalize(_SunPos); + + if (ray.bMissed) + { + return 0.1; + } + + fixed4 col = 0; + + col = ray.mat.col * lightSun(ray.vNorm, vSunDir, col(5, 2, 0.1)); + col += ray.mat.col * lightSky(ray.vNorm, 1); + col *= lightAO(ray.vHit, ray.vNorm, 0.05); + + col = pow(col, 0.7); + //col = lightFog(col, col(0.3, .17, 0.001), ray.dist, 0, 48); + return col; + } + ENDCG + } + } +} diff --git a/Assets/test/Demo3.shader.meta b/Assets/test/Demo3.shader.meta new file mode 100644 index 0000000..2e91cf8 --- /dev/null +++ b/Assets/test/Demo3.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 26b714026d4c6e2dc8fefdbcf28344fd +ShaderImporter: + externalObjects: {} + defaultTextures: [] + nonModifiableTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/test/Demo4.shader b/Assets/test/Demo4.shader new file mode 100644 index 0000000..a5e4c30 --- /dev/null +++ b/Assets/test/Demo4.shader @@ -0,0 +1,79 @@ +Shader "Demo/Spinny thing" +{ + Properties + { + [Header(Lighting)] + _SunPos ("Sun position", Vector) = (8, 4, 2) + + [Header(Raymarcher Properties)] + _MaxSteps ("Max steps", Int) = 256 + _MaxDist ("Max distance", Float) = 256 + _SurfDist ("Surface distance threshold", Range(0.00001, 0.05)) = 0.001 + + } + SubShader + { + Tags { "RenderType"="Opaque" } + Cull Off + LOD 100 + + Pass + { + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + + #define USE_DYNAMIC_QUALITY + // #define USE_WORLD_SPACE + #define USE_REFLECTIONS + #define MAX_REFLECTIONS 5 + #define DISCARD_ON_MISS + //#define CONSTRAIN_TO_MESH + #include "RayMarchLib.cginc" + + float3 _SunPos; + + sdfData scene(float3 p) + { + sdfData o; + const material mGrass = mat(0.001, 0.1, 0.001, 0.7); + o = sdfPlane(p, 0, mGrass); + material mDirt = mat(0.1, 0.04, 0.01, 1); + o = sdfInter(p, o, sdfSphere(p, 9, mDirt), 0.5); + + const material mMetal = mat(0.1, 0); + + o = sdfAdd(p, o, sdfSphere(p - V_Y*2, 2, mMetal)); + material m = mat(0.05, 0.1, 0.2, 1); + o = sdfAdd(p, o, sdfTorus(rotX(p, _Time* 40+UNITY_PI/2), 5, 0.5, m), 0.5); + o = sdfAdd(p, o, sdfTorus(rotZ(p, _Time* 40+UNITY_PI/2), 5, 0.5, m), 0.5); + o = sdfAdd(p, o, sdfTorus(rotX(p, _Time* 40), 5, 0.5, m), 0.5); + o = sdfAdd(p, o, sdfTorus(rotZ(p, _Time* 40), 5, 0.5, m), 0.5); + + o = sdfAdd(p, o, sdfSphere(abs(rotY(p, -20 * _Time)) - float3(1.5,2,1.5), 1, mMetal), 0.2); + return o; + } + + fixed4 lightPoint(rayData ray) + { + float3 vSunDir = normalize(_SunPos); + + if (ray.bMissed) + { + return sky(ray.vRayDir); + } + + fixed4 col = 0; + + col = ray.mat.col * lightSun(ray.vNorm, vSunDir); + col *= lightShadow(ray.vHit, vSunDir, 50); + col += ray.mat.col * lightSky(ray.vNorm, 1); + col *= lightAO(ray.vHit, ray.vNorm); + + col = pow(col, 0.5); + return col; + } + ENDCG + } + } +} diff --git a/Assets/test/Demo4.shader.meta b/Assets/test/Demo4.shader.meta new file mode 100644 index 0000000..9f8b6a5 --- /dev/null +++ b/Assets/test/Demo4.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: d83b23d955f9dc5739d0827cd507a63e +ShaderImporter: + externalObjects: {} + defaultTextures: [] + nonModifiableTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/test/RayMarchLib.cginc b/Assets/test/RayMarchLib.cginc new file mode 100644 index 0000000..b6a37af --- /dev/null +++ b/Assets/test/RayMarchLib.cginc @@ -0,0 +1,1044 @@ +//double include guard +#ifndef RAY_MARCH_LIB_INCLUDED +#define RAY_MARCH_LIB_INCLUDED + +#include "UnityCG.cginc" + +// Multi compile stuff + +#define V_X float3(1, 0, 0) +#define V_Y float3(0, 1, 0) +#define V_Z float3(0, 0, 1) +#define V_XZ float3(1, 0, 1) +#define V_XY float3(1, 1, 0) +#define V_YZ float3(0, 1, 1) + +//ambient occlusion quality +#ifndef AO_STEPS +#define AO_STEPS 5 +#endif + +//normals for lighting +#ifndef NORMAL_DELTA +#define NORMAL_DELTA 0.001 +#endif +//normals for reflection angles +#ifndef REFL_NORMAL_DELTA +#define REFL_NORMAL_DELTA 0.001 +#endif + +#ifndef MAX_REFLECTIONS +#define MAX_REFLECTIONS 2 +#endif + +#ifdef USE_DYNAMIC_QUALITY//quality settings as unity material properties +int _MaxSteps = 100; +float _MaxDist = 100; +float _SurfDist = 0.00001; +#else//pre compile quality settings +#ifndef MAX_STEPS +#define MAX_STEPS 256 +//256 +#endif +#ifndef MAX_DIST +#define MAX_DIST 128 +#endif +#ifndef SURF_DIST +#define SURF_DIST 0.0001 +//#define SURF_DIST 0.00001 +#endif +#endif + + +#define col(r, g, b) fixed4(r, g, b, 1) + +struct appdata +{ + float4 vertex : POSITION; +}; + +struct v2f +{ + float4 vertex : SV_POSITION; + float3 vCamPos : TEXCOORD1; + float3 vHitPos : TEXCOORD2; +}; + +struct fragOut +{ + fixed4 col : SV_Target; + float depth : SV_Depth; +}; + +typedef struct material +{ + fixed4 col; + fixed fRough; +} material_t; + +#define DEFMAT {fixed4(.2,.2,.2,1), 1} + +#define M_RED {fixed4(0.2, 0.001, 0.001, 1), 1} +#define M_ORANGE {fixed4(0.2, 0.1, 0.001, 1), 1} +#define M_YELLOW {fixed4(0.2, 0.2, 0.001, 1), 1} +#define M_GREEN {fixed4(0.001, 0.2, 0.001, 1), 1} +#define M_BLUE {fixed4(0.001, 0.001, 0.2, 1), 1} +#define M_LIGHT_BLUE{fixed4(0.001, 0.05, 0.2, 1), 1} +#define M_MAGENTA {fixed4(0.2, 0.001, 0.2, 1), 1} +#define M_PURPLE {fixed4(0.05, 0.001, 0.2, 1), 1} +#define M_WHITE {fixed4(0.5, 0.5, 0.5, 1), 1} +#define M_MIRROR {fixed4(0.1, 0.1, 0.1, 1), 0} + +inline material mat(float r, float g, float b, float fRough = 1) +{ + material m = {fixed4(r, g, b, 1), fRough}; + return m; +} + +inline material mat(float3 rgb, float fRough = 1) +{ + material m = {fixed4(rgb, 1), fRough}; + return m; +} + +//used for lighting a point +struct rayData +{ + float dist; + int iSteps; + material mat; + float3 vRayStart; + float3 vRayDir; + float3 vHit; + fixed3 vNorm; + bool bMissed; + float minDist; + float distToMinDist; +}; + +//returned from distance functions, including main scene +struct sdfData +{ + float dist; + material mat; +}; + + +sdfData scene(float3 p); +fixed4 lightPoint(rayData r); +fixed4 rayMarch(float3 p, float3 d); +rayData castRay(float3 p, float3 d, float startDist = 0); + + +v2f vert (appdata v) +{ + v2f o; + o.vertex = UnityObjectToClipPos(v.vertex); +#ifdef USE_WORLD_SPACE + o.vCamPos = _WorldSpaceCameraPos; + o.vHitPos = mul(unity_ObjectToWorld, v.vertex); +#else + o.vCamPos = mul(unity_WorldToObject, float4(_WorldSpaceCameraPos, 1)); + o.vHitPos = v.vertex; +#endif + return o; +} + + +#ifdef USE_REFLECTIONS +#define CALC_NORM +fragOut frag (v2f i) +{ + + float fRayLen = 0;//since last bounce + + #ifdef CONSTRAIN_TO_MESH + float3 vLastBounce = i.vHitPos; + fRayLen += length(i.vHitPos - i.vCamPos); + #else + float3 vLastBounce = i.vCamPos; + #endif + float3 vRayDir = normalize(i.vHitPos - i.vCamPos);//current direction + sdfData point_data; + rayData ray; + + fixed4 col; + float colUsed = 0;// what amount of the final colour has been calculated + float prevRough = 0; + + float3 vFirstHit; + + for (int i = 0; i < MAX_REFLECTIONS+1; i++) + { + ray = castRay(vLastBounce, vRayDir); + if (i == 0) + {//before any bounces + col = lightPoint(ray); + vFirstHit = ray.vHit; + } + else + { + float colAmt = colUsed + (prevRough * (1-colUsed)); + col = lerp(lightPoint(ray), col, colAmt); + colUsed = colAmt; + } + if (ray.bMissed || ray.mat.fRough > 0.99) + { + break; + } + prevRough = ray.mat.fRough; + vRayDir = reflect(vRayDir, ray.vNorm); + vLastBounce = ray.vHit + vRayDir * 0.01; + } + #ifdef DISCARD_ON_MISS + if (ray.bMissed && i == 0) discard; + #endif + fragOut o; + o.col = col; + + #ifdef USE_WORLD_SPACE + float4 vClipPos = mul(UNITY_MATRIX_VP, float4(vFirstHit, 1)); + #else + float4 vClipPos = mul(UNITY_MATRIX_VP, mul(unity_ObjectToWorld, float4(vFirstHit, 1))); + #endif + + o.depth = vClipPos.z / vClipPos.w; + #if !defined(UNITY_REVERSED_Z) // basically only OpenGL (unity editor on linux) + o.depth = o.depth * 0.5 + 0.5; // remap -1 to 1 range to 0.0 to 1.0 + #endif + return o; +} +#else +fragOut frag (v2f i) +{ + float3 vRayDir = normalize(i.vHitPos - i.vCamPos); + #ifdef CONSTRAIN_TO_MESH + //rayData ray = castRay(i.vHitPos, vRayDir, length(i.vHitPos-i.vCamPos)); + rayData ray = castRay(i.vCamPos, vRayDir, length(i.vHitPos-i.vCamPos)); + //rayData ray = castRay(i.vCamPos, vRayDir, 1); + //rayData ray = castRay(i.vCamPos, vRayDir, 0); + + #else + rayData ray = castRay(i.vCamPos, vRayDir); + #endif + #ifdef DISCARD_ON_MISS + if (ray.bMissed) discard; + #endif + fragOut o; + o.col = lightPoint(ray); + + // writing to depth buffer costs about 1-2 frames at 4k + #ifdef USE_WORLD_SPACE + float4 vClipPos = mul(UNITY_MATRIX_VP, float4(ray.vHit, 1)); + #else + float4 vClipPos = mul(UNITY_MATRIX_VP, mul(unity_ObjectToWorld, float4(ray.vHit, 1))); + #endif + + o.depth = (vClipPos.z / vClipPos.w + 1.0) * 0.5; + return o; +} +#endif + +//gets normal of a point +inline float3 getNormFull(float3 vPos, float fEpsilon = 0.001) +{ + //if epsilon is smaller than 0.001, there are often artifacts + const float2 e = float2(fEpsilon, 0); + float3 n = scene(vPos).dist - float3( + scene(vPos - e.xyy).dist, + scene(vPos - e.yxy).dist, + scene(vPos - e.yyx).dist); + return normalize(n); +} +//gets normal, provided you have the distance for pos (1 less call to scene()) +inline float3 getNorm(float3 vPos, float fPointDist, float fEpsilon = 0.001) +{ + ////if epilon is smaller than 0.001, there are often artifacts + const float2 e = float2(fEpsilon, 0); + float3 n = fPointDist - float3( + scene(vPos - e.xyy).dist, + scene(vPos - e.yxy).dist, + scene(vPos - e.yyx).dist); + return normalize(n); +} + +//marches a ray through the scene once +rayData castRay(float3 vRayStart, float3 vRayDir, float startDist) +{ + float fRayLen = startDist;//startDist;// total distance marched / distance from camera + + float3 vPos; + sdfData sdf_data; + + rayData ray; + ray.vRayDir = vRayDir; + ray.vRayStart = vRayStart; + ray.minDist = 30000.0;// budget "infinity" + ray.distToMinDist = 0; + + #ifdef USE_DYNAMIC_QUALITY + for (int i = 0; i < _MaxSteps; i++) + #else + for (int i = 0; i < MAX_STEPS; i++) + #endif + { + vPos = vRayStart + fRayLen * vRayDir; + sdf_data = scene(vPos); + + #ifdef USE_DYNAMIC_QUALITY + if (abs(sdf_data.dist) < _SurfDist) break; + #else + if (abs(sdf_data.dist) < SURF_DIST) break; + #endif + + fRayLen += sdf_data.dist;// move forward + + if (ray.minDist>sdf_data.dist) + { + ray.minDist = sdf_data.dist; + ray.distToMinDist = fRayLen; + } + + #ifdef USE_DYNAMIC_QUALITY + if (fRayLen > _MaxDist) {ray.bMissed = true; break;}//flag this as transparent/sky + #else + if (fRayLen > MAX_DIST) {ray.bMissed = true; break;}//flag this as transparent/sky + #endif + } + + ray.dist = fRayLen; + ray.iSteps = i; + ray.mat = sdf_data.mat; + ray.vHit = vPos; + #ifdef CALC_NORM + ray.vNorm = getNorm(vPos, sdf_data.dist); + #endif + return ray; +} + + +////////////////////////////////////////////////////////////////////// +// +// Lighting +// +////////////////////////////////////////////////////////////////////// + + +//generates a skybox, use when ray didn't hit anything (ray_data.bMissed) +inline fixed4 sky(float3 vRayDir) +{ + float4 cRenderedSun = max(0, pow(dot(vRayDir, normalize(float3(8,4,2))) + 0.4, 10)-28) * float4(.8,.4,0,1); + return fixed4(0.7, 0.75, 0.8, 1) - abs(vRayDir.y) * 0.5 + cRenderedSun; +} + +//calculate sun light based on normal +fixed4 lightSun(float3 vNorm, float3 vSunDir = float3(8, 4, 2), fixed4 cSunCol = fixed4(7.0, 5.5, 3.0, 1)) +{ + float fSunLight = max(dot(vNorm, vSunDir), 0); + return fSunLight * cSunCol; +} + +//calculate shadow from sun +float lightShadow(float3 vPos, float3 vSunDir, float fSharpness = 8) +{ + float fShadow = 1; + #ifdef USE_DYNAMIC_QUALITY + for (float fRayLen = 0.001; fRayLen < _MaxDist/2.0;) + #else + for (float fRayLen = 0.001; fRayLen < MAX_DIST/2.0;) + #endif + { + float dist = scene(vPos + vSunDir * fRayLen).dist; + + #ifdef USE_DYNAMIC_QUALITY + if (dist < _SurfDist) return 0; + #else + if (dist < SURF_DIST) return 0; + #endif + + fShadow = min(fShadow, fSharpness * dist/fRayLen); + fRayLen += dist; + } + return fShadow; +} + +//calculate sky light +inline fixed4 lightSky(float3 vNorm, fixed4 cSkyCol = fixed4(0.5, 0.8, 0.9, 1)) +{ + return cSkyCol * (0.5 + 0.5 * vNorm.y); +} + +//bad ambient occlusion (screen space) based on steps +float lightSSAO(rayData ray_data, float fDarkenFactor = 2) +{ + #ifdef USE_DYNAMIC_QUALITY + return pow(1 - float(ray_data.iSteps) / _MaxSteps, fDarkenFactor); + #else + return pow(1 - float(ray_data.iSteps) / MAX_STEPS, fDarkenFactor); + #endif +} + +//ambient occlusion +float lightAO(float3 vPos, float3 vNorm, float fEpsilon = 0.05) +{ + float ao = 0; + for (int i = 0; i < AO_STEPS; i++) + { + float fOffset = i * fEpsilon; + float fDist = scene(vPos + vNorm * fOffset).dist; + ao += 1/pow(2, i) * (fOffset - fDist); + } + ao = 1 - AO_STEPS * ao; + return ao; +} + +inline fixed4 lightFog(fixed4 col, fixed4 cFog, float fDist, float fStart=16, float fFull=32) +{ + if (fDist < 0) return cFog; + return lerp(col, cFog, smoothstep(fStart, fFull, fDist)); +} + +//a light pass for debugging +fixed4 lightOnly(float3 vPos, float3 vNorm, float3 vSunDir) +{ + float fLight = lightSun(vNorm, vSunDir, 1); + float fAO = lightAO(vPos, vNorm); + float fShadow = lightShadow(vPos, vSunDir); + return fLight * fAO * fShadow; +} + + +////////////////////////////////////////////////////////////////////// +// +// Interpolation and Math +// +////////////////////////////////////////////////////////////////////// + + +//soft min of a and b with smoothing factor k +inline float smin(float a, float b, float k) +{ + float h = max(k - abs(a-b), 0) / k; + return min(a, b) - h*h*h*k * 1/6.0; +} + +//soft max of a and b with smoothing factor k +inline float smax(float a, float b, float k) +{ + float h = max(k - abs(a - b), 0) / k; + return max(a, b) + h*h*h*k * 1/6.0; +} + +//interpolate between the colours of 2 SDFs +inline material mixMat(sdfData sdfA, sdfData sdfB) +{ + material m; + float fac = clamp(sdfA.dist/(sdfA.dist + sdfB.dist), 0, 1); + m.col = lerp(sdfA.mat.col, sdfB.mat.col, fac); + m.fRough = lerp(sdfA.mat.fRough, sdfB.mat.fRough, fac); + return m; +} + +//interpolate between the colours of 2 SDFs +inline material mixMat(material a, material b, float fac) +{ + material m; + m.col = lerp(a.col, b.col, fac); + m.fRough = lerp(a.fRough, b.fRough, fac); + return m; +} + +// from: https://github.com/michaldrobot/ShaderFastLibs/blob/master/ShaderFastMathLib.h +// modified to be more "optimized" (WAY worse approximations) +static const float fsl_PI = 3.1415926535897932384626433f; +static const float fsl_PI_half = fsl_PI/2; +inline float acosFast4(float inX) +{ + return 1.57-inX; + float x1 = abs(inX); + //float x2 = x1 * x1; + //float x3 = x2 * x1; + float s; + + s = -0.2121144f * x1 + 1.5707288f; + //s = 0.0742610f * x2 + s; + //s = -0.0187293f * x3 + s; + s = sqrt(1.0f - x1) * s; + + // acos function mirroring + // check per platform if compiles to a selector - no branch neeeded + return s; + //return inX >= 0.0f ? s : fsl_PI - s; +} + +// polynomial degree 2 +// Tune for positive input [0, infinity] and provide output [0, PI/2] +inline float ATanPos(float x) +{ + const float C1 = 1.01991; + const float C2 = -0.218891; + float t0 = (x < 1.0f) ? x : 1.0f / x; + float t1 = (C2 * t0 + C1) * t0; // p(x) + return t1;//return (x < 1.0f) ? t1: fsl_PI_half - t1; // undo range reduction +} +// Common function, ATanPos is implemented below +// input [-infinity, infinity] and output [-PI/2, PI/2] +inline float ATan(float x) +{ + float t0 = ATanPos(abs(x)); + return t0;//(x < 0.0f) ? -t0: t0; // undo range reduction +} + +inline float atanFast4(float inX) +{ + //return atan(inX); + return ATan(inX); + float x = inX; + return x*(-0.1784f * abs(x) - 0.0663f * x * x + 1.0301f); +} + +// https://en.wikipedia.org/wiki/Atan2#Definition_and_computation +inline float atanFast4_2(float y, float x) +{ + //return sign(x)*sign(x)*atanFast4(y/x)+((1-sign(x))/2)*(1-sign(y)-sign(y)*sign(y))*fsl_PI; + return atanFast4(y/x)+(1-sign(x))*(sign(y))*fsl_PI/2; + +} + + + + + + +////////////////////////////////////////////////////////////////////// +// +// SDF operations +// +////////////////////////////////////////////////////////////////////// + + +//union of SDF A and B +sdfData sdfAdd(float3 p, sdfData sA, sdfData sB) +{ + sdfData sC; + sC.dist = min(sA.dist, sB.dist); + sC.mat = mixMat(sA, sB); + return sC; +} + +//union of SDF A and B, with smoothing +sdfData sdfAdd(float3 p, sdfData sA, sdfData sB, float fSmooth) +{ + sdfData sC; + sC.dist = smin(sA.dist, sB.dist, fSmooth); + sC.mat = mixMat(sA, sB); + return sC; +} + +//remove the SDF B from A (colour is from A) +sdfData sdfSub(float3 p, sdfData sA, sdfData sB) +{ + sdfData sC; + sC.dist = max(sA.dist, -sB.dist); + sC.mat = sA.mat; + return sC; +} + +//remove the SDF B from A (colour is from A), with smoothing +sdfData sdfSub(float3 p, sdfData sA, sdfData sB, float fSmooth) +{ + sdfData sC; + sC.dist = smax(sA.dist, -sB.dist, fSmooth); + sC.mat = sA.mat; + return sC; +} + +//intersection of SDF A and B +sdfData sdfInter(float3 p, sdfData sA, sdfData sB) +{ + sdfData sC; + sC.dist = max(sA.dist, sB.dist); + sC.mat = mixMat(sA, sB); + return sC; +} + +//intersection of SDF A and B, with smoothing +sdfData sdfInter(float3 p, sdfData sA, sdfData sB, float fSmooth) +{ + sdfData sC; + sC.dist = smax(sA.dist, sB.dist, fSmooth); + sC.mat = mixMat(sA, sB); + return sC; +} + +//round edges of an SDF +sdfData sdfRound(float3 p, sdfData sdfIn, float fRadius) +{ + sdfData sdfOut = sdfIn; + sdfOut.dist -= fRadius; + return sdfOut; +} + + + +////////////////////////////////////////////////////////////////////// +// +// SDF shapes +// +////////////////////////////////////////////////////////////////////// + + +//create sphere +sdfData sdfSphere(float3 p, float fRadius, material mat = DEFMAT) +{ + sdfData sdf; + sdf.dist = length(p) - fRadius; + sdf.mat = mat; + return sdf; +} + +//create plane pointing to positive Y +sdfData sdfPlane(float3 p, float fHeight, material mat = DEFMAT) +{ + sdfData sdf; + sdf.dist = p.y - fHeight; + sdf.mat = mat; + return sdf; +} + +//create plane with normal +sdfData sdfPlane(float3 p, float3 vNorm, float fHeight, material mat = DEFMAT) +{ + sdfData sdf; + sdf.dist = dot(p, normalize(vNorm)) - fHeight; + sdf.mat = mat; + return sdf; +} + +//create cuboid +sdfData sdfBox(float3 p, float3 vDim, material mat = DEFMAT) +{ + sdfData sdf; + float3 q = abs(p) - vDim/2.0; + sdf.dist = length(max(q, 0)) + min(max(q.x, max(q.y, q.z)), 0); + sdf.mat = mat; + return sdf; +} + +//create cuboid +sdfData sdfBox(float3 p, float3 vDim, float fRound, material mat = DEFMAT) +{ + sdfData sdf; + float3 q = abs(p) - vDim/2.0; + sdf.dist = length(max(q, 0)) + min(max(q.x, max(q.y, q.z)), 0) - fRound; + sdf.mat = mat; + return sdf; +} + +//create line segment +sdfData sdfLine(float3 p, float3 vStart, float3 vEnd, float fRadius, material mat = DEFMAT) +{ + sdfData sdf; + float h = min(1, max(0, dot(p-vStart, vEnd-vStart) / dot(vEnd-vStart, vEnd-vStart))); + sdf.dist = length(p-vStart-(vEnd-vStart)*h)-fRadius; + sdf.mat = mat; + return sdf; +} + +//create cylinder +sdfData sdfCylinder(float3 p, float fRadius, float fHeight, material mat = DEFMAT) +{ + sdfData sdf; + sdf.dist = max(abs(p.y) - fHeight/2.0, length(p.xz) - fRadius); + sdf.mat = mat; + return sdf; +} + +//create cylinder +sdfData sdfCylinder(float3 p, float fRadius, float fHeight, float fRound, material mat = DEFMAT) +{ + sdfData sdf; + sdf.dist = max(abs(p.y) - fHeight/2.0, length(p.xz) - fRadius) - fRound; + sdf.mat = mat; + return sdf; +} + +//create torus +sdfData sdfTorus(float3 p, float fRadius, float fThickness, material mat = DEFMAT) +{ + sdfData sdf; + float2 q = float2(length(p.xz) - fRadius, p.y); + sdf.dist = length(q) - fThickness; + sdf.mat = mat; + return sdf; +} + +//triangular prism (BOUND) +sdfData sdfTriPrism(float3 p, float fSide, float fDepth, material mat = DEFMAT) +{ + float3 q = abs(p); + sdfData sdf; + sdf.dist = max(q.z - fDepth, max(q.x * 0.866025 + p.y * 0.5, -p.y) - fSide * 0.5); + sdf.mat = mat; + return sdf; +} + + +////////////////////////////////////////////////////////////////////// +// +// Fractals, complex shapes and scenes (frac prefix) +// +////////////////////////////////////////////////////////////////////// + +//TODO: +// complex :julia, +// simple sierpinsky, menger + +// Mandelbolb - OPTIMIZED AF, still a fractal but visually diffrent. +sdfData fracMandelbolb(float3 p, material mat = DEFMAT) +{ + // http://blog.hvidtfeldts.net/index.php/2011/09/distance-estimated-3d-fractals-v-the-mandelbulb-different-de-approximations/ + float3 pos; + pos.x = p.x; + pos.y = p.y; + pos.z = p.z; + + float dr = 1.0; + float r = 0; + + const int iterations = 4; + + const float maxRThreshold = 2;//2; + + const float Power = 16; + for (int i = 0; i < iterations; i++) + { + r = length(p); + if (r>maxRThreshold) break; + + // xyz -> polar + //float theta = acos( p.z / r ); + float theta = acosFast4( p.z / r ); + //float phi = atan2( p.y, p.x ); + float phi = atanFast4_2( p.y, p.x ); + dr = pow( r, Power-1.0)*Power*dr + 1.0; + + // transform point + float zr = pow( r, Power ); + theta = theta * Power; + phi = phi * Power; + + // polar -> xyz + p = zr*float3(sin(theta)*cos(phi), sin(phi)*sin(theta), cos(theta)); + p += pos; + } + + sdfData sdf; + sdf.mat = mat; + sdf.dist = 0.5*log(r)*r/dr; + return sdf; +} + +// Mandelbulb +sdfData fracMandelbulb(float3 p, material mat = DEFMAT) +{ + // http://blog.hvidtfeldts.net/index.php/2011/09/distance-estimated-3d-fractals-v-the-mandelbulb-different-de-approximations/ + float3 pos; + pos.x = p.x; + pos.y = p.y; + pos.z = p.z; + + float dr = 1.0; + float r = 0; + + // Lowest number of iterations without loosing a significant amount of detail + // Depends on maxRThreshold + //int iterations = 1; + //int iterations = 8; + const int iterations = 5; + + //float maxRThreshold = 2; + const float maxRThreshold = 2; + + // Z_(n+1) = Z(n)^? + // float Power = 8 + 6 * sin(_Time.x); + float Power = 8; + for (int i = 0; i < iterations; i++) + { + r = length(p); + if (r>maxRThreshold) break; + + // xyz -> polar + float theta = acos( p.z / r ); + float phi = atan2( p.y, p.x ); + dr = pow( r, Power-1.0)*Power*dr + 1.0; + + // transform point + float zr = pow( r, Power ); + theta = theta * Power; + phi = phi * Power; + + // polar -> xyz + p = zr*float3(sin(theta)*cos(phi), sin(phi)*sin(theta), cos(theta)); + p += pos; + + + } + + sdfData sdf; + sdf.mat = mat; + //sdf.mat.col.y = sin(p.x); + //sdf.dist = sdfSphere(pos, 10).dist; + //sdf.mat = mat; + sdf.dist = 0.5*log(r)*r/dr; + //sdf.mat = mat; + + return sdf; +} + +void sphereFold(inout float3 p, inout float dz, float minRadius, float fixedRadius); +void boxFold(inout float3 p, float dz, float foldingLimit); + +// Mandelbox +sdfData fracMandelbox(float3 p, float scaleFactor, material mat = DEFMAT) +{ + // http://blog.hvidtfeldts.net/index.php/2011/11/distance-estimated-3d-fractals-vi-the-mandelbox/ + + float3 offset = p; + float dr = 0; + + // Parameters + int iterations = 8;//20;//14; + //scaleFactor = -2 + (_SinTime.x*4+2); + float fixedRadius = 1.0; + float minRadius = 0.5; + /*float foldingLimit = 0.2 + _SinTime.x/4 + 0.25; + float minRadius = 0.07; + float fixedRadius = 0.2;*/ + + //float scaleFactor = -0.8; + + + /*float foldingLimit = _FoldingLimit; + float minRadius = _MinRadius; + float fixedRadius = _FixedRadius;*/ + + + for(int i=0; i 1.0) + p.x = 2.0 - p.x; + else if (p.x < -1.0) p.x = -2.0 - p.x; + if (p.y > 1.0) + p.y = 2.0 - p.y; + else if (p.y < -1.0) p.y = -2.0 - p.y; + if (p.z > 1.0) + p.z = 2.0 - p.z; + else if (p.z < -1.0) p.z = -2.0 - p.z; + + // radius squared + float r2 = dot(p,p); + + if (r2 < mR2) + { + p*=(fR2/mR2); + DEfactor*=(fR2/mR2); + } + else if (r2 < fR2) + { + p*=(fR2/r2); + DEfactor*=(fR2/r2); + } + p=p*scale+1; + DEfactor*=scale; + } + + sdfData sdf; + sdf.mat = mat; + sdf.dist = length(p)/abs(DEfactor); + return sdf; +} + +// Feather +sdfData fracFeather(float3 p, float cx = 2.0, float cy = 2.7, float cz = 1.4, material mat=DEFMAT) +{ + // https://fractalforums.org/index.php?action=gallery;sa=view;id=5732 + int iterations = 5; + //float cx = 2.0; + //float cy = 2.7; + //float cz = 1.4; + float cw = 0.1; + float dx = 1.5;// + _FoldingLimit-0.5; + + float lp,r2,s = 1; + + float icy = 1.0 / cy; + float3 p2,cy3 = float3(cy,cy,cy); + + for (int i=0; i