Page 1 of 3 123 LastLast
Results 1 to 10 of 30

Thread: [OpenGL] Earth atmosphere effect

  1. #1

    [OpenGL] Earth atmosphere effect

    Hello.

    I would like to write (based on my own, not-ready yet engine. ) a little program that displays our Earth, stars, and generally space. I've already coded the basics (the starfield, displaying Earth), but I'd like to know how do I achieve the effect similar to the one in this picture?

    I thought of using border detection algorithms, I've heard there are a few of them. But maybe there is another solution? Please explain it to me.

    Greetings.

  2. #2

    [OpenGL] Earth atmosphere effect

    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. You don't need alpha channel for the texture.

    Or you could render it on top of planet but then you need to fade out big portion of sphere center in your image editor. This technique would allow texture light up a little of planet surface too that may look more realistic.

    Size and position of the quad shouldn't be a problem.

    Edit: Oh, you need to invert Modelview matrix, null its position values (x,y,z are on 4th column) and then use it with glMultMatrixf before rendering quad.

  3. #3

    [OpenGL] Earth atmosphere effect

    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]

  4. #4

    [OpenGL] Earth atmosphere effect

    Don't know what the other code did, but here's my idea demonstrated:
    Glow texture http://i30.tinypic.com/o8fcqr.jpg
    Test application (with sphere actually rotating realtime) http://i25.tinypic.com/jaja6q.jpg
    You can have it better depending on scaling and glow texture. This one is 256x256 only cause i wanted to see how it looks

    [pascal]unit Unit1;

    interface

    uses
    Windows, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
    ExtCtrls, dglOpenGL, nxGL, Geometry2;

    type
    TForm1 = class(TForm)
    Timer1: TTimer;
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure Timer1Timer(Sender: TObject);
    private
    sphere: pgluQuadric;
    public
    end;

    var Form1: TForm1;

    implementation

    {$R *.dfm}

    procedure TForm1.FormCreate(Sender: TObject);
    var f: array[0..3] of single;
    begin
    nxCreateGlWindow(handle);
    tex.AddTexture('glow','glow.jpg');
    sphere:=gluNewQuadric;
    gluQuadricNormals(sphere,GLU_SMOOTH);
    DefaultLights;
    f[0]:=7;
    f[1]:=-2;
    f[2]:=6;
    f[3]:=0;
    glLightfv(GL_LIGHT0,GL_POSITION,@f);
    end;

    procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
    begin
    nxKillGLWindow;
    end;

    procedure TForm1.Timer1Timer(Sender: TObject);
    const A_rad = 1.33;
    var mat: TMatrix;
    begin
    nxClear(true,true);

    glLoadIdentity;
    glTranslatef(0,0,-4);
    glRotatef(GetTickCount*0.02,0,1,0);

    // Planet
    glEnable(GL_DEPTH_TEST);
    tex.SetTex(-1);
    glColor3f(0.2,0.2,0.2);
    gluSphere(sphere,1,30,30);
    glDisable(GL_DEPTH_TEST);

    // Atmosphere effect
    glDisable(GL_LIGHTING);
    tex.SetTex(0);
    AddBlend(true);
    glColor3f(0.4,0.6,1);
    glGetfloatv(GL_MODELVIEW_MATRIX,@mat);
    MatrixInvert(mat);
    mat[3,0]:=0;
    mat[3,1]:=0;
    mat[3,2]:=0;
    glMultMatrixf(@mat);
    RectT(A_rad,-A_rad,-A_rad,A_rad);
    AddBlend(false);
    glEnable(GL_LIGHTING);

    nxFlip;
    end;

    end.[/pascal]

  5. #5

    [OpenGL] Earth atmosphere effect

    Whoa, looks very good! The only question left is what does RectT do?

  6. #6

    [OpenGL] Earth atmosphere effect

    RectT renders a quad with texture coordinates.

    [pascal]procedure RectT(x1,y1,x2,y2: single);
    begin
    glBegin(GL_QUADS);
    glTexCoord2f(0,0); glVertex2f(x1, y1);
    glTexCoord2f(0,1); glVertex2f(x1, y2);
    glTexCoord2f(1,1); glVertex2f(x2, y2);
    glTexCoord2f(1,0); glVertex2f(x2, y1);
    glEnd;
    end;[/pascal]

  7. #7

    [OpenGL] Earth atmosphere effect

    Thank you very much, man.

  8. #8

    [OpenGL] Earth atmosphere effect

    perhaps also an interesting link for this topic:
    http://www.gamedev.net/community/for...opic_id=498700

  9. #9

    [OpenGL] Earth atmosphere effect

    I've discussed this matter with User137, but we couldn't find the answer together, so I decided to ask you, guys, to help me out.

    The problem is that the ring doesn't seem to be correctly aligned with the sphere. Look at the screenshot's top-left corner. You can see that the texture is not at the border of the sphere, but now it overlaps the other texture.

    How do I fix it?

  10. #10

    [OpenGL] Earth atmosphere effect

    It's probably because it's screen aligned. I think the solution is to use billboards instead, so that the normal always faces the viewer
    Peregrinus, expectavi pedes meos in cymbalis
    Nullus norvegicorum sole urinat

Page 1 of 3 123 LastLast

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •