Hello everyone!
I’m programming a little space sim. Right
now, i’m including planets and i’d like
them to have a nice athmosphere-effect.
Since i have no experience with shader-programming,
i’d like to include a piece of code from the
GLScene “Earth”-Demo in my game. There you
can see the Earth from space with a very nice
athmosphere.
The Atmosphere is a bunch of GL_QUAD_STRIPS and
GL_TRIANGLE_FANS that are originated at (0,0,0).
They build the atmosphere as a kind of sphere
around the sphere that is the earth. Its stored
in “pVertex”.
I would now like to move this atmosphere-sphere
to another point, but i don’t know how, because
i have no experience with 3D-Math.
Hopefully, if i post the source here, somebode
can help me.
(Sorry for my awful english )
The Source code:
procedure TForm1.GLDirectOpenGL1Render(Sender: TObject; var rci: TRenderContextInfo);
const
// unrealisticly thick atmospheres look better :)
cAtmosphereRadius : Single = 0.55;
// use value slightly lower than actual radius, for antialiasing effect
cPlanetRadius : Single = 0.495;
cLowAtmColor : TColorVector = (1, 1, 1, 1);
cHighAtmColor : TColorVector = (0, 0, 1, 1);
cOpacity : Single = 5;
cIntDivTable : array [2..20] of Single =
(1/2, 1/3, 1/4, 1/5, 1/6, 1/7, 1/8, 1/9, 1/10,
1/11, 1/12, 1/13, 1/14, 1/15, 1/16, 1/17, 1/18, 1/19, 1/20);
var
radius, invAtmosphereHeight : Single;
sunPos, eyePos, lightingVector : TVector;
diskNormal, diskRight, diskUp : TVector;
function AtmosphereColor(const rayStart, rayEnd : TVector) : TColorVector;
var
i, n : Integer;
atmPoint, normal : TVector;
altColor : TColorVector;
alt, rayLength, contrib, decay, intensity, invN : Single;
begin
Result:=clrTransparent;
rayLength:=VectorDistance(rayStart, rayEnd);
n:=Round(3*rayLength*invAtmosphereHeight)+2;
if n>10 then n:=10;
invN:=cIntDivTable[n];//1/n;
contrib:=rayLength*invN*cOpacity;
decay:=1-contrib*0.5;
contrib:=contrib*(1/1.1);
for i:=n-1 downto 0 do begin
VectorLerp(rayStart, rayEnd, i*invN, atmPoint);
// diffuse lighting normal
normal:=VectorNormalize(atmPoint);
// diffuse lighting intensity
intensity:=VectorDotProduct(normal, lightingVector)+0.1;
if PInteger(@intensity)^>0 then begin
// sample on the lit side
intensity:=intensity*contrib;
alt:=(VectorLength(atmPoint)-cPlanetRadius)*invAtmosphereHeight;
VectorLerp(cLowAtmColor, cHighAtmColor, alt, altColor);
Result[0]:=Result[0]*decay+altColor[0]*intensity;
Result[1]:=Result[1]*decay+altColor[1]*intensity;
Result[2]:=Result[2]*decay+altColor[2]*intensity;
end else begin
// sample on the dark sid
Result[0]:=Result[0]*decay;
Result[1]:=Result[1]*decay;
Result[2]:=Result[2]*decay;
end;
end;
Result[3]:=n*contrib*cOpacity*0.1;
end;
function ComputeColor(var rayDest : TVector; mayHitGround : Boolean) : TColorVector;
var
ai1, ai2, pi1, pi2 : TVector;
rayVector : TVector;
begin
rayVector:=VectorNormalize(VectorSubtract(rayDest, eyePos));
if RayCastSphereIntersect(eyePos, rayVector, NullHmgPoint, cAtmosphereRadius, ai1, ai2)>1 then begin
// atmosphere hit
if mayHitGround and (RayCastSphereIntersect(eyePos, rayVector, NullHmgPoint, cPlanetRadius, pi1, pi2)>0) then begin
// hit ground
Result:=AtmosphereColor(ai1, pi1);
end else begin
// through atmosphere only
Result:=AtmosphereColor(ai1, ai2);
end;
rayDest:=ai1;
end else Result:=clrTransparent;
end;
const
cSlices = 60;
var
i, j, k0, k1 : Integer;
cosCache, sinCache : array [0..cSlices] of Single;
pVertex, pColor : PVectorArray;
tmp:TVector;
begin
sunPos:=LSSun.AbsolutePosition;
eyepos:=GLCamera.AbsolutePosition;
diskNormal:=VectorNegate(eyePos);
NormalizeVector(diskNormal);
diskRight:=VectorCrossProduct(GLCamera.AbsoluteUp, diskNormal);
NormalizeVector(diskRight);
diskUp:=VectorCrossProduct(diskNormal, diskRight);
NormalizeVector(diskUp);
invAtmosphereHeight:=1/(cAtmosphereRadius-cPlanetRadius);
lightingVector:=VectorNormalize(sunPos); // sun at infinity
PrepareSinCosCache(sinCache, cosCache, 0, 360);
GetMem(pVertex, 2*(cSlices+1)*SizeOf(TVector));
GetMem(pColor, 2*(cSlices+1)*SizeOf(TVector));
glPushAttrib(GL_ENABLE_BIT);
glDepthMask(False);
glDisable(GL_LIGHTING);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
for i:=0 to 13 do begin
if i<5 then
radius:=cPlanetRadius*Sqrt(i*(1/5))
else radius:=cPlanetRadius+(i-5.1)*(cAtmosphereRadius-cPlanetRadius)*(1/6.9);
radius:=SphereVisibleRadius(VectorLength(eyePos), radius);
k0:=(i and 1)*(cSlices+1);
k1:=(cSlices+1)-k0;
for j:=0 to cSlices do begin
VectorCombine(diskRight, diskUp,
cosCache[j]*radius, sinCache[j]*radius,
pVertex[k0+j]);
if i<13 then
pColor[k0+j]:=ComputeColor(pVertex[k0+j], i<=7);
if i=0 then Break;
end;
if i>1 then begin
if i=13 then begin
glBegin(GL_QUAD_STRIP);
for j:=cSlices downto 0 do begin
glColor4fv(@pColor[k1+j]);
glVertex3fv(@pVertex[k1+j]);
glColor4fv(@clrTransparent);
glVertex3fv(@pVertex[k0+j]);
end;
glEnd;
end else begin
glBegin(GL_QUAD_STRIP);
for j:=cSlices downto 0 do begin
glColor4fv(@pColor[k1+j]);
glVertex3fv(@pVertex[k1+j]);
glColor4fv(@pColor[k0+j]);
glVertex3fv(@pVertex[k0+j]);
end;
glEnd;
end;
end else if i=1 then begin
glBegin(GL_TRIANGLE_FAN);
glColor4fv(@pColor[k1]);
glVertex3fv(@pVertex[k1]);
for j:=k0+cSlices downto k0 do begin
glColor4fv(@pColor[j]);
glVertex3fv(@pVertex[j]);
end;
glEnd;
end;
end;
glDepthMask(True);
glPopAttrib;
FreeMem(pVertex);
FreeMem(pColor);
end;