Quote Originally Posted by User137
Simple 1 is to render a quad with high enough quality bi-linear texture (512 perhaps enough, maybe 1024) with black and white smooth sphere behind the planet, using additive blending and no depth-test.
Sounds very interesting. Unfortunately I don't have any ideas how to do it. Can you show me an example of this? Is this the same technique as projected textures?

Also, I've found out that GLScene has the thing I'm looking for, but I can't understand how it works. Can someone explain it? Here's the code:
[pascal]
procedure TGLCustomAtmosphere.DoRender(var rci: TRenderContextInfo; renderSelf, renderChildren: Boolean);
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 * Opacity;
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) - FPlanetRadius) * invAtmosphereHeight;
VectorLerp(LowAtmColor.Color, HighAtmColor.Color, 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 * Opacity * 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,
FAtmosphereRadius, ai1, ai2) > 1 then
begin
// atmosphere hit
if mayHitGround and (RayCastSphereIntersect(eyePos, rayVector,
NullHmgPoint, FPlanetRadius, 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;

var
I, J, k0, k1: Integer;
begin
if FSun <nil> FPlanetRadius);

sunPos := VectorSubtract(FSun.AbsolutePosition, AbsolutePosition);
eyepos := VectorSubtract(rci.CameraPosition, AbsolutePosition);

diskNormal := VectorNegate(eyePos);
NormalizeVector(diskNormal);
diskRight := VectorCrossProduct(rci.CameraUp, diskNormal);
NormalizeVector(diskRight);
diskUp := VectorCrossProduct(diskNormal, diskRight);
NormalizeVector(diskUp);

invAtmosphereHeight := 1 / (FAtmosphereRadius - FPlanetRadius);
lightingVector := VectorNormalize(sunPos); // sun at infinity

glPushAttrib(GL_ENABLE_BIT);
glDepthMask(False);
glDisable(GL_LIGHTING);
glEnable(GL_BLEND);
EnableGLBlendingMode;
for I := 0 to 13 do
begin
if I < 5 then
radius := FPlanetRadius * Sqrt(I * (1 / 5))
else
radius := FPlanetRadius + (I - 5.1) * (FAtmosphereRadius - FPlanetRadius) * (1 / 6.9);
radius := SphereVisibleRadius(VectorLength(eyePos), radius);
k0 := (I and 1) * (FSlices + 1);
k1 := (FSlices + 1) - k0;
for J := 0 to FSlices 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> 1 then
begin
if I = 13 then
begin
// glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBegin(GL_QUAD_STRIP);
for J := FSlices downto 0 do
begin
glColor4fv(@pColor[k1 + J]);
glVertex3fv(@pVertex[k1 + J]);
glColor4fv(@clrTransparent);
glVertex3fv(@pVertex[k0 + J]);
end;
glEnd;
end
else
begin
// glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_DST_COLOR);
glBegin(GL_QUAD_STRIP);
for J := FSlices 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
//glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBegin(GL_TRIANGLE_FAN);
glColor4fv(@pColor[k1]);
glVertex3fv(@pVertex[k1]);
for J := k0 + FSlices downto k0 do
begin
glColor4fv(@pColor[J]);
glVertex3fv(@pVertex[J]);
end;
glEnd;
end;
end;
glDepthMask(True);
glPopAttrib;
end;
inherited;
end;
[/pascal]