#version 120 const float tau = 6.28318530716; const bool parallax = #{{level:extreme}}; const bool advancedProcedurals = #{{level:high}}; // it needs special tweaks to not bleed out in overexposure bool lightShaftsOn = #{{bGodRays}}; bool bloomOn = #{{bBloom}}; // parallax scale, bias and steps const vec2 scaleBias = vec2(0.005, 0.0025); uniform sampler2D texture[2]; uniform float cycles[5]; uniform float temperature; uniform float nodeScale; varying float distortion; varying vec2 uvA, uvB; varying vec3 vertCol, normal, origo; varying vec3 v; const float maxVariance = 0.03; //should be kept low const float deviationCycles = 3.25; //How much variation is based on base color const float two_pi = 6.28318531; const float noise1Base = 0.84, noise1Range = 0.25; const float noise2Base = 0.93, noise2Range = 0.34; const float diffPower = 2.3; const float tempInfluence = 0.25; const float baseTemp = 10000.0; const float noiseOffsetNoise = 0.1; float mixRange(float x, float low, float hi) { return clamp((x - low) / (hi - low), 0.0, 1.0); } vec3 blackBody(float temp) { vec3 c; c.r = mix(1.0, 0.6234, mixRange(temp, 6400.0, 29800.0)); c.b = mix(0.0, 1.0, mixRange(temp, 2800.0, 7600.0)); if(temp < 6600.0) c.g = mix(0.22, 0.976, mixRange(temp, 1000.0, 6600.0)); else c.g = mix(0.976, 0.75, mixRange(temp, 6600.0, 29800.0)); if(temp > 13000.0) c += vec3(mixRange(temp, 13000.0, 29800.0)); return c; } vec3 dp1Calc(vec3 p) { return dFdx(p); } vec3 dp2Calc(vec3 p) { return dFdy(p); } vec4 duv1Calc(vec4 uv) { return dFdx(uv); } vec4 duv2Calc(vec4 uv) { return dFdy(uv); } float pow4(float x){ x*= x; return x*x; } /* float mip_map_level(vec2 uv) { vec2 dx_vtc = dFdx(uv); vec2 dy_vtc = dFdy(uv); float delta_max_sqr = max(dot(dx_vtc, dx_vtc), dot(dy_vtc, dy_vtc)); //return max(0.0, 0.5 * log2(delta_max_sqr) - 1.0); // == log2(sqrt(delta_max_sqr)); return 0.5 * log2(delta_max_sqr); // == log2(sqrt(delta_max_sqr)); } */ float starSampMip(vec2 uv, float mip){ vec2 noiseCoord = uv * 3.0 + (texture2D(texture[1], uv * 16.0, mip).xz - vec2(0.5)) * noiseOffsetNoise; noiseCoord += vec2( cycles[0], cycles[1]); vec2 noise2Coord = noiseCoord + vec2( -cycles[3], cycles[4] ); vec2 noise3Coord = noiseCoord + vec2( -cycles[2], cycles[3] * 4.0 ); vec2 noise4Coord = noiseCoord * 2.0 + vec2( cycles[4], cycles[0] * -2.0 ); noiseCoord += vec2( cycles[1], cycles[2] ); float heat = noise1Base + noise1Range * texture2D(texture[1], uv * 4.0, mip).r; heat *= noise2Base + noise2Range * texture2D(texture[0], noise2Coord, mip).g; heat *= noise2Base + noise2Range * texture2D(texture[0], noise3Coord, mip).b; heat *= noise1Base + noise1Range * texture2D(texture[1], noise4Coord, mip).g; return heat; } float starSamp(vec2 uv){ vec2 noiseCoord =uv * 3.0 + (texture2D(texture[1], uv * 16.0).xz - vec2(0.5)) * noiseOffsetNoise; noiseCoord += vec2( cycles[0], cycles[1]); vec2 noise2Coord = noiseCoord + vec2( -cycles[3], cycles[4] ); vec2 noise3Coord = noiseCoord + vec2( -cycles[2], cycles[3] * 4.0 ); vec2 noise4Coord = noiseCoord * 2.0 + vec2( cycles[4], cycles[0] * -2.0 ); noiseCoord += vec2( cycles[1], cycles[2] ); float heat = noise1Base + noise1Range * texture2D(texture[1], uv * 4.0).r; heat *= noise2Base + noise2Range * texture2D(texture[0], noise2Coord).g; heat *= noise2Base + noise2Range * texture2D(texture[0], noise3Coord).b; heat *= noise1Base + noise1Range * texture2D(texture[1], noise4Coord).g; return heat; } void main() { vec4 uvP = vec4(uvA, uvB); // do polar blend mask from world space normals float blendMask = clamp(abs(normal.y)* 4.0 - 2.0, 0.0, 1.0); float NdotV = max(0.0, dot(normal, v)); float heat = 0.0; if (parallax){ // star surface to noisy to work for parallax, so sample mip-blurred for approximate softened plumes heat = mix(starSampMip(uvB, 5.0), starSampMip(uvA, 5.0), blendMask); // make the parallax a little more interesting heat = pow4(abs(fract(heat) * 2.0 - 1.0)); // and smoothstep heat *= heat * (3.0 - (2.0 * heat)); vec3 dp1 = dp1Calc(-v); vec3 dp2 = dp2Calc(-v); // derive for both uv's vec4 duv1 = duv1Calc(uvP); vec4 duv2 = duv2Calc(uvP); vec3 dp2perp = cross(dp2, normal); vec3 dp1perp = cross(normal, dp1); // do parallax float fDet = dot(dp1, dp2perp); vec2 vProjVScr = (1.0/fDet) * vec2(dot(dp2perp, v), dot(dp1perp, v)); vec4 vProjVTex = (duv1 * vProjVScr.x + duv2 * vProjVScr.y); float vProjVTexZ = NdotV * ((1.0 - heat - 0.5) * scaleBias.r - scaleBias.g); uvP += (vProjVTex * vProjVTexZ); heat = mix(starSamp(uvP.zw), starSamp(uvP.xy), blendMask); } else{ heat = mix(starSamp(uvB), starSamp(uvA), blendMask); } heat -=1.1; if(temperature < 3500.0) { heat += 0.05; if(heat < 0.0) heat *= 2.0; else heat *= 22.0 - (temperature / 350.0); } else if(temperature < 6500.0) { heat *= 4.0; } else if(temperature > 20000.0) { heat *= 5.0; } else { heat += 0.05; if(heat < 0.0) heat *= 2.0; else heat *= 20.0; } heat = mix(heat, 0.7, pow(max(distortion,0.0), 2.8)); heat = mix(0.6, heat, NdotV) + 1.0; gl_FragColor.rgb = blackBody(temperature * heat) * clamp(heat, min(temperature / 2500.0, 1.0), 1.0); gl_FragColor.a = 1.0; }