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/
#2
11/01/2004 (12:27 pm)
Nice.
#3
11/01/2004 (2:04 pm)
I updated it, on Zoom's request, to not do the calculations every tick, but read from an array.
#4
void Sky::spherearray()
{
int j,i,n = 0;
for (j=0;j<50;j++) {
t1 = ((j+1) *RAD/100-PID2);
t2 = (j*RAD/100-PID2);
for (i=0;i<=100;i++,n++) {
t3 = (i*RAD/100);
Sphere[n].point = Point3F(cos(t1) * cos(t3),sin(t1),cos(t1) * sin(t3);
Sphere[n].point2 = Point3F(cos(t2) * cos(t3),sin(t2),cos(t2)* sin(t3));
Sphere[n].tex = Point2F(i/(double)100,2*(j+1)/(double)100);
Sphere[n].tex2 = Point2F(i/(double)100,2*j/(double)100);
}
}
mFirstRun = 1;
}
11/02/2004 (5:17 pm)
Reduce the calculations a bit...void Sky::spherearray()
{
int j,i,n = 0;
for (j=0;j<50;j++) {
t1 = ((j+1) *RAD/100-PID2);
t2 = (j*RAD/100-PID2);
for (i=0;i<=100;i++,n++) {
t3 = (i*RAD/100);
Sphere[n].point = Point3F(cos(t1) * cos(t3),sin(t1),cos(t1) * sin(t3);
Sphere[n].point2 = Point3F(cos(t2) * cos(t3),sin(t2),cos(t2)* sin(t3));
Sphere[n].tex = Point2F(i/(double)100,2*(j+1)/(double)100);
Sphere[n].tex2 = Point2F(i/(double)100,2*j/(double)100);
}
}
mFirstRun = 1;
}
#5
11/03/2004 (12:32 pm)
I added the optimizations... btw... aren't they somewhat redundant seeing as spherearray is only called once?
#6
What open source license did it use?
12/02/2004 (8:36 am)
Quote:
found freely on the internet (released as open source)
What open source license did it use?
#7
This morning, I edited the source to add fixes, since some clients got rendering errors on the single-pass calculations. This uses an array of points instead, which does not get those errors. If you get any runtime or compiler errors, please notify me immediately.
12/02/2004 (12:16 pm)
There was no license. The site simply stated "Use as you please". However, the before stated math is no longer used in the rendering.This morning, I edited the source to add fixes, since some clients got rendering errors on the single-pass calculations. This uses an array of points instead, which does not get those errors. If you get any runtime or compiler errors, please notify me immediately.
#8
12/02/2004 (3:04 pm)
could you post as a Zip file instead of a .rar
#9
12/02/2004 (3:42 pm)
ZIP doesnt compress small enough.
#10
12/02/2004 (4:14 pm)
How big is the maximum size of a sphere texture?
#11
12/02/2004 (4:19 pm)
The maximum limit should be set by your video card.... I personally use 1024*512 (seeing as 2:1 is near the proper proportion for a sphere texture), and that works with a high level of detail.
#12
And do you have any links to info on how to create a polar map?
12/03/2004 (3:03 am)
ic, I'm asking becuase currently I'm using 5 512*512 textures for a skybox, so I'm think replacing those with 1 texture would mean loss of detail.And do you have any links to info on how to create a polar map?
#13
12/03/2004 (11:14 am)
I will create a new resource for that later, discussing how to make polar maps.
#14
06/18/2005 (9:34 am)
Is there any interest in a TSE version of this?
#15
06/25/2005 (11:49 am)
Yes, there is an interest in a TSE version of this ;)
#16
06/26/2005 (1:40 pm)
Once my development computer is fixed, i will port out the changes. They are primarily renderer... IE converting the GL calls to their GFX/PrimBuild equivalents.
#17
08/07/2005 (6:17 am)
This crashes me when i load a map. Any ideas?
#18
09/09/2005 (12:27 pm)
I don't know -- this was built around TGE 1.2 IIRC, the newer versions might be substantially different.
#19
09/09/2005 (2:35 pm)
so it seems:(
#20
10/17/2005 (11:15 am)
Any decision on a TSE version of this resource Mike? 
Torque Owner Mike Kuklinski