Texture quality and distance to object
by Funky Diver · 01/22/2005 (8:34 pm) · 6 comments
This code snippet helps to define the distance between the camera and an object when the object will be rendered using hi-res or low-res textures, and to completely disable the usage of low-res textures.
I started to dig this problem when I've decided to make a 3D puzzle game. When I came up with a working demo, I've found that all small pieces had strange textures due to the fact that engine kicked to the low-res textures while rendering the object. That was the short pre-story ;)
Now, the actual code...
1) Let's define all the necessary variables first. Obviously, we will be making changes to the gTexManager.h and gTexManager.cc files. Open gTexManager.h file and find this place:
In the top of gTexManager.cc file find these two lines:
2) We have to expose our new variables to the engine's script, so we can change them at run-time. Find the code that defines TextureDictionary::create() function in gTexManager.cc file:
3) We have to define the main function that tells us if low-res textures are enabled. Find the last method of the TextureManager structure defined in gTexManager.cc file and add these lines:
4) Now the most interesting part: the actual rendering code of a game object. Torque defines two base classes that are used for in-mission object: ShapeBase and TSStatic. We need to change renderObject() functions for both. In the shapeBase.cc find these lines (I love those comments of DMM :D ):
The code for TSStatic is almost identical, so fins in tsStatic.cc
We are done with the code.
How to use it in the engine? Quite easy: find the demo/client/defaults.cs and add our new variables (can be near $pref::OpenGL group of the variables):
Try to experiment with $pref::OpenGL::textureLoResDistance, changing to 5, 10, and 100.
...
Thanks to everyone who gave me ideas! Special thanks to Ben Garney for the inspiration!
I started to dig this problem when I've decided to make a 3D puzzle game. When I came up with a working demo, I've found that all small pieces had strange textures due to the fact that engine kicked to the low-res textures while rendering the object. That was the short pre-story ;)
Now, the actual code...
1) Let's define all the necessary variables first. Obviously, we will be making changes to the gTexManager.h and gTexManager.cc files. Open gTexManager.h file and find this place:
struct TextureManager
{
...
public:
static const char * csmTexturePrefix;
static void setSmallTexturesActive(const bool t) { smUseSmallTextures = t; }
static bool areSmallTexturesActive() { return smUseSmallTextures; }
static GBitmap *loadBitmapInstance(const char *textureName);
...
}And replace it with the following code:struct TextureManager
{
...
public:
static const char * csmTexturePrefix;
//********** AG ****************** >>
static bool smTextureDisableLoRes; //Texture LoRes management: disable/enable switching between the hi- and low-res textures
static float smTextureLoResDist; //Texture LoRes management: the distance from camera when it start to use the low-res texture
//********** AG ****************** <<
static void setSmallTexturesActive(const bool t) { smUseSmallTextures = t; }
static bool areSmallTexturesActive(); //AG Texture LoRes management: we must move the function body from here to the gTexManager.cc file
static GBitmap *loadBitmapInstance(const char *textureName);
...
}We are done with the gTexManager.h file, now, to the gTexManager.cc one... In the top of gTexManager.cc file find these two lines:
bool TextureManager::smUseSmallTextures = false; bool TextureManager::smIsZombie = false;and add the following lines:
bool TextureManager::smTextureDisableLoRes = false; //By default, texture switching is enabled float TextureManager::smTextureLoResDist = 15.0; //The minimum distance between the camera and the object when engine switch to the hi-res textures
2) We have to expose our new variables to the engine's script, so we can change them at run-time. Find the code that defines TextureDictionary::create() function in gTexManager.cc file:
void TextureDictionary::create()
{
smTOList = NULL;
smHashTableSize = 1023;
smTable = new TextureObject *[smHashTableSize];
for(U32 i = 0; i < smHashTableSize; i++)
smTable[i] = NULL;
//Con::addVariable("$pref::OpenGL::mipReduction", texDetailLevelCB, "0");
//Con::addVariable("$pref::OpenGL::anisotropy", anisotropyCB, "0");
Con::addVariable("$pref::OpenGL::force16BitTexture", TypeBool, &sgForce16BitTexture);
Con::addVariable("$pref::OpenGL::forcePalettedTexture", TypeBool, &sgForcePalettedTexture);
Con::addVariable("$pref::OpenGL::allowCompression", TypeBool, &sgAllowTexCompression);
Con::addVariable("$pref::OpenGL::disableSubImage", TypeBool, &sgDisableSubImage);
Con::addVariable("$pref::OpenGL::textureTrilinear", TypeBool, &sgTextureTrilinear);
Con::addVariable("$pref::OpenGL::textureAnisotropy", TypeF32, &sgTextureAnisotropy);
}Add two new lines likevoid TextureDictionary::create()
{
smTOList = NULL;
smHashTableSize = 1023;
smTable = new TextureObject *[smHashTableSize];
for(U32 i = 0; i < smHashTableSize; i++)
smTable[i] = NULL;
//Con::addVariable("$pref::OpenGL::mipReduction", texDetailLevelCB, "0");
//Con::addVariable("$pref::OpenGL::anisotropy", anisotropyCB, "0");
Con::addVariable("$pref::OpenGL::force16BitTexture", TypeBool, &sgForce16BitTexture);
Con::addVariable("$pref::OpenGL::forcePalettedTexture", TypeBool, &sgForcePalettedTexture);
Con::addVariable("$pref::OpenGL::allowCompression", TypeBool, &sgAllowTexCompression);
Con::addVariable("$pref::OpenGL::disableSubImage", TypeBool, &sgDisableSubImage);
Con::addVariable("$pref::OpenGL::textureTrilinear", TypeBool, &sgTextureTrilinear);
Con::addVariable("$pref::OpenGL::textureAnisotropy", TypeF32, &sgTextureAnisotropy);
//********** AG ****************** >>
Con::addVariable("$pref::OpenGL::textureDisableLoRes", TypeBool, &TextureManager::smTextureDisableLoRes);
Con::addVariable("$pref::OpenGL::textureLoResDistance", TypeF32, &TextureManager::smTextureLoResDist);
//********** AG ****************** <<
}Good.3) We have to define the main function that tells us if low-res textures are enabled. Find the last method of the TextureManager structure defined in gTexManager.cc file and add these lines:
bool TextureManager::areSmallTexturesActive() //AG Texture LoRes management: returns true if we must use small textures and it's enabled
{
return !smTextureDisableLoRes && smUseSmallTextures;
}4) Now the most interesting part: the actual rendering code of a game object. Torque defines two base classes that are used for in-mission object: ShapeBase and TSStatic. We need to change renderObject() functions for both. In the shapeBase.cc find these lines (I love those comments of DMM :D ):
void ShapeBase::renderObject(SceneState* state, SceneRenderImage* image)
{
...
// This is something of a hack, but since the 3space objects don't have a
// clear conception of texels/meter like the interiors do, we're sorta
// stuck. I can't even claim this is anything more scientific than eyeball
// work. DMM
F32 axis = (getObjBox().len_x() + getObjBox().len_y() + getObjBox().len_z()) / 3.0;
F32 dist = (getRenderWorldBox().getClosestPoint(state->getCameraPosition()) - state->getCameraPosition()).len();
if (dist != 0)
{
F32 projected = dglProjectRadius(dist, axis) / 350;
if (projected < (1.0 / 16.0))
{
TextureManager::setSmallTexturesActive(true);
}
}
...
}And replace them withvoid ShapeBase::renderObject(SceneState* state, SceneRenderImage* image)
{
...
// This is something of a hack, but since the 3space objects don't have a
// clear conception of texels/meter like the interiors do, we're sorta
// stuck. I can't even claim this is anything more scientific than eyeball
// work. DMM
F32 axis = (getObjBox().len_x() + getObjBox().len_y() + getObjBox().len_z()) / 3.0;
F32 dist = (getRenderWorldBox().getClosestPoint(state->getCameraPosition()) - state->getCameraPosition()).len();
if (dist != 0)
{
if (dist > TextureManager::smTextureLoResDist) //AG Texture LoRes management: check if we in the range to use the hi-res textures
{
TextureManager::setSmallTexturesActive(true);
}
}
...
}The code for TSStatic is almost identical, so fins in tsStatic.cc
void TSStatic::renderObject(SceneState* state, SceneRenderImage* image)
{
...
// This is something of a hack, but since the 3space objects don't have a
// clear conception of texels/meter like the interiors do, we're sorta
// stuck. I can't even claim this is anything more scientific than eyeball
// work. DMM
F32 axis = (getObjBox().len_x() + getObjBox().len_y() + getObjBox().len_z()) / 3.0;
F32 dist = (getRenderWorldBox().getClosestPoint(state->getCameraPosition()) - state->getCameraPosition()).len();
if (dist != 0)
{
F32 projected = dglProjectRadius(dist, axis) / 350;
if (projected < (1.0 / 16.0))
{
TextureManager::setSmallTexturesActive(true);
}
}
...
}and replace withvoid TSStatic::renderObject(SceneState* state, SceneRenderImage* image)
{
...
// This is something of a hack, but since the 3space objects don't have a
// clear conception of texels/meter like the interiors do, we're sorta
// stuck. I can't even claim this is anything more scientific than eyeball
// work. DMM
F32 axis = (getObjBox().len_x() + getObjBox().len_y() + getObjBox().len_z()) / 3.0;
F32 dist = (getRenderWorldBox().getClosestPoint(state->getCameraPosition()) - state->getCameraPosition()).len();
if (dist != 0)
{
if (dist > TextureManager::smTextureLoResDist) //AG Texture LoRes management: check if we in the range to use the hi-res textures
{
TextureManager::setSmallTexturesActive(true);
}
}
...
}We are done with the code.
How to use it in the engine? Quite easy: find the demo/client/defaults.cs and add our new variables (can be near $pref::OpenGL group of the variables):
$pref::OpenGL::textureDisableLoRes = "0"; $pref::OpenGL::textureLoResDistance = "30";Then remove all the *.dso and prefs.cs (saved preferences by the game, so it will be recreated again automatically) files from your "demo/client" folder.
Try to experiment with $pref::OpenGL::textureLoResDistance, changing to 5, 10, and 100.
...
Thanks to everyone who gave me ideas! Special thanks to Ben Garney for the inspiration!
#2
01/27/2005 (2:26 pm)
Thank you very much, Ben!
#3
that was long time ago.. so I guess in the current TGE 1.3 there is a quicker way to edit enable/disable lowres and to edit the distance at which the textures switch between high res and low res?
or even integrated somwhere in the world editor?
Or a per object modification so more important objects can look better at greated distance then less important objects?
Thanks for any info
03/15/2005 (7:06 am)
Ben... that was long time ago.. so I guess in the current TGE 1.3 there is a quicker way to edit enable/disable lowres and to edit the distance at which the textures switch between high res and low res?
or even integrated somwhere in the world editor?
Or a per object modification so more important objects can look better at greated distance then less important objects?
Thanks for any info
#4
06/09/2006 (4:10 am)
I assume this is in 1.4?
#5
07/25/2006 (6:17 pm)
Did this code make it into TSE Ben?
Associate Ben Garney
Nice work, Alexander! :)