SkySphere
by Mike Kuklinski · 12/01/2004 (6:18 pm) · 41 comments
Download Code File
This resource is designed to allow the user to utilize a SkySphere instead of a SkyBox.
By default, the TGE utilizes a 6 sided box in order to render the background. For many applications, this is sufficient, however, in many space simulations, the SkyBox can have a detrimental effect on the background by causing stretching of the texture near the edges. A sphere works to repair this issue by having the majority of the edges of the polygons closer to being the same distance from the camera. Spheres have the small issue of often requiring a mapped texture. I have attached an example polar mapped texture.
I would recommend you use this resource with the Star Rendering resource by James Lupiani.
//SKY.CC
Around Line 28
Around Line 57
Around Line 332
Around Line 524
Then, replace Sky::renderSkyBox with this:
Put this code above renderSkyBox:
Put this after renderSkyBox:
//Sky.h
Around Line 157, in Private:
Around Line 220
//In Mission File
Add "SkySphere = "1";" to the Sky object. It should map the sky using the first texture in the sky DML. Unless it is a polar mapped texture, it will NOT look right.
Also, you must define the location of sphere.arr using
sphereList = "~/data/sphere.arr";
SkyDepth = "1"; //Use this to render two spheres.
This resource is designed to allow the user to utilize a SkySphere instead of a SkyBox.
By default, the TGE utilizes a 6 sided box in order to render the background. For many applications, this is sufficient, however, in many space simulations, the SkyBox can have a detrimental effect on the background by causing stretching of the texture near the edges. A sphere works to repair this issue by having the majority of the edges of the polygons closer to being the same distance from the camera. Spheres have the small issue of often requiring a mapped texture. I have attached an example polar mapped texture.
I would recommend you use this resource with the Star Rendering resource by James Lupiani.
//SKY.CC
Around Line 28
#define RAD (2 * M_PI) //SkySphere #define PID2 (M_PI / 2) //SkySphere
Around Line 57
mRenderStars = true; //SkySphere mSkySphere = false; mSkyDepth = false; //SkySphere
Around Line 332
addField("noRenderBans", TypeBool, Offset(mNoRenderBans, Sky));
//SkySphere
addField("SkySphere", TypeBool, Offset(mSkySphere, Sky));
addField("SkyDepth", TypeBool, Offset(mSkyDepth, Sky));
addField("sphereList", TypeFilename, Offset(mSphereListName,Sky));
//SkySphereAround Line 362stream->read(&mRenderBoxBottom); //SkySphere stream->read(&mSkySphere); stream->read(&mSkyDepth); mSphereListName = stream->readSTString(); //SkySphere
Around Line 524
stream->write(mRenderBoxBottom); //SkySphere stream->write(mSkySphere); stream->write(mSkyDepth); stream->writeString(mSphereListName); //SkySphere
In Sky::renderObject(SceneState* state, SceneRenderImage*), after render(state); glDisable(GL_TEXTURE_2D); put: glEnable(GL_TEXTURE_2D); glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_REPLACE); glDepthMask(GL_FALSE); rendersphere(); glDisable(GL_TEXTURE_2D); "If you are using the star generation resource, put that after the star rendering code"
Then, replace Sky::renderSkyBox with this:
void Sky::renderSkyBox(F32 lowerBanHeight, F32 alphaBanUpper)
{
if(!mSkyTexturesOn || !smSkyOn)
{
glDisable(GL_TEXTURE_2D);
glColor3ub(mRealSkyColor.red, mRealSkyColor.green, mRealSkyColor.blue);
}
if (!mSkySphere) {
S32 side, index=0, val;
U32 numPoints;
Point3F renderPoints[4];
Point2F texCoords[4];
for(side = 0; side < ((mRenderBoxBottom) ? 6 : 5); ++side)
{
if((lowerBanHeight != mSpherePt.z || (side == 4 && alphaBanUpper < 1.0f)) && mSkyHandle[side])
{
glBindTexture(GL_TEXTURE_2D,mSkyHandle[side].getGLName());
if(side < 4)
{
numPoints = 4;
setRenderPoints(renderPoints, index);
if(!mNoRenderBans)
sgUtil_clipToPlane(renderPoints, numPoints, PlaneF(0.0f, 0.0f, 1.0f, -lowerBanHeight));
if(numPoints)
{
calcTexCoords(texCoords, renderPoints, index);
glBegin(GL_QUADS);
glTexCoord2f(texCoords[0].x, texCoords[0].y);
glVertex3f(renderPoints[0].x, renderPoints[0].y, renderPoints[0].z);
glTexCoord2f(texCoords[1].x, texCoords[1].y);
glVertex3f(renderPoints[1].x, renderPoints[1].y, renderPoints[1].z);
glTexCoord2f(texCoords[3].x, texCoords[3].y);
glVertex3f(renderPoints[2].x, renderPoints[2].y, renderPoints[2].z);
glTexCoord2f(texCoords[2].x, texCoords[2].y);
glVertex3f(renderPoints[3].x, renderPoints[3].y, renderPoints[3].z);
glEnd();
}
++index;
}
else
{
index = 3;
val = -1;
if(side == 5)
{
index = 5;
val = 1;
}
glBegin(GL_QUADS);
glTexCoord2f(mTexCoord[0].x, mTexCoord[0].y);
glVertex3f(mPoints[index].x, mPoints[index].y, mPoints[index].z);
glTexCoord2f(mTexCoord[1].x, mTexCoord[1].y);
glVertex3f(mPoints[index+(1*val)].x, mPoints[index+(1*val)].y, mPoints[index+(1*val)].z);
glTexCoord2f(mTexCoord[3].x, mTexCoord[3].y);
glVertex3f(mPoints[index+(2*val)].x, mPoints[index+(2*val)].y, mPoints[index+(2*val)].z);
glTexCoord2f(mTexCoord[2].x, mTexCoord[2].y);
glVertex3f(mPoints[index+(3*val)].x, mPoints[index+(3*val)].y, mPoints[index+(3*val)].z);
glEnd();
}
}
}
}
else {
int i,j,n = 0;
if (mFirstRun != 1)
spherearray();
for (j=0;j<20;j++) {
glBindTexture(GL_TEXTURE_2D,mSkyHandle[1].getGLName());
glBegin(GL_TRIANGLE_STRIP);
for (i=0;i<=40;i++,n++) {
glNormal3f(Sphere[n].x,Sphere[n].y,Sphere[n].z);
glTexCoord2f(Sphere3[n].x,Sphere3[n].y);
glVertex3f(Sphere[n].x,Sphere[n].y,Sphere[n].z);
glNormal3f(Sphere2[n].x,Sphere2[n].y,Sphere2[n].z);
glTexCoord2f(Sphere4[n].x,Sphere4[n].y);
glVertex3f(Sphere2[n].x,Sphere2[n].y,Sphere2[n].z);
}
glEnd();
}
}
if(!mSkyTexturesOn)
glEnable(GL_TEXTURE_2D);
}Put this code above renderSkyBox:
void Sky::spherearray()
{
char path[1024], *p;
dStrcpy(path, mSphereListName);
if ((p = dStrrchr(path, '/')) != NULL)
*p = 0;
Stream *stream = ResourceManager->openStream(mSphereListName);
char buffer[512];
U32 count;
stream->readLine( (U8*)buffer, 512 );
count = dAtoi( buffer );
if( count > 820 )
count = 820;
for(int i=0; i<count; ++i)
{
if( stream->getStatus() == Stream::EOS )
break;
stream->readLine( (U8*)buffer, 512 );
F32 aa,bb,cc,dd,ee,ff,gg,hh,ii,jj;
aa=bb=cc=dd=ee=ff=gg=hh=ii=jj=0;
dSscanf( buffer, "%f %f %f %f %f %f %f %f %f %f",&aa,&bb,&cc,&dd,&ee,&ff,&gg,&hh,&ii,&jj);
Sphere[i] = Point3F(aa,bb,cc);
Sphere2[i] = Point3F(dd,ee,ff);
Sphere3[i]= Point2F(gg,hh);
Sphere4[i] = Point2F(ii,jj);
}
mNumVerts = count;
ResourceManager->closeStream(stream);
mFirstRun = 1;
}Put this after renderSkyBox:
void Sky::rendersphere()
{
if (mSkyDepth) {
if(!mSkyTexturesOn || !smSkyOn)
{
glDisable(GL_TEXTURE_2D);
glColor3ub(mRealSkyColor.red, mRealSkyColor.green, mRealSkyColor.blue);
}
if (mSkySphere) {
int i,j,n = 0;
if (mFirstRun != 1)
spherearray();
for (j=0;j<20;j++) {
glBindTexture(GL_TEXTURE_2D,mSkyHandle[4].getGLName());
glBegin(GL_TRIANGLE_STRIP);
for (i=0;i<=40;i++,n++) {
glNormal3f(Sphere[n].x,Sphere[n].y,Sphere[n].z);
glTexCoord2f(Sphere3[n].x,Sphere3[n].y);
glVertex3f(Sphere[n].x,Sphere[n].y,Sphere[n].z);
glNormal3f(Sphere2[n].x,Sphere2[n].y,Sphere2[n].z);
glTexCoord2f(Sphere4[n].x,Sphere4[n].y);
glVertex3f(Sphere2[n].x,Sphere2[n].y,Sphere2[n].z);
}
glEnd();
}
}
if(!mSkyTexturesOn)
glEnable(GL_TEXTURE_2D);
}
}//Sky.h
Around Line 157, in Private:
MaterialList mMaterialList; //SkySphere F32 mod1; F32 mod2; F32 sLastTime; bool mSkySphere; bool mSkyDepth; bool mFirstRun; Point3F Sphere[820]; Point3F Sphere2[820]; Point2F Sphere3[820]; Point2F Sphere4[820]; U16 mNumVerts; StringTableEntry mSphereListName; //SkySphere
Around Line 220
void calcAlphas_Heights(F32 zCamPos, F32 *banHeights, F32 *alphaBan, F32 DepthInFog); //SkySphere void spherearray(); void rendersphere(); //SkySphere
//In Mission File
Add "SkySphere = "1";" to the Sky object. It should map the sky using the first texture in the sky DML. Unless it is a polar mapped texture, it will NOT look right.
Also, you must define the location of sphere.arr using
sphereList = "~/data/sphere.arr";
SkyDepth = "1"; //Use this to render two spheres.
About the author
http://dev.stackheap.com/
#22
For those slow like me, make sure to add:
Also in the Sky datablock in the .mis, I added
Finally, instead of glEnabling again in Sky::renderObject, I did the following:
01/19/2006 (2:20 am)
First of all, rock on Mike! This is awesome stuff.For those slow like me, make sure to add:
noRenderBans = "1";to your Sky datablock in your .mis file otherwise you get nasty gray gradients where the horizon used to be.
Also in the Sky datablock in the .mis, I added
renderBottomTexture = "1"; clipLowerHalf = "0";For good measure...?
Finally, instead of glEnabling again in Sky::renderObject, I did the following:
glEnable(GL_TEXTURE_2D); glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_REPLACE); glDepthMask(GL_FALSE); rendersphere(); // skysphere render(state); glDisable(GL_TEXTURE_2D);What is the difference? maybe slightly faster?
#23
Thanks,
JS
03/04/2006 (3:48 pm)
Hi, I was just wondering if there was any news on the TSE port of this code? Im trying to use it in TSE myself.Thanks,
JS
#25
Mike... Are you still planning on doing the tutorial on creating the polar texture?
04/04/2006 (11:13 pm)
This works in TGE 1.4.Mike... Are you still planning on doing the tutorial on creating the polar texture?
#26
04/23/2006 (4:09 pm)
any possibilities to get bigger screenshots?
#28
08/29/2006 (7:12 am)
@Mike... When is that tutorial coming (polar texture)? It's really needed by us newbs.
#29
12/31/2006 (2:23 pm)
No luck with TGE 1.5... crashes on load.
#30
You must set the mission variables directly in the *mis file!
02/04/2007 (3:39 pm)
work in tge 1.5!You must set the mission variables directly in the *mis file!
#31
02/04/2007 (8:41 pm)
Oooh... that's encouraging! Perhaps I booched something in the update. I'll take another stab at it when time permits.
#32
02/23/2007 (7:06 am)
how do you mean directly in the mis files?
#33
name_of_mission.mis
//In Mission File
Add "SkySphere = "1";" to the Sky object. It should map the sky using the first texture in the sky DML. Unless it is a polar mapped texture, it will NOT look right.
Also, you must define the location of sphere.arr using
sphereList = "~/data/sphere.arr";
SkyDepth = "1"; //Use this to render two spheres.
02/23/2007 (7:14 am)
in the mission's file like: name_of_mission.mis
//In Mission File
Add "SkySphere = "1";" to the Sky object. It should map the sky using the first texture in the sky DML. Unless it is a polar mapped texture, it will NOT look right.
Also, you must define the location of sphere.arr using
sphereList = "~/data/sphere.arr";
SkyDepth = "1"; //Use this to render two spheres.
#34
On further study it seems to be coming from the BitStream::writeString function on the for loop?
02/23/2007 (8:53 am)
Yeh Ive done that, this must be another problem then! I keep getting a runtime error when loading the game, when i debug it goes through to stream.h and the function read? Ive put this into 1.42 and is the only mod ive made on it, any ideas?On further study it seems to be coming from the BitStream::writeString function on the for loop?
#35
nebula.dml & nebula_*.jpg in the skies dir and the sphere.arr in data?
02/23/2007 (9:44 am)
You putted al the files in the correct dirs?nebula.dml & nebula_*.jpg in the skies dir and the sphere.arr in data?
#36
07/09/2007 (11:09 am)
Hey dude, could you tell us all how you make your polar mapped textures and make nice nebula textures too? I've done a quick tutorial about it for my space-sim guide but yours looks better! :o)
#37
02/06/2008 (1:43 am)
I try and try and try, but it always crashes on 1.52, no matter what i do. Do you have an idea of the necessary changes to adapt it to 1.52 ? Do somebody already tried it wth 1.5.2?
#38
10/26/2008 (3:19 am)
hmmm i cant get it to work with 1.5.2 either it says loading objects then stops towards end , doesnt crash, just doesnt load.
#39
01/10/2009 (2:22 pm)
I have this working on 1.5.0, mostly no problem. However, for lower-end graphics hardware, it doesn't render at all, although the sky box will render. Any idea as to what or where could be causing this? It's very strange. It works on my macbook pro, but not on another team member's normal macbook. It works on my work computer under software opengl emulation (Rage Pro 8mb graphics on Linux- the sky renders, but I can't say the rest of the game works right).
#40
05/20/2009 (8:38 am)
Any luck with TGEA 1.8.1? 
Torque Owner Mike Kuklinski