Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
262 changes: 180 additions & 82 deletions blackhole/main.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// blackhole/main.cpp
#ifdef __APPLE__
#define GL_SILENCE_DEPRECATION
#include <OpenGL/gl3.h>
Expand Down Expand Up @@ -30,11 +31,14 @@ out vec4 FragColor;
in vec2 uv;
uniform float t;
uniform vec3 cam;
uniform vec2 res;

const float sr = 0.15;
const float eh = 0.2;
const float di = 0.4;
const float do_ = 3.5;
const float sr = 0.12;
const float eh = 0.18;
const float di = 0.35;
const float do_ = 4.5;
const int MAX_STEPS = 256;
const int LIGHT_SAMPLES = 4;

float h(vec2 p){return fract(sin(dot(p,vec2(127.1,311.7)))*43758.5453);}
float h3(vec3 p){return fract(sin(dot(p,vec3(127.1,311.7,74.7)))*43758.5453);}
Expand All @@ -50,114 +54,207 @@ float fbm(vec2 p){
float val=0,amp=.5,freq=1;
for(int i=0;i<6;i++){
val+=amp*n(p*freq);
freq*=2;amp*=.5;
freq*=2.1;amp*=.48;
}
return val;
}

float fbm3(vec3 p){
float val=0,amp=.5;
for(int i=0;i<4;i++){
val+=amp*(h3(p)-.5);
p*=2.1;amp*=.5;
}
return val*.5+.5;
}

float getDensity(vec3 pos,float r){
float dh=abs(pos.y);
float dt=.4+.25*sin(t*.8);
if(dh>=dt||r<=di||r>=do_)return 0.;

float dn=(r-di)/(do_-di);
float av=(1./pow(dn+.05,0.4))*4.2;
float ang=atan(pos.z,pos.x)+t*av;

vec2 tc=vec2(ang*9.+t*1.6,dn*24);
float turb=fbm(tc);

vec3 p3=pos*4.;
float turb3d=fbm3(p3+t*.4);

float sp=sin(ang*22-dn*32+t*7.)*.5+.5;
float sp2=sin(ang*28+dn*22-t*5.5)*.5+.5;

float hf=1.-pow(dh/dt,1.1);
float dens=turb*turb3d*hf*(.75+sp*.25);
dens*=(1.-pow(dn,.55));

float hs=n(vec2(ang*14+t*3.5,dn*16));
float flare=n(vec2(ang*6-t*2.2,dn*9));

if(hs>.75) dens*=7.+sin(t*22.)*2.5;
if(flare>.83) dens*=5.+sp2*3.5;

return dens;
}

vec3 getColor(vec3 pos,float r,float dens){
float dn=(r-di)/(do_-di);
float ang=atan(pos.z,pos.x)+t*3.5;

float turb=fbm(vec2(ang*9.+t*1.2,dn*22));
float sp=sin(ang*22-dn*32+t*7.)*.5+.5;
float sp2=sin(ang*28+dn*22-t*5.5)*.5+.5;
float hs=n(vec2(ang*14+t*3.5,dn*16));
float flare=n(vec2(ang*6-t*2.2,dn*9));

vec3 c;
float tmp=1.-dn;

if(tmp>.85){
c=mix(vec3(.3,.5,1.6),vec3(1.5,1.6,2.),(tmp-.85)*6.66);
c+=vec3(.2,.4,2.2)*hs*6.;
c+=vec3(.6,.8,1.8)*flare*4.;
}else if(tmp>.7){
c=mix(vec3(.1,.7,1.5),vec3(.7,1.2,1.8),(tmp-.7)*6.66);
c+=vec3(.3,1.5,2.)*turb*2.;
c+=vec3(.5,.9,1.4)*sp2*1.4;
}else if(tmp>.55){
c=mix(vec3(.6,1.2,.1),vec3(1.2,1.4,.5),(tmp-.55)*6.66);
c+=vec3(1.3,1.6,.2)*sp*1.5;
c+=vec3(.8,1.2,.4)*turb*1.2;
}else if(tmp>.4){
c=mix(vec3(1.2,.7,.05),vec3(1.4,1.1,.3),(tmp-.4)*6.66);
c+=vec3(1.8,.9,.1)*turb*1.6;
c+=vec3(1.3,.8,.15)*sp2*1.;
}else if(tmp>.25){
c=mix(vec3(1.3,.4,.02),vec3(1.4,.8,.1),(tmp-.25)*6.66);
c+=vec3(1.6,.6,.05)*sp*1.1;
}else{
c=mix(vec3(.7,.02,.05),vec3(1.3,.25,.4),tmp*4.);
c+=vec3(1.4,.1,.5)*sp*.9;
c+=vec3(.9,.05,.3)*flare*.7;
}

c.r+=turb*.5+sp*.3;
c.g+=sin(ang*24+t*3.8)*.35;
c.b+=cos(ang*30-t*4.5)*.4;

return c;
}

