Skip to content

Instantly share code, notes, and snippets.

@StagPoint
Created May 7, 2020 00:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save StagPoint/6780d62717e66f26f46adf828ffe16c0 to your computer and use it in GitHub Desktop.
Save StagPoint/6780d62717e66f26f46adf828ffe16c0 to your computer and use it in GitHub Desktop.
Unity Port of "Dusty Nebula 4" by Duke ( https://www.shadertoy.com/view/MsVXWW )
// "Dusty nebula 4" by Duke
// https://www.shadertoy.com/view/MsVXWW
//-------------------------------------------------------------------------------------
// Based on "Dusty nebula 3" (https://www.shadertoy.com/view/lsVSRW)
// and "Protoplanetary disk" (https://www.shadertoy.com/view/MdtGRl)
// otaviogood's "Alien Beacon" (https://www.shadertoy.com/view/ld2SzK)
// and Shane's "Cheap Cloud Flythrough" (https://www.shadertoy.com/view/Xsc3R4) shaders
// Some ideas came from other shaders from this wonderful site
// Press 1-2-3 to zoom in and zoom out.
// License: Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License
//-------------------------------------------------------------------------------------
Shader "StarMap/Raycast Nebula"
{
Properties
{
// Assign a 256x256 blue noise texture to the material's _MainTex property
_MainTex( "Texture", 2D ) = "white" {}
}
SubShader
{
Tags
{
"Queue" = "Transparent"
"RenderType" = "Transparent"
"IgnoreProjector" = "True"
"ForceNoShadowCasting" = "True"
"CanUseSpriteAtlas" = "False"
"PreviewType" = "Plane"
}
Blend SrcAlpha One
ZWrite Off
ZTest Less
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_instancing
#include "UnityCG.cginc"
const float nudge = 0.739513; // size of perpendicular vector
sampler2D _MainTex;
float4 _MainTex_ST;
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 pos : SV_POSITION;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
#define pi 3.14159265
#define R(p, a) p= cos(a) * p + sin(a) * float2(p.y, -p.x)
// iq's noise
float noise( in float3 x )
{
float3 p = floor( x );
float3 f = frac( x );
f = f * f*(3.0 - 2.0*f);
float2 uv = (p.xy + float2( 37.0, 17.0 ) * p.z) + f.xy;
float2 rg = tex2D( _MainTex, (uv + 0.5) / 256.0 ).yx;
return 1.0 - 0.82 * lerp( rg.x, rg.y, f.z );
}
float rand( float2 co )
{
return frac( sin( dot( co * 0.123, float2( 12.9898, 78.233 ) ) ) * 43758.5453 );
}
//=====================================
// otaviogood's noise from https://www.shadertoy.com/view/ld2SzK
//--------------------------------------------------------------
// This spiral noise works by successively adding and rotating sin waves while increasing frequency.
// It should work the same on all computers since it's not based on a hash function like some other noises.
// It can be much faster than other noise functions if you're ok with some repetition.
float SpiralNoiseC( float3 p )
{
float normalizer = 1.0 / sqrt( 1.0 + nudge * nudge ); // Pythagorean theorem on that perpendicular to maintain scale
float n = 0.0; // noise amount
float iter = 1.0;
for( int i = 0; i < 8; i++ )
{
// add sin and cos scaled inverse with the frequency
n += -abs( sin( p.y*iter ) + cos( p.x*iter ) ) / iter; // abs for a ridged look
// rotate by adding perpendicular and scaling down
p.xy += float2( p.y, -p.x ) * nudge;
p.xy *= normalizer;
// rotate on other axis
p.xz += float2( p.z, -p.x ) * nudge;
p.xz *= normalizer;
// increase the frequency
iter *= 1.733733;
}
return n;
}
float SpiralNoise3D( float3 p )
{
float normalizer = 1.0 / sqrt( 1.0 + nudge * nudge ); // Pythagorean theorem on that perpendicular to maintain scale
float n = 0.0;
float iter = 1.0;
for( int i = 0; i < 5; i++ )
{
n += (sin( p.y*iter ) + cos( p.x*iter )) / iter;
p.xz += float2( p.z, -p.x ) * nudge;
p.xz *= normalizer;
iter *= 1.33733;
}
return n;
}
float NebulaNoise( float3 p )
{
float final = p.y + 4.5;
final -= SpiralNoiseC( p.xyz ); // mid-range noise
final += SpiralNoiseC( p.zxy*0.5123 + 100.0 )*4.0; // large scale features
final -= SpiralNoise3D( p ); // more large scale features, but 3d
return final;
}
float map( float3 p )
{
#ifdef ROTATION
R( p.xz, iMouse.x*0.008*pi + iTime * 0.1 );
#endif
R( p.xz, _Time.y * 0.1 );
float NebNoise = abs( NebulaNoise( p / 0.5 ) * 0.5 );
return NebNoise + 0.03;
}
// assign color to the media
float3 computeColor( float density, float radius )
{
// color based on density alone, gives impression of occlusion within
// the media
float3 result = lerp( float3( 1.0, 0.9, 0.8 ), float3( 0.4, 0.15, 0.1 ), density );
// color added to the media
float3 colCenter = 7.0 * float3( 0.8, 1.0, 1.0 );
float3 colEdge = 1.5 * float3( 0.48, 0.53, 0.5 );
result *= lerp( colCenter, colEdge, min( (radius + 0.05) / 0.9, 1.15 ) );
return result;
}
bool RaySphereIntersect( float3 org, float3 dir, out float near, out float far )
{
float b = dot( dir, org );
float c = dot( org, org ) - 8.0;
float delta = b * b - c;
if( delta < 0.0 )
return false;
float deltasqrt = sqrt( delta );
near = -b - deltasqrt;
far = -b + deltasqrt;
return far > 0.0;
}
// Applies the filmic curve from John Hable's presentation
// More details at : http://filmicgames.com/archives/75
float3 ToneMapFilmicALU( float3 _color )
{
_color = max( float3(0, 0, 0), _color - float3(0.004, 0.004, 0.004) );
_color = (_color * (6.2 * _color + float3(0.5, 0.5, 0.5))) / (_color * (6.2 * _color + float3(1.7, 1.7, 1.7)) + float3(0.06, 0.06, 0.06));
return _color;
}
//void R( out float2 p, float a )
//{
// p = cos( a ) * p + sin( a ) * float2(p.y, -p.x);
//}
v2f vert( appdata v )
{
v2f o;
o.pos = UnityObjectToClipPos( v.vertex );
o.uv = v.uv.xy;
float3 vpos = mul( (float3x3)unity_ObjectToWorld, v.vertex.xyz );
float4 worldCoord = float4(unity_ObjectToWorld._m03, unity_ObjectToWorld._m13, unity_ObjectToWorld._m23, 1);
float4 viewPos = mul( UNITY_MATRIX_V, worldCoord ) + float4(vpos, 0);
float4 outPos = mul( UNITY_MATRIX_P, viewPos );
o.pos = outPos;
o.uv = v.uv.xy;
return o;
}
fixed4 frag( v2f input ) : SV_Target
{
float3 fragCoord = input.pos;
float iTime = _Time.y;
float key = 0.0;
// ro: ray origin
// rd: direction of the ray
float3 rd = normalize( float3( (fragCoord.xy - 0.5 * _ScreenParams.xy) / _ScreenParams.y, 1.0 ) );
float3 ro = float3( 0.0, 0.0, -6.0 + key * 1.6 );
R( rd.yz, -pi * 3.93 );
R( rd.xz, pi*3.2 );
R( ro.yz, -pi * 3.93 );
R( ro.xz, pi*3.2 );
float2 dpos = (fragCoord.xy / _ScreenParams.xy);
float2 seed = dpos + frac( iTime );
// ld, td: local, total density
// w: weighting factor
float ld = 0.0;
float td = 0.0;
float w = 0.0;
// t: length of the ray
// d: distance function
float d = 1.0;
float t = 0.0;
const float h = 0.1;
float4 sum = float4( 0, 0, 0, 0 );
float min_dist = 0.0, max_dist = 0.0;
if( RaySphereIntersect( ro, rd, min_dist, max_dist ) )
{
t = min_dist * step( t, min_dist );
// raymarch loop
for( int i = 0; i < 56; i++ )
{
float3 pos = ro + t * rd;
// Loop break conditions.
if( td > 0.9 || d<0.1*t || t>10.0 || sum.a > 0.99 || t > max_dist )
{
break;
}
// evaluate distance function
float d = map( pos );
// change this string to control density
d = max( d, 0.08 );
// point light calculations
float3 ldst = float3( 0, 0, 0 ) - pos;
float lDist = max( length( ldst ), 0.001 );
// star in center
float3 lightColor = float3( 1.0, 0.5, 0.25 );
sum.rgb += (lightColor / (lDist*lDist) / 30.); // star itself and bloom around the light
if( d < h )
{
// compute local density
ld = h - d;
// compute weighting factor
w = (1. - td) * ld;
// accumulate density
td += w + 1. / 200.;
float4 col = float4( computeColor( td, lDist ), td );
// uniform scale density
col.a *= 0.185;
// colour by alpha
col.rgb *= col.a;
// alpha blend in contribution
sum = sum + col * (1.0 - sum.a);
}
td += 1.0 / 70.0;
// enforce minimum step size
d = max( d, 0.04 );
// add in noise to reduce banding and create fuzz
d = abs( d ) * (0.8 + 0.2 * rand( seed * float2(i, i) ));
// trying to optimize step size near the camera and near the light source
t += max( d * 0.1 * max( min( length( ldst ), length( ro ) ), 1.0 ), 0.02 );
}
// simple scattering
sum *= 1.0 / exp( ld * 0.2 ) * 0.6;
sum = clamp( sum, 0.0, 1.0 );
sum.xyz = sum.xyz * sum.xyz * (3.0 - 2.0 * sum.xyz);
}
float4 fragColor = float4( ToneMapFilmicALU( sum.xyz * 2.2 ), 1.0 );
fixed4 colorTex = tex2D( _MainTex, input.uv );
return fragColor;
}
ENDCG
}
}
}
@StagPoint
Copy link
Author

Noise texture used during testing

noise

@StagPoint
Copy link
Author

Screenshot:

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment