Cũng là một câu hỏi cũ và đã được trả lời nhưng tôi muốn thêm giải pháp của tôi để bắt đầu xem xét trên mạng. Có plaing cùng tán xạ khí quyển và GLSL trong một thời gian dài và đến phiên bản Giản VEEERRRYYY này (nếu hoạt hình dừng trang làm mới hoặc xem GIF trong một cái gì đó hơn decend):
[
- hành tinh là và ellipsoid (trung tâm x, y, z và bán kính rx, ry, rz)
- bầu không khí cũng là elip (giống nhau nhưng lớn hơn bởi chiều cao không khí)
- tất cả kết xuất được thực hiện bình thường nhưng trên đầu trang được thêm 1 lần cho hành tinh quan sát gần
- mà vượt qua là quad đơn bao trùm toàn bộ màn hình
- bên trong đoạn nó tính toán giao điểm của tia pixel với những 2 ellipsoids
- mất phần nhìn thấy được (không phải phía sau, không phải sau khi mặt đất)
- tính toán chiều dài ray bầu không khí bên trong
- bóp méo màu gốc như chức năng của r, g, b params nhân theo tỷ lệ chiều dài ray (cái gì đó như tích hợp dọc theo đường dẫn)
- một số màu sắc được thực hiện một số trao ...
- rất ảnh hưởng đến màu sắc để có thể của nó để mô phỏng bầu khí quyển khác nhau bằng cách chỉ vài thuộc tính
- nó hoạt động tốt bên trong và cũng bên ngoài bầu khí quyển (từ khoảng cách)
- có thể thêm sao gần như là nguồn ánh sáng (tôi sử dụng tối đa 3 sao hệ thống)
kết quả là nhìn thấy hình ảnh tuyệt đẹp dưới đây:
Vertex:
/* SSH GLSL Atmospheric Ray light scattering ver 3.0
glEnable(GL_BLEND);
glBlendFunc(GL_ONE,GL_ONE);
use with single quad covering whole screen
no Modelview/Projection/Texture matrixes used
gl_Normal is camera direction in ellipsoid space
gl_Vertex is pixel in ellipsoid space
gl_Color is pixel pos in screen space <-1,+1>
const int _lights=3;
uniform vec3 light_dir[_lights]; // direction to local star in ellipsoid space
uniform vec3 light_col[_lights]; // local star color * visual intensity
uniform vec4 light_posr[_lights]; // local star position and radius^-2 in ellipsoid space
uniform vec4 B0; // atmosphere scattering coefficient (affects color) (r,g,b,-)
[ToDo:]
add light map texture for light source instead of uniform star colide parameters
- all stars and distant planets as dots
- near planets ??? maybe too slow for reading pixels
aspect ratio correction
*/
varying vec3 pixel_nor; // camera direction in ellipsoid space
varying vec4 pixel_pos; // pixel in ellipsoid space
void main(void)
{
pixel_nor=gl_Normal;
pixel_pos=gl_Vertex;
gl_Position=gl_Color;
}
Fragment:
varying vec3 pixel_nor; // camera direction in ellipsoid space
varying vec4 pixel_pos; // pixel in ellipsoid space
uniform vec3 planet_r; // rx^-2,ry^-2,rz^-2 - surface
uniform vec3 planet_R; // Rx^-2,Ry^-2,Rz^-2 - atmosphere
uniform float planet_h; // atmoshere height [m]
uniform float view_depth; // max. optical path length [m] ... saturation
// lights are only for local stars-atmosphere ray colision to set start color to star color
const int _lights=3;
uniform vec3 light_dir[_lights]; // direction to local star in ellipsoid space
uniform vec3 light_col[_lights]; // local star color * visual intensity
uniform vec4 light_posr[_lights]; // local star position and radius^-2 in ellipsoid space
uniform vec4 B0; // atmosphere scattering coefficient (affects color) (r,g,b,-)
// compute length of ray(p0,dp) to intersection with ellipsoid((0,0,0),r) -> view_depth_l0,1
// where r.x is elipsoid rx^-2, r.y = ry^-2 and r.z=rz^-2
float view_depth_l0=-1.0,view_depth_l1=-1.0;
bool _view_depth(vec3 p0,vec3 dp,vec3 r)
{
float a,b,c,d,l0,l1;
view_depth_l0=-1.0;
view_depth_l1=-1.0;
a=(dp.x*dp.x*r.x)
+(dp.y*dp.y*r.y)
+(dp.z*dp.z*r.z); a*=2.0;
b=(p0.x*dp.x*r.x)
+(p0.y*dp.y*r.y)
+(p0.z*dp.z*r.z); b*=2.0;
c=(p0.x*p0.x*r.x)
+(p0.y*p0.y*r.y)
+(p0.z*p0.z*r.z)-1.0;
d=((b*b)-(2.0*a*c));
if (d<0.0) return false;
d=sqrt(d);
l0=(-b+d)/a;
l1=(-b-d)/a;
if (abs(l0)>abs(l1)) { a=l0; l0=l1; l1=a; }
if (l0<0.0) { a=l0; l0=l1; l1=a; }
if (l0<0.0) return false;
view_depth_l0=l0;
view_depth_l1=l1;
return true;
}
// determine if ray (p0,dp) hits a sphere ((0,0,0),r)
// where r is (sphere radius)^-2
bool _star_colide(vec3 p0,vec3 dp,float r)
{
float a,b,c,d,l0,l1;
a=(dp.x*dp.x*r)
+(dp.y*dp.y*r)
+(dp.z*dp.z*r); a*=2.0;
b=(p0.x*dp.x*r)
+(p0.y*dp.y*r)
+(p0.z*dp.z*r); b*=2.0;
c=(p0.x*p0.x*r)
+(p0.y*p0.y*r)
+(p0.z*p0.z*r)-1.0;
d=((b*b)-(2.0*a*c));
if (d<0.0) return false;
d=sqrt(d);
l0=(-b+d)/a;
l1=(-b-d)/a;
if (abs(l0)>abs(l1)) { a=l0; l0=l1; l1=a; }
if (l0<0.0) { a=l0; l0=l1; l1=a; }
if (l0<0.0) return false;
return true;
}
// compute atmosphere color between ellipsoids (planet_pos,planet_r) and (planet_pos,planet_R) for ray(pixel_pos,pixel_nor)
vec3 atmosphere()
{
const int n=8;
const float _n=1.0/float(n);
int i;
bool b0,b1;
vec3 p0,p1,dp,p,c,b;
// c - color of pixel from start to end
float l0,l1,l2,h,dl;
c=vec3(0.0,0.0,0.0);
b0=_view_depth(pixel_pos.xyz,pixel_nor,planet_r);
if ((b0)&&(view_depth_l0>0.0)&&(view_depth_l1<0.0)) return c;
l0=view_depth_l0;
b1=_view_depth(pixel_pos.xyz,pixel_nor,planet_R);
l1=view_depth_l0;
l2=view_depth_l1;
dp=pixel_nor;
p0=pixel_pos.xyz;
if (!b0)
{ // outside surface
if (!b1) return c; // completly outside planet
if (l2<=0.0) // inside atmosphere to its boundary
{
l0=l1;
}
else{ // throu atmosphere from boundary to boundary
p0=p0+(l1*dp);
l0=l2-l1;
}
// if a light source is in visible path then start color is light source color
for (i=0;i<_lights;i++)
if (light_posr[i].a<=1.0)
if (_star_colide(p0-light_posr[i].xyz,dp,light_posr[i].a))
c+=light_col[i];
}
else{ // into surface
if (l0<l1) b1=false; // atmosphere is behind surface
if (!b1) // inside atmosphere to surface
{
l0=l0;
}
else{ // from atmosphere boundary to surface
p0=p0+(l1*dp);
l0=l0-l1;
}
}
dp*=l0;
p1=p0+dp;
dp*=_n;
/*
p=normalize(p1);
h=0.0; l2=0.0;
for (i=0;i<_lights;i++)
if (light_posr[i].a<=1.0)
{
dl=dot(pixel_nor,light_dir[i]); // cos(ang: light-eye)
if (dl<0.0) dl=0.0;
h+=dl;
dl=dot(p,light_dir[i]); // normal shading
if (dl<0.0) dl=0.0;
l2+=dl;
}
if (h>1.0) h=1.0;
if (l2>1.0) l2=1.0;
h=0.5*(2.0+(h*h));
*/
float qqq=dot(normalize(p1),light_dir[0]);
dl=l0*_n/view_depth;
for (p=p1,i=0;i<n;p-=dp,i++) // p1->p0 path throu atmosphere from ground
{
_view_depth(p,normalize(p),planet_R); // view_depth_l0=depth above atmosphere top [m]
h=exp(view_depth_l0/planet_h)/2.78;
b=B0.rgb*h*dl;
c.r*=1.0-b.r;
c.g*=1.0-b.g;
c.b*=1.0-b.b;
c+=b*qqq;
}
if (c.r<0.0) c.r=0.0;
if (c.g<0.0) c.g=0.0;
if (c.b<0.0) c.b=0.0;
h=0.0;
if (h<c.r) h=c.r;
if (h<c.g) h=c.g;
if (h<c.b) h=c.b;
if (h>1.0)
{
h=1.0/h;
c.r*=h;
c.g*=h;
c.b*=h;
}
return c;
}
void main(void)
{
gl_FragColor.rgb=atmosphere();
}
Xin lỗi nhưng một nguồn thực sự cũ của tôi ... có lẽ nên được chuyển đổi vào hồ sơ của lõi
[ Chỉnh sửa 1] xin lỗi quên thêm các hằng số phân tán đầu vào của tôi cho bầu khí quyển Trái đất
double view_depth=1000000.0; // [m] ... longer path is saturated atmosphere color
double ha=40000.0; // [m] ... usable atmosphere height (higher is too low pressure)
// this is how B0 should be computed (for real atmospheric scattering with nested volume integration)
// const float lambdar=650.0*0.000000001; // wavelengths for R,G,B rays
// const float lambdag=525.0*0.000000001;
// const float lambdab=450.0*0.000000001;
// double r=1.0/(lambdar*lambdar*lambdar*lambdar); // B0 coefficients
// double g=1.0/(lambdag*lambdag*lambdag*lambdag);
// double b=1.0/(lambdab*lambdab*lambdab*lambdab);
// and these are my empirical coefficients for earth like
// blue atmosphere with my simplified integration style
// images above are rendered with this:
float r=0.198141888310295;
float g=0.465578010163675;
float b=0.862540960504986;
float B0=2.50000E-25;
i=glGetUniformLocation(ShaderProgram,"planet_h"); glUniform1f(i,ha);
i=glGetUniformLocation(ShaderProgram,"view_depth"); glUniform1f(i,view_depth);
i=glGetUniformLocation(ShaderProgram,"B0"); glUniform4f(i,r,g,b,B0);
// all other atributes are based on position and size of planet and are
// pretty straightforward so here is just the earth size i use ...
double r_equator=6378141.2; // [m]
double r_poles=6356754.8; // [m]
[edit2] 2014/09/03 mã nguồn mới
tôi đã có một số thời gian gần đây để thực hiện zoom vào công cụ mỏ và đã tìm ra rằng mã nguồn gốc không phải là rất chính xác từ khoảng cách trên 0,002 AU. Nếu không có Zoom nó chỉ là một vài điểm ảnh để không có gì được nhìn thấy, nhưng với zoom tất cả các thay đổi vì vậy tôi đã cố gắng để cải thiện độ chính xác nhiều nhất có thể.
Sau một vài tinh chỉnh tôi càng làm cho nó được sử dụng lên đến 25,0 AU và với các đồ tạo tác nội suy lên đến 50,0-100,0 AU. Đó là giới hạn cho HW hiện tại vì tôi không thể vượt qua phi flat fp64
để nội suy từ đỉnh đến đoạn. Một cách có thể là di chuyển hệ tọa độ biến đổi thành mảnh nhưng chưa thử nó. Dưới đây là một số thay đổi:
- nguồn mới sử dụng 64 bit nổi
- và thêm
uniform int lights
đó là đếm đèn đã qua sử dụng
- cũng có một số thay đổi trong ý nghĩa B0 (họ bước sóng không còn thường xuyên phụ thuộc nhưng màu sắc thay vì) vì vậy bạn cần phải thay đổi giá trị thống nhất điền vào mã CPU một chút.
- một số cải tiến hiệu suất đã được bổ sung
[đỉnh]
/* SSH GLSL Atmospheric Ray light scattering ver 3.1
glEnable(GL_BLEND);
glBlendFunc(GL_ONE,GL_ONE_MINUS_SRC_ALPHA);
use with single quad covering whole screen
no Modelview/Projection/Texture matrixes used
gl_Normal is camera direction in ellipsoid space
gl_Vertex is pixel in ellipsoid space
gl_Color is pixel pos in screen space <-1,+1>
const int _lights=3;
uniform int lights; // actual number of lights
uniform vec3 light_dir[_lights]; // direction to local star in ellipsoid space
uniform vec3 light_col[_lights]; // local star color * visual intensity
uniform vec4 light_posr[_lights]; // local star position and radius^-2 in ellipsoid space
uniform vec4 B0; // atmosphere scattering coefficient (affects color) (r,g,b,-)
[ToDo:]
add light map texture for light source instead of uniform star colide parameters
- all stars and distant planets as dots
- near planets ??? maybe too slow for reading pixels
aspect ratio correction
*/
varying vec3 pixel_nor; // camera direction in ellipsoid space
varying vec4 pixel_pos; // pixel in ellipsoid space
varying vec4 pixel_scr; // pixel in screen space <-1,+1>
varying vec3 p_r; // rx,ry,rz
uniform vec3 planet_r; // rx^-2,ry^-2,rz^-2 - surface
void main(void)
{
p_r.x=1.0/sqrt(planet_r.x);
p_r.y=1.0/sqrt(planet_r.y);
p_r.z=1.0/sqrt(planet_r.z);
pixel_nor=gl_Normal;
pixel_pos=gl_Vertex;
pixel_scr=gl_Color;
gl_Position=gl_Color;
}
[fragment]
#extension GL_ARB_gpu_shader_fp64 : enable
double abs(double x) { if (x<0.0) x=-x; return x; }
varying vec3 pixel_nor; // camera direction in ellipsoid space
varying vec4 pixel_pos; // pixel in ellipsoid space
varying vec4 pixel_scr; // pixel in screen space
varying vec3 p_r; // rx,ry,rz
uniform vec3 planet_r; // rx^-2,ry^-2,rz^-2 - surface
uniform vec3 planet_R; // Rx^-2,Ry^-2,Rz^-2 - atmosphere
uniform float planet_h; // atmoshere height [m]
uniform float view_depth; // max. optical path length [m] ... saturation
// lights are only for local stars-atmosphere ray colision to set start color to star color
const int _lights=3;
uniform int lights; // actual number of lights
uniform vec3 light_dir[_lights]; // direction to local star in ellipsoid space
uniform vec3 light_col[_lights]; // local star color * visual intensity
uniform vec4 light_posr[_lights]; // local star position and radius^-2 in ellipsoid space
uniform vec4 B0; // atmosphere scattering color coefficients (r,g,b,ambient)
// compute length of ray(p0,dp) to intersection with ellipsoid((0,0,0),r) -> view_depth_l0,1
// where r.x is elipsoid rx^-2, r.y = ry^-2 and r.z=rz^-2
const double view_depth_max=100000000.0; // > max view depth
double view_depth_l0=-1.0, // view_depth_l0 first hit
view_depth_l1=-1.0; // view_depth_l1 second hit
bool _view_depth_l0=false;
bool _view_depth_l1=false;
bool _view_depth(vec3 _p0,vec3 _dp,vec3 _r)
{
dvec3 p0,dp,r;
double a,b,c,d,l0,l1;
view_depth_l0=-1.0; _view_depth_l0=false;
view_depth_l1=-1.0; _view_depth_l1=false;
// conversion to double
p0=dvec3(_p0);
dp=dvec3(_dp);
r =dvec3(_r);
// quadratic equation a.l.l+b.l+c=0; l0,l1=?;
a=(dp.x*dp.x*r.x)
+(dp.y*dp.y*r.y)
+(dp.z*dp.z*r.z);
b=(p0.x*dp.x*r.x)
+(p0.y*dp.y*r.y)
+(p0.z*dp.z*r.z); b*=2.0;
c=(p0.x*p0.x*r.x)
+(p0.y*p0.y*r.y)
+(p0.z*p0.z*r.z)-1.0;
// discriminant d=sqrt(b.b-4.a.c)
d=((b*b)-(4.0*a*c));
if (d<0.0) return false;
d=sqrt(d);
// standard solution l0,l1=(-b +/- d)/2.a
a*=2.0;
l0=(-b+d)/a;
l1=(-b-d)/a;
// alternative solution q=-0.5*(b+sign(b).d) l0=q/a; l1=c/q; (should be more accurate sometimes)
// if (b<0.0) d=-d; d=-0.5*(b+d);
// l0=d/a;
// l1=c/d;
// sort l0,l1 asc
if ((l0<0.0)||((l1<l0)&&(l1>=0.0))) { a=l0; l0=l1; l1=a; }
// exit
if (l1>=0.0) { view_depth_l1=l1; _view_depth_l1=true; }
if (l0>=0.0) { view_depth_l0=l0; _view_depth_l0=true; return true; }
return false;
}
// determine if ray (p0,dp) hits a sphere ((0,0,0),r)
// where r is (sphere radius)^-2
bool _star_colide(vec3 _p0,vec3 _dp,float _r)
{
dvec3 p0,dp,r;
double a,b,c,d,l0,l1;
// conversion to double
p0=dvec3(_p0);
dp=dvec3(_dp);
r =dvec3(_r);
// quadratic equation a.l.l+b.l+c=0; l0,l1=?;
a=(dp.x*dp.x*r)
+(dp.y*dp.y*r)
+(dp.z*dp.z*r);
b=(p0.x*dp.x*r)
+(p0.y*dp.y*r)
+(p0.z*dp.z*r); b*=2.0;
c=(p0.x*p0.x*r)
+(p0.y*p0.y*r)
+(p0.z*p0.z*r)-1.0;
// discriminant d=sqrt(b.b-4.a.c)
d=((b*b)-(4.0*a*c));
if (d<0.0) return false;
d=sqrt(d);
// standard solution l0,l1=(-b +/- d)/2.a
a*=2.0;
l0=(-b+d)/a;
l1=(-b-d)/a;
// alternative solution q=-0.5*(b+sign(b).d) l0=q/a; l1=c/q; (should be more accurate sometimes)
// if (b<0.0) d=-d; d=-0.5*(b+d);
// l0=d/a;
// l1=c/d;
// sort l0,l1 asc
if (abs(l0)>abs(l1)) { a=l0; l0=l1; l1=a; }
if (l0<0.0) { a=l0; l0=l1; l1=a; }
if (l0<0.0) return false;
return true;
}
// compute atmosphere color between ellipsoids (planet_pos,planet_r) and (planet_pos,planet_R) for ray(pixel_pos,pixel_nor)
vec4 atmosphere()
{
const int n=8;
const float _n=1.0/float(n);
int i;
bool b0,b1;
vec3 p0,p1,dp,p,b;
vec4 c; // c - color of pixel from start to end
float h,dl,ll;
double l0,l1,l2;
bool e0,e1,e2;
c=vec4(0.0,0.0,0.0,0.0); // a=0.0 full background color, a=1.0 no background color (ignore star)
b1=_view_depth(pixel_pos.xyz,pixel_nor,planet_R);
if (!b1) return c; // completly outside atmosphere
e1=_view_depth_l0; l1=view_depth_l0; // first atmosphere hit
e2=_view_depth_l1; l2=view_depth_l1; // second atmosphere hit
b0=_view_depth(pixel_pos.xyz,pixel_nor,planet_r);
e0=_view_depth_l0; l0=view_depth_l0; // first surface hit
if ((b0)&&(view_depth_l1<0.0)) return c; // under ground
// set l0 to view depth and p0 to start point
dp=pixel_nor;
p0=pixel_pos.xyz;
if (!b0) // outside surface
{
if (!e2) // inside atmosphere to its boundary
{
l0=l1;
}
else{ // throu atmosphere from boundary to boundary
p0=vec3(dvec3(p0)+(dvec3(dp)*l1));
l0=l2-l1;
}
// if a light source is in visible path then start color is light source color
for (i=0;i<lights;i++)
if (_star_colide(p0.xyz-light_posr[i].xyz,dp.xyz,light_posr[i].a*0.75)) // 0.75 is enlargment to hide star texture corona
{
c.rgb+=light_col[i];
c.a=1.0; // ignore already drawed local star color
}
}
else{ // into surface
if (l1<l0) // from atmosphere boundary to surface
{
p0=vec3(dvec3(p0)+(dvec3(dp)*l1));
l0=l0-l1;
}
else{ // inside atmosphere to surface
l0=l0;
}
}
// set p1 to end of view depth, dp to intergral step
p1=vec3(dvec3(p0)+(dvec3(dp)*l0)); dp=p1-p0;
dp*=_n;
dl=float(l0)*_n/view_depth;
ll=B0.a; for (i=0;i<lights;i++) // compute normal shaded combined light sources into ll
ll+=dot(normalize(p1),light_dir[0]);
for (p=p1,i=0;i<n;p-=dp,i++) // p1->p0 path throu atmosphere from ground
{
// _view_depth(p,normalize(p),planet_R); // too slow... view_depth_l0=depth above atmosphere top [m]
// h=exp(view_depth_l0/planet_h)/2.78;
b=normalize(p)*p_r; // much much faster
h=length(p-b);
h=exp(h/planet_h)/2.78;
b=B0.rgb*h*dl;
c.r*=1.0-b.r;
c.g*=1.0-b.g;
c.b*=1.0-b.b;
c.rgb+=b*ll;
}
if (c.r<0.0) c.r=0.0;
if (c.g<0.0) c.g=0.0;
if (c.b<0.0) c.b=0.0;
h=0.0;
if (h<c.r) h=c.r;
if (h<c.g) h=c.g;
if (h<c.b) h=c.b;
if (h>1.0)
{
h=1.0/h;
c.r*=h;
c.g*=h;
c.b*=h;
}
return c;
}
void main(void)
{
gl_FragColor.rgba=atmosphere();
}
[giá trị thống nhất]
// Earth
re=6378141.2 // equatoreal radius r.x,r.y
rp=6356754.79506139 // polar radius r.z
planet_h=60000 // atmosphere thickness R(r.x+planet_h,r.y+planet_h,r.z+planet_h)
view_depth=250000 // max view distance before 100% scattering occur
B0.r=0.1981 // 100% scattered atmosphere color
B0.g=0.4656
B0.b=0.8625
B0.a=0.75 // overglow (sky is lighter before Sun actually rise) it is added to light dot product
// Mars
re=3397000
rp=3374919.5
ha=30000
view_depth=300000
B0.r=0.4314
B0.g=0.3216
B0.b=0.196
B0.a=0.5
Để biết thêm thông (và mới hơn hình ảnh) cũng thấy liên quan:
Wow, những ví dụ là thực sự ấn tượng! Tuy nhiên, bạn nên biết rằng tôi thực sự mới với công cụ này. Trong liên kết thứ hai bạn đăng, có vẻ như có một số mã C-looking. Đây có phải là cách tôi sử dụng bóng đổ không khí đó không? Đây có phải là những gì họ gọi là 'glsl'? Làm thế nào để thực hiện điều này trong Three.js? Xin lỗi vì sự thiếu hiểu biết nghiêm trọng của tôi về chủ đề này. – Hassan
Cảm ơn bạn đã cập nhật nhanh. Tôi nghĩ rằng tôi sẽ tiếp tục và cố gắng tìm hiểu về shaders, vì chúng có vẻ quan trọng. Tuy nhiên, kể từ khi tôi phải chứng minh điều này trong khoảng một tuần, tôi không nghĩ rằng tôi sẽ có thể tìm hiểu tất cả trong khung thời gian đó. Nhưng tôi sẽ cố gắng, và như bạn nói, tôi luôn có thể tạo ra một quả cầu trong suốt. – Hassan