vec3 calcLighting(vec3 pos,vec3 d,float dens){
vec3 lightDir=normalize(vec3(.3,.8,.5));

float shadow=1.;
vec3 p=pos;
for(int i=0;i<4;i++){
p+=lightDir*.2;
float r=length(p);
float sd=getDensity(p,r);
shadow*=exp(-sd*.3);
if(shadow<.05)break;
}

float diff=max(dot(normalize(vec3(0,1,0)),lightDir),0.)*.5+.5;
float rim=pow(1.-abs(dot(d,normalize(pos))),2.)*.3;

return vec3(diff*shadow+rim);
}

vec3 march(vec3 o,vec3 d){
vec3 pos=o;
float td=0;
vec3 col=vec3(0);
float alpha=0;

for(int i=0;i<200;i++){
for(int i=0;i<MAX_STEPS;i++){
float r=length(pos);
if(r<eh) return col;

float dh=abs(pos.y);
float dt=.25+.15*sin(t*1.2);
if(r<eh){
col+=vec3(.04,.015,.08)*(1.-alpha);
return col;
}

if(dh<dt&&r>di&&r<do_){
float dn=(r-di)/(do_-di);
float av=(1./sqrt(dn+.1))*2.5;
float ang=atan(pos.z,pos.x)+t*av;

vec2 tc=vec2(ang*6+t*.8,dn*15);
float turb=fbm(tc);
float sp=sin(ang*12-dn*20+t*4)*.5+.5;
float hf=1.-dh/dt;hf=pow(hf,2);
float dens=turb*hf*(.6+sp*.4);
dens*=(1.-dn*.5);

float hs=n(vec2(ang*8+t*2,dn*10));
if(hs>.82) dens*=4.+sin(t*15);

vec3 c;
float tmp=1.-dn;

if(tmp>.75){
c=mix(vec3(.6,.7,1),vec3(1), (tmp-.75)*4);
c+=vec3(.4,.5,1.2)*hs*3;
}else if(tmp>.6){
c=mix(vec3(.3,.9,1),vec3(.9,.95,1),(tmp-.6)*6.66);
c+=vec3(.5,1,1.2)*turb*.8;
}else if(tmp>.45){
c=mix(vec3(.8,1,.3),vec3(1,1,.7),(tmp-.45)*6.66);
c+=vec3(1,1,.4)*sp*.6;
}else if(tmp>.3){
c=mix(vec3(1,.6,.1),vec3(1,.9,.4),(tmp-.3)*6.66);
c+=vec3(1.2,.7,.2)*turb*.7;
}else{
c=mix(vec3(.5,.05,.1),vec3(1,.3,.5),tmp*3.33);
c+=vec3(1,.2,.6)*sp*.5;
}

c.r+=turb*.3;
c.g+=sin(ang*15+t*2)*.2;
c.b+=cos(ang*20-t*3)*.25;
float dens=getDensity(pos,r);

if(dens>.01){
vec3 c=getColor(pos,r,dens);
vec3 light=calcLighting(pos,d,dens);

float br=dens*(3+tmp*4);
br*=(1+sin(t*5+ang*8)*.5);
float tmp=1.-(r-di)/(do_-di);
float br=dens*(5.5+tmp*7.5);
br*=(1.+sin(t*9.+atan(pos.z,pos.x)*15.)*.75);
br*=(1.+cos(atan(pos.z,pos.x)*8.-t*3.)*.5);

vec3 dc=c*br;
float a=dens*.15;
col+=dc*a*(1-alpha);
alpha+=a*(1-alpha);
if(alpha>.95)break;
vec3 dc=c*br*light;
float a=dens*.25;
col+=dc*a*(1.-alpha);
alpha+=a*(1.-alpha);
if(alpha>.98)break;
}

float g=(sr*sr)/(r*r+.01);
float g=(sr*sr)/(r*r+.006);
vec3 gd=-normalize(pos);
d=normalize(d+gd*g*.4);
d=normalize(d+gd*g*.5);

float step=.03+r*.015;
if(r>di-.5&&r<do_+.5)step*=.4;
float step=.02+r*.01;
if(r>di-.7&&r<do_+.7)step*=.3;
pos+=d*step;
td+=step;
if(td>25)break;
if(td>35)break;
}

vec3 sd=normalize(d);
float sn=h(sd.xy*200+sd.z*100);
if(sn>.997){
float sb=(sn-.997)*1000;
vec3 sc=mix(vec3(1,.9,.8),vec3(.8,.9,1),h(sd.yz*123));
col+=sc*sb*(1-alpha);
float sn=h(sd.xy*280+sd.z*150);
if(sn>.9978){
float sb=(sn-.9978)*2000;
vec3 sc=mix(vec3(1.,.96,.88),vec3(.88,.96,1.),h(sd.yz*165));
float twinkle=.65+.35*sin(sn*1200.+t*6.);
col+=sc*sb*twinkle*(1.-alpha);
}

float bg=fbm(sd.xy*3+t*.05)*.03;
col+=vec3(.1,.05,.15)*bg*(1-alpha);
col+=vec3(.002,.003,.01)*(1-alpha);
float bg=fbm(sd.xy*5.+t*.025)*.05;
vec3 nebula=mix(vec3(.06,.03,.1),vec3(.1,.05,.15),bg);
nebula+=vec3(.02,.01,.03)*fbm(sd.yz*3.-t*.02);
col+=nebula*(1.-alpha);

col+=vec3(.0008,.0015,.006)*(1.-alpha);
return col;
}

void main(){
vec2 uv_=(uv-.5)*2;
uv_.x*=res.x/res.y;

vec3 ro=cam;
vec3 tgt=vec3(0);
vec3 fwd=normalize(tgt-ro);
vec3 rt=normalize(cross(vec3(0,1,0),fwd));
vec3 up=cross(fwd,rt);
vec3 rd=normalize(fwd+uv_.x*rt+uv_.y*up);

vec3 c=march(ro,rd);
c=c/(c+vec3(.5));
c=pow(c,vec3(.9));
c=pow(c,vec3(1./2.2));
c.r=pow(c.r,.95);
c.b=pow(c.b,1.05);
FragColor=vec4(c,1);
vec3 col=march(ro,rd);

// Advanced tone mapping (ACES filmic)
col*=2.2;
vec3 a=col*(col+.0245786)-.000090537;
vec3 b=col*(.983729*col+.4329510)+.238081;
col=a/b;

// Color grading
col=pow(col,vec3(.82));
col.r=pow(col.r,.88);
col.g=pow(col.g,.92);
col.b=pow(col.b,1.15);

// Subtle vignette
float vig=1.-length(uv_*.28);
vig=pow(vig,1.4);
col*=.25+vig*.75;

FragColor=vec4(col,1);
}
)";

Expand Down Expand Up @@ -205,7 +302,7 @@ int main(){
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR,3);
glfwWindowHint(GLFW_OPENGL_PROFILE,GLFW_OPENGL_CORE_PROFILE);

GLFWwindow* win=glfwCreateWindow(1600,900,"Black Hole",nullptr,nullptr);
GLFWwindow* win=glfwCreateWindow(1600,900,"Black Hole - Ultra Quality",nullptr,nullptr);
if(!win){
std::cerr<<"Window fail"<<std::endl;
glfwTerminate();
Expand Down Expand Up @@ -254,6 +351,13 @@ int main(){
if(glfwGetKey(win,GLFW_KEY_ESCAPE)==GLFW_PRESS)
glfwSetWindowShouldClose(win,true);

float tm=glfwGetTime();
float spd=tm*.6f,inw=tm*.12f;
float rad=fmax(5.5f-inw,1.2f);
float ang=spd*1.8f;
float cx=cos(ang)*rad,cz=sin(ang)*rad;
float cy=.45f+sin(spd*.4f)*.25f;

int w,h;
glfwGetFramebufferSize(win,&w,&h);
float asp=(float)w/(float)h;
Expand All @@ -263,15 +367,9 @@ int main(){
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(prog);

float tm=glfwGetTime();
float spd=tm*.8f,inw=tm*.15f;
float rad=fmax(5.0f-inw,.8f);
float ang=spd*2.0f;
float cx=cos(ang)*rad,cz=sin(ang)*rad;
float cy=.3f+sin(spd*.5f)*.5f;

glUniform1f(glGetUniformLocation(prog,"t"),tm);
glUniform3f(glGetUniformLocation(prog,"cam"),cx,cy,cz);
glUniform2f(glGetUniformLocation(prog,"res"),(float)w,(float)h);
glUniformMatrix4fv(glGetUniformLocation(prog,"m"),1,GL_FALSE,glm::value_ptr(mdl));
glUniformMatrix4fv(glGetUniformLocation(prog,"v"),1,GL_FALSE,glm::value_ptr(view));
glUniformMatrix4fv(glGetUniformLocation(prog,"p"),1,GL_FALSE,glm::value_ptr(proj));
Expand Down
1 change: 1 addition & 0 deletions build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ switch ($choice) {
"1" {
$exe = "blackhole"
$title = "Blackhole Simulation"
Write-Host "`n Press ESC to exit"
}
"2" {
$exe = "fractal"
Expand Down
2 changes: 2 additions & 0 deletions build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ case $choice in
1)
exe="blackhole"
title="Blackhole Simulation"
echo ""
echo "Press ESC to exit"
;;
2)
exe="fractal"
Expand Down