Get the amount of light the player is standing in
by Bryce · in Torque Game Engine · 01/18/2009 (10:04 am) · 18 replies
Hello everyone,
I was wondering if there is a function that returns the amount of light (preferably a value from 0.0 to 1.0) a player is standing in? I'm using TGE 1.4.2 without Torque Lighting Kit.
Help is appreciated
I was wondering if there is a function that returns the amount of light (preferably a value from 0.0 to 1.0) a player is standing in? I'm using TGE 1.4.2 without Torque Lighting Kit.
Help is appreciated
#2
Hmmm....where would the code be that lights the player, then? I know that the player is lit whatever color the terrain below them is. Where does this happen, shapeBase.cs?
01/18/2009 (12:23 pm)
The trigger thing was my initial idea, but it becomes a bit tedious, especially for big levels.Hmmm....where would the code be that lights the player, then? I know that the player is lit whatever color the terrain below them is. Where does this happen, shapeBase.cs?
#3
01/18/2009 (1:05 pm)
sceneObject.cc, I think. Look for getLightingAmbientColor
#4
the sceneobject is setting a variable mLightingInfo to the color it extracts from the terrain it is standing on. So, I should be able to make a SceneObject console method that looks something like this, right?
Is the object-> bit necessary? Would this work (I'm reading out of notepad, I need to register my compiler but I'm too lazy at the moment)?
01/18/2009 (1:49 pm)
There's a bit of code I noticed in that function, not too sure if it's useful or not:ColorI terrCol;
if(lightmap->getColor(pos.x, pos.y, terrCol))
{
const F32 scale = 255.f / 31.f;
// convert the color...
terrCol.red = U8(F32(terrCol.red) * scale);
terrCol.green = U8(F32(terrCol.green) * scale);
terrCol.blue = U8(F32(terrCol.blue) * scale);
mLightingInfo.mDefaultColor = terrCol;
mLightingInfo.mLightSource = LightingInfo::Terrain;
mLightingInfo.mUseInfo = true;
}the sceneobject is setting a variable mLightingInfo to the color it extracts from the terrain it is standing on. So, I should be able to make a SceneObject console method that looks something like this, right?
ConsoleMethod( SceneObject, getLightvalue, F32, 2, 2, "gets the light under a sceneobject")
{
return object->mLightingInfo.mDefaultColor;
}Is the object-> bit necessary? Would this work (I'm reading out of notepad, I need to register my compiler but I'm too lazy at the moment)?
#5
I have to move LightingInfo mLightingInfo; in SceneObject.cc from protected: to public: to make it accessible to the ConsoleMethod, so I think all the errors now have to do with the return type (not my area of expertise, either). I get the following errors now:
1>..enginesimsceneObject.cc(53) : error C2059: syntax error : ')'
1>..enginesimsceneObject.cc(53) : error C2065: 'conmethod_return_ColorF' : undeclared identifier
1>..enginesimsceneObject.cc(53) : error C2146: syntax error : missing ';' before identifier 'cSceneObjectgetLightAmount'
1>..enginesimsceneObject.cc(53) : error C2664: 'ConsoleConstructor::ConsoleConstructor(const char *,const char *,StringCallback,const char *,S32,S32)' : cannot convert parameter 3 from 'ColorF (__cdecl *)(SimObject *,S32,const char **)' to 'StringCallback'
1> Incompatible calling conventions for UDT return value
01/18/2009 (2:02 pm)
Okay, now I'm getting closer (I think):ConsoleMethod( SceneObject, getLightAmount, ColorF, 2, 2, "Get object light.")
{
return object->mLightingInfo.mDefaultColor;
}I have to move LightingInfo mLightingInfo; in SceneObject.cc from protected: to public: to make it accessible to the ConsoleMethod, so I think all the errors now have to do with the return type (not my area of expertise, either). I get the following errors now:
1>..enginesimsceneObject.cc(53) : error C2059: syntax error : ')'
1>..enginesimsceneObject.cc(53) : error C2065: 'conmethod_return_ColorF' : undeclared identifier
1>..enginesimsceneObject.cc(53) : error C2146: syntax error : missing ';' before identifier 'cSceneObjectgetLightAmount'
1>..enginesimsceneObject.cc(53) : error C2664: 'ConsoleConstructor::ConsoleConstructor(const char *,const char *,StringCallback,const char *,S32,S32)' : cannot convert parameter 3 from 'ColorF (__cdecl *)(SimObject *,S32,const char **)' to 'StringCallback'
1> Incompatible calling conventions for UDT return value
#6
01/18/2009 (4:33 pm)
Yeah.. I don't think you can return a ColorF through a ConsoleMethod. You'll probably have to build a char* and return that. Reference the ConsoleMethod getPosition for an example.
#7
Something like that.
btw.. yes you do need "object->". Because ConsoleMethod is not a member function belonging to SceneObject, the "object" pointer is your only reference to the object instance in question.
01/18/2009 (4:36 pm)
ConsoleMethod( SceneObject, getLightAmount, const char*, 2, 2, "Get object light.")
{
ColorF col = object->mLightingInfo.mDefaultColor;
char *returnBuffer = Con::getReturnBuffer(256);
dSprintf(returnBuffer,256,"%g %g %g", col.red, col.green, col.blue);
return returnBuffer;
}Something like that.
btw.. yes you do need "object->". Because ConsoleMethod is not a member function belonging to SceneObject, the "object" pointer is your only reference to the object instance in question.
#8
Odd.
It could have something to do with this:
but this is an initialization function; I don't see why the color variable wouldn't change while the actual color does change :-/
01/18/2009 (5:12 pm)
Okay, she now compiles, but no matter where the player stands (even as I see the light color change when I move into a shadow), it keeps returning "0.5 0.5 0.5"Odd.
It could have something to do with this:
//--------------------------------------------------------------------------
SceneObject::LightingInfo::LightingInfo()
{
mUseInfo = false;
mDirty = false;
mHasLastColor = false;
// set the colors to half white for invalid surfaces and all...
mDefaultColor.set(0.5f, 0.5f, 0.5f);
mAlarmColor.set(0.5f, 0.5f, 0.5f);
mLastColor.set(0.5f, 0.5f, 0.5f);
mLastTime = 0;
}but this is an initialization function; I don't see why the color variable wouldn't change while the actual color does change :-/
#9
01/18/2009 (5:31 pm)
Hmm. Are you calling getLightAmount on a CLIENT or SERVER object? Light values are only calculated on CLIENT objects. If you're checking a SERVER object, that would explain why you're only seeing the default values.
#10
I'm calling Localclientconnection.player.getlightamount();. Should I call Localclientconnection.getlightamount();?
If so, how would I get this to work with ai players, I don't believe they have a client.
01/18/2009 (5:45 pm)
ah.....I'm calling Localclientconnection.player.getlightamount();. Should I call Localclientconnection.getlightamount();?
If so, how would I get this to work with ai players, I don't believe they have a client.
#11
01/18/2009 (6:44 pm)
What exactly do you mean by a client object?
#12
"localClientConnection" is the name of the server-side instance of the "local client" connection. So when you're referencing localClientConnection.player, you're getting the server copy of the player.
The question then becomes, what do you want to do with this getLightAmount function, and should it be a client or server function?
An overly-simplified way to look at it is this: The server controls what happens in the game, and the client is responsible for displaying it. So visual effects like lense-flare or light coronas or particle effects are generally client-side. While game logic like damage or inventory tracking is server-side.
Since you mentioned AI Players, I'm going to guess you're dealing with AI logic here. Perhaps so your AI can be aware of shadows? AI logic is a server-side function, ideally. So you'd want to calculate lighting for the server copies of your players. At best, this would involve some rewriting of the getLightingAmbientColor function to adapt it for server-side use. Unfortunately, I'm not at all sure that will work, because I'm not sure that the lighting data you need even exists server-side.
Now, I could be wrong about that. The server may have lighting data, but I rather doubt it.
If you're making an exclusively Single-Player game, or if you're not concerned with breaking dedicated server functionality, then you can "cheat" and ignore the client/server divide. Basically you would have your server-side Players (where the AI logic is) directly query the client-side versions of the Terrain and Interiors (where the light data is). That should work, and it's certainly the easiest solution I can think of.
If on the other hand you want full multiplayer with dedicated server... That I think won't be so easy.
Of course that's assuming i'm correct about what you're trying to do with your ai players.
01/18/2009 (9:04 pm)
Torque uses a client/server system, even in a "single player" game. In a multiplayer game obviously you have multiple remote clients connected to the server. In a "single player" game, there still exists one "local" client "connected" to the server, and the client and server still maintain their own collection of game world objects. Some functions are server-side and some are client-side. For an object such as a Player class instance there will be two versions of the same object. One each for the client and the server. Only the client-side copy need care about the lighting because only the client-side copy is responsible for rendering its image to the screen. Hence only the client-side copy runs the getLightingAmbientColor function. And therein lies your problem. "localClientConnection" is the name of the server-side instance of the "local client" connection. So when you're referencing localClientConnection.player, you're getting the server copy of the player.
The question then becomes, what do you want to do with this getLightAmount function, and should it be a client or server function?
An overly-simplified way to look at it is this: The server controls what happens in the game, and the client is responsible for displaying it. So visual effects like lense-flare or light coronas or particle effects are generally client-side. While game logic like damage or inventory tracking is server-side.
Since you mentioned AI Players, I'm going to guess you're dealing with AI logic here. Perhaps so your AI can be aware of shadows? AI logic is a server-side function, ideally. So you'd want to calculate lighting for the server copies of your players. At best, this would involve some rewriting of the getLightingAmbientColor function to adapt it for server-side use. Unfortunately, I'm not at all sure that will work, because I'm not sure that the lighting data you need even exists server-side.
Now, I could be wrong about that. The server may have lighting data, but I rather doubt it.
If you're making an exclusively Single-Player game, or if you're not concerned with breaking dedicated server functionality, then you can "cheat" and ignore the client/server divide. Basically you would have your server-side Players (where the AI logic is) directly query the client-side versions of the Terrain and Interiors (where the light data is). That should work, and it's certainly the easiest solution I can think of.
If on the other hand you want full multiplayer with dedicated server... That I think won't be so easy.
Of course that's assuming i'm correct about what you're trying to do with your ai players.
#13
Thanks for all the help anyway!!
01/18/2009 (9:55 pm)
Yes, I'm working on an AI Pack, and I was attempting to adjust visibility probability depending on how lit an object is. If this would break multiplayer functionality, I don't think I'll include it.Thanks for all the help anyway!!
#14
That's just speculation, though :P It may be possible that all lights are entirely client-side... which would suck...
01/19/2009 (9:29 am)
The server should keep track of light objects though, shouldn't it? It may be possible to implement a server-side routine specific to AIPlayer (or move it up to ShapeBase) that checks the object against server-side light objects and calculated a visibility score.That's just speculation, though :P It may be possible that all lights are entirely client-side... which would suck...
#15
the lightmap value is determined by casting a ray downward from the player and seeing what polygon it hits, and getting the lightmap value from that. (it's actually slightly more complex, but that's 90% of the idea)
unfortunately, as has been pointed out, this is only available on the client. (fwiw, i just confiremd this: replacing gClientContainer with gServerContainer results in the player being always full-brightness)
for more info, see the code in sceneObject.cc following the comment "Ambient light is determined by the surface we are standing on".
(near line 1908)
bryce,
if you're not too worried about client-side hacking (that is, if you expect your game to have a relatively small and/or casual audience for the next six months or so) then you could have the clients occasionally self-report their lighting back to the server. naturally this is a fragile approach and should only be considered stop-gap at best, but it might enable you to at least try out your gameplay ideas. if it looks like a good feature, you can worry about securing it later. (ie loading the lightmaps server-side)
01/19/2009 (9:51 am)
the lighting used on a given player is calculated from a combination of the lightmap value on the interior or terrain under their feet, and then from other lights. the lightmap value is the main contributor, generally.the lightmap value is determined by casting a ray downward from the player and seeing what polygon it hits, and getting the lightmap value from that. (it's actually slightly more complex, but that's 90% of the idea)
unfortunately, as has been pointed out, this is only available on the client. (fwiw, i just confiremd this: replacing gClientContainer with gServerContainer results in the player being always full-brightness)
for more info, see the code in sceneObject.cc following the comment "Ambient light is determined by the surface we are standing on".
(near line 1908)
bryce,
if you're not too worried about client-side hacking (that is, if you expect your game to have a relatively small and/or casual audience for the next six months or so) then you could have the clients occasionally self-report their lighting back to the server. naturally this is a fragile approach and should only be considered stop-gap at best, but it might enable you to at least try out your gameplay ideas. if it looks like a good feature, you can worry about securing it later. (ie loading the lightmaps server-side)
#16
01/19/2009 (2:15 pm)
You could also just have an option to disable checking for light. This way developers using your pack could decide if they want to use it for their game, or maybe have it disabled in multiplayer matches but allowed in single-player (where cheating and client-side stuff won't really be a big deal).Quote:I have to move LightingInfo mLightingInfo; in SceneObject.cc from protected: to public: to make it accessible to the ConsoleMethod,In situations like this, it is considered better practice to write a get() function for the protected object than to set it public, for example getLightingInfo(). I'm not entirely sure why, but it's kind of standard practice :P
#17
01/19/2009 (3:39 pm)
Quote:because if you just make it public, then other classes can not only read the value of the field, but write it as well. whereas if you only provide a getter() and no setter() then you've essentially made a read-only field.
In situations like this, it is considered better practice to write a get() function for the protected object than to set it public, for example getLightingInfo(). I'm not entirely sure why, but it's kind of standard practice :P
#18
03/04/2009 (4:32 pm)
Would it be possible to take the light color defined in getLightingAmbientColor, and then save it (on the server) onto the shape that is being lit so other things can use that information?
Associate Steve Acaster
[YorkshireRifles.com]
[psuedoscript]
if(%this.inshadow) = 1;
[/psuedoscript]