Laser Sight
by Paul Clarke · in Torque Game Engine · 10/04/2009 (10:28 am) · 59 replies
I'm trying to implement a laser sight for the weapons in my game instead of using a crosshair. So far I've been using a volume light and it works quite well, but as you'll see in the picture below it clips through walls, enemies and eveything else.
I guess I'm just wondering if anyone knows how to stop this from happening, or if there's a better way to do laser sight. I've looked at the resources available but they all seem to be for laser projectiles which isn't what I need.
Any help is appreciated.
[IMG]http://img225.imageshack.us/img225/7172/25492337.th.jpg[/IMG]
I guess I'm just wondering if anyone knows how to stop this from happening, or if there's a better way to do laser sight. I've looked at the resources available but they all seem to be for laser projectiles which isn't what I need.
Any help is appreciated.
[IMG]http://img225.imageshack.us/img225/7172/25492337.th.jpg[/IMG]
About the author
#2
10/04/2009 (1:30 pm)
That does look good! I had been thinking of just using a terrible hack like having a transparent billboard attached to the gun, but had then realised the whole lack of clip issue. If you know some coding, I suppose that you could draw a line on screen from weapon to collision point, kinda like the way path nodes draw between each other. Though that's all rather beyond me.
#3
10/04/2009 (2:54 pm)
i simple draw a line from the gun, so you can raycast to set the length of the line if you want to collision with an object...
#4
10/04/2009 (3:03 pm)
player.ccvoid Player::renderImage(SceneState* state, SceneRenderImage* image) {
....
// Debugging Bounding Box
if (!mShapeInstance || gShowBoundingBox) {
Point3F box;
glPushMatrix();
box = (mWorkingQueryBox.min + mWorkingQueryBox.max) * 0.5f;
glTranslatef(box.x,box.y,box.z);
box = (mWorkingQueryBox.max - mWorkingQueryBox.min) * 0.5f;
glScalef(box.x,box.y,box.z);
glColor3f(1.0f, 1.0f, 0.0f);
wireCube(Point3F(1.0f, 1.0f, 1.0f),Point3F(0.0f, 0.0f, 0.0f));
glPopMatrix();
Box3F convexBox = mConvex.getBoundingBox(getRenderTransform(), getScale());
glPushMatrix();
box = (convexBox.min + convexBox.max) * 0.5f;
glTranslatef(box.x,box.y,box.z);
box = (convexBox.max - convexBox.min) * 0.5f;
glScalef(box.x,box.y,box.z);
glColor3f(1.0f, 1.0f, 1.0f);
wireCube(Point3F(1.0f, 1.0f, 1.0f),Point3F(0.0f, 0.0f, 0.0f));
glPopMatrix();
glEnable(GL_DEPTH_TEST);
}
/*
// javier, point helper
GameConnection* conn = GameConnection::getConnectionToServer();
ShapeBase* ControlObj = NULL;
// Problem?
if (conn)
{
// Get the Control Object.
ControlObj = conn->getControlObject();
}
*/
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_TEXTURE_2D);
// Fetch ini Position.
Point3F eyePos;
MatrixF eye;
/*
if (con && con->getControlObject() == this){
//ShapeBase* selectedObj = NULL;
//selectedObj = con->getControlObject()->getMuzzleTransform(0,&eye);
//selectedObj->getMuzzleTransform(0,&eye);
//con->getControlObject()->getRenderMuzzleTransform(0,&eye);
con->getControlObject()->getRenderMuzzleTransform(0,&eye);
Point3F box;
glPushMatrix();
box = (mWorkingQueryBox.min + mWorkingQueryBox.max) * 0.5f;
glTranslatef(box.x,box.y,box.z);
box = (mWorkingQueryBox.max - mWorkingQueryBox.min) * 0.5f;
glScalef(box.x,box.y,box.z);
//glColor4f(1.0f,1.0f,0.0f,0.3f);
glColor3f(1.f, 1.f, 0.f);
wireCube(Point3F(1.f, 1.f, 1.f),Point3F(0.f, 0.f, 0.f));
glPopMatrix();
}
else
*/
getRenderMuzzleTransform(0,&eye);
eye.getColumn(3, &eyePos);
// Extend the vector to create an endpoint for our ray
Point3F endPos;
eye.getColumn(1, &endPos);
endPos *= mDataBlock->fUnitMaxVision; // TODO: get max vision of the unit
endPos += eyePos;
glLineWidth(1.f);
glBegin(GL_LINES);
glColor4f(1.0f,0.0f,0.0f,0.5f);
//glColor3f(1.f, 0.f, 0.f);
glVertex3fv(eyePos);
glVertex3fv(endPos);
glEnd();
glLineWidth(1.f); //back
glDisable(GL_BLEND);
// javier, end
}
#5
@Javier, Thanks for the code, I tried it and it seems like an easier solution, although it doesn't look as good as the voulme light.
Would it possible to get an example of how to do a raycast that changes the length of the line if it collides with something? I'm still a C++ noob, and the code could really help me.
@Daniel, I'm really interested in getting your method working, although I think my lack of C++ knowledge might make it difficult. I'm not quite sure how to make a subclass of volume light since I've never done anything like that before, I've also just searched the forums and resources but couldn't find any good info on how to do it. is there anyway you could give me an example?
Thanks for everyones help.
10/05/2009 (4:47 am)
Thanks for the replies guys,@Javier, Thanks for the code, I tried it and it seems like an easier solution, although it doesn't look as good as the voulme light.
Would it possible to get an example of how to do a raycast that changes the length of the line if it collides with something? I'm still a C++ noob, and the code could really help me.
@Daniel, I'm really interested in getting your method working, although I think my lack of C++ knowledge might make it difficult. I'm not quite sure how to make a subclass of volume light since I've never done anything like that before, I've also just searched the forums and resources but couldn't find any good info on how to do it. is there anyway you could give me an example?
Thanks for everyones help.
#6
EDIT:
Oh, forgot about an old bug fix that will cause the compile to fail. You will have to change a line in sgLightObject.h from:
10/05/2009 (6:04 pm)
You could use something along the lines of this:void volumeLight::renderGL(SceneState *state, SceneRenderImage *image)
{
....
F32 ax = mXextent / 2;
F32 ay = mYextent / 2;
F32 collisionDistance = mShootDistance;
GameBase *obj = getAttachedObject();
ShapeBase *shape = dynamic_cast<ShapeBase*>(obj);
if(shape)
{
Point3F startPosition;
Point3F endPosition;
RayInfo rInfo;
MatrixF muzzleMat;
shape->getMuzzlePoint(0,&startPosition);
shape->getMuzzleVector(0,&endPosition);
endPosition.normalize();
endPosition *= mShootDistance;
endPosition += startPosition;
shape->disableCollision();
const U32 ObjectMask = TerrainObjectType |
InteriorObjectType |
StaticObjectType |
PlayerObjectType |
VehicleObjectType |
DamagableItemObjectType;
if(getContainer()->castRay(startPosition, endPosition, ObjectMask, &rInfo) == true)
collisionDistance = (rInfo.point - startPosition).len();
shape->enableCollision();
}
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
....
end1 -= lightpoint; // get a vector from point to lightsource
end1.normalize(); // normalize vector
end1 *= collisionDistance; // multiply it out by shootlength
end1.x += bx; // Add the original point location to the vector
end1.y -= ay;
// Do it again for the other point.
end2 -= lightpoint;
end2.normalize();
end2 *= collisionDistance;
end2.x += bx;
end2.y += ay;
....
end1 -= lightpoint; // get a vector from point to lightsource
end1.normalize(); // normalize vector
end1 *= collisionDistance; // extend it out by shootlength
end1.x -= ax; // Add the original point location to the vector
end1.y += by;
// Do it again for the other point.
end2 -= lightpoint;
end2.normalize();
end2 *= collisionDistance;
end2.x += ax;
end2.y += by;
....
}It will need a lot more fleshing out to make sure it does not interfere with other volume lights.EDIT:
Oh, forgot about an old bug fix that will cause the compile to fail. You will have to change a line in sgLightObject.h from:
virtual SceneObject *getAttachedObject() {return sgAttachedObjectPtr;}to:virtual GameBase *getAttachedObject() {return sgAttachedObjectPtr;}Not sure why GG decided to return a sceneobject object for something that is a gamebase object throughout the rest of the code.
#7
10/06/2009 (4:53 am)
Paul, Thank you so much for that code, it works great. I've still got some work to do to make the laser sight behave the way I want it to, but with your code I'm definitely heading in the right direction, Thanks again.
#8
Change:
I've also noticed the volume light does not use the image muzzle vector, so it does not render to the centre of the screen.
10/06/2009 (8:32 am)
A minor change you can make in case you use a different slot;Change:
shape->getMuzzlePoint(0,&startPosition); shape->getMuzzleVector(0,&endPosition);to:
shape->getRenderMuzzlePoint(mountPoint,&startPosition); shape->getRenderMuzzleVector(mountPoint,&endPosition);That will take the mount point from the light datablock instead of forcing it to 0.
I've also noticed the volume light does not use the image muzzle vector, so it does not render to the centre of the screen.
#9
I also noticed that it doesn't render to the centre of the screen, but for my current project (a 2d style topdown/overhead shooter) it works fine.
10/06/2009 (2:11 pm)
That small change could be very useful, thanks again.I also noticed that it doesn't render to the centre of the screen, but for my current project (a 2d style topdown/overhead shooter) it works fine.
#10
I think that with my method you can have the same effect, because you can draw an semitransparent line too in:
# glBegin(GL_LINES);
# glColor4f(1.0f,0.0f,0.0f,0.5f);
# //glColor3f(1.f, 0.f, 0.f);
# glVertex3fv(eyePos);
# glVertex3fv(endPos);
# glEnd();
but the question is what is the more efficient way... or quality vs speed
10/06/2009 (3:33 pm)
good code @paul/*ilys, thanks.I think that with my method you can have the same effect, because you can draw an semitransparent line too in:
# glBegin(GL_LINES);
# glColor4f(1.0f,0.0f,0.0f,0.5f);
# //glColor3f(1.f, 0.f, 0.f);
# glVertex3fv(eyePos);
# glVertex3fv(endPos);
# glEnd();
but the question is what is the more efficient way... or quality vs speed
#11
sgLightObject.cc calculateLightPosition()
change
10/07/2009 (12:33 pm)
A fix for rendering to the centre of the screen;sgLightObject.cc calculateLightPosition()
change
shape->getRenderMountTransform(mountPoint, &mat);to
shape->getRenderMuzzleTransform(mountPoint, &mat);
#12
I had actually tried to fix that myself but couldn't figure it out. the laser sight works great in first person now.
10/07/2009 (4:39 pm)
nice one, thanks again.I had actually tried to fix that myself but couldn't figure it out. the laser sight works great in first person now.
#13
10/07/2009 (5:02 pm)
ill try it, and maybe its good post this as resource..., thanks Paul.
#14
thanks...
10/09/2009 (3:13 am)
@paul, can you copy paste the laser light datablock (torquescript) ?thanks...
#15
10/09/2009 (5:03 am)
I'd also like to see the datablock and volumelight object for that lazer sight.
#16
I noticed a problem with the code last night, it will crash if the map contains any volume lights. eg: in the Lighting System demo, as soon as I turn towards the interior the engine crashes.
10/09/2009 (5:57 am)
I'm at work at the moment so I don't have access to my files, I'll post the datablock later when I get home.I noticed a problem with the code last night, it will crash if the map contains any volume lights. eg: in the Lighting System demo, as soon as I turn towards the interior the engine crashes.
#17
volLight.cc
volumeLight::volumeLight() add;
volumeLight::packUpdate() add;
volumeLight::unpackUpdate() add in the same sequence as packUpdate;
volumeLight::renderGL() change;
volumeLight::initPersistFields() add;
volLight.h
under mShootDistance add;
That change lets you specify which volumeLight object will use the LoS code.
10/09/2009 (6:31 am)
EDIT: Make sure you clean or re-build with the following code, or it will still crash.volLight.cc
volumeLight::volumeLight() add;
mShootLOS = false;
volumeLight::packUpdate() add;
stream->write(mShootLOS);
volumeLight::unpackUpdate() add in the same sequence as packUpdate;
stream->read(&mShootLOS);
volumeLight::renderGL() change;
if(shape)to
if(shape && mShootLOS)
volumeLight::initPersistFields() add;
addField( "ShootLOS", TypeBool, Offset( mShootLOS, volumeLight ) );
volLight.h
under mShootDistance add;
bool mShootLOS;
That change lets you specify which volumeLight object will use the LoS code.
#18
Here's what I have for the laser sight.
In player.cs, Armor::onAdd
and then in common/lighting/lights, I created a new file called laserlight.cs
I also created a red texture to replace the default one.
10/09/2009 (10:41 am)
awesome, I just quickly tried the new code and it doesn't crash now, thanks again.Here's what I have for the laser sight.
In player.cs, Armor::onAdd
%light = new volumeLight() {
dataBlock = "sgLaserLight";
rotation = "-0.357694 0.933839 9.9834e-009 180";
scale = "1 1 1";
//dataBlock = "sgMountLight";
Enable = "1";
IconSize = "1";
ParticleColorAttenuation = "1";
Texture = "common/lighting/lightFalloffMono.png";
lpDistance = "38.00";
ShootDistance = "60";
ShootLOS = "true";
Xextent = "0.05";
Yextent = "0.05";
SubdivideU = "4";
SubdivideV = "4";
FootColour = "1.000000 1.000000 1.000000 0.182000";
TailColour = "0.400000 0.400000 0.400000 0.400000";and then in common/lighting/lights, I created a new file called laserlight.cs
//--- OBJECT WRITE BEGIN ---
datablock sgUniversalStaticLightData(sgLaserLight) {
className = "sgUniversalStaticLightData";
LightOn = "0";
Radius = "0.85";
Brightness = "0.37931";
Colour = "1.000000 0.976471 0.941177 1.000000";
FlareOn = "0";
FlareTP = "1";
FlareBitmap = "common/lighting/corona";
FlareColour = "1.000000 1.000000 1.000000 1.000000";
ConstantSizeOn = "0";
ConstantSize = "0.4";
NearSize = "0.4";
FarSize = "0.6";
NearDistance = "3";
FarDistance = "10";
FadeTime = "0.1";
BlendMode = "0";
AnimColour = "0";
AnimBrightness = "0";
AnimRadius = "0";
AnimOffsets = "0";
AnimRotation = "0";
LinkFlare = "1";
LinkFlareSize = "0";
MinColour = "0.000000 0.000000 0.000000 1.000000";
MaxColour = "1.000000 0.976471 0.941177 1.000000";
MinBrightness = "0";
MaxBrightness = "0.37931";
MinRadius = "0.1";
MaxRadius = "0.85";
StartOffset = "-5 0 0";
EndOffset = "5 0 0";
MinRotation = "0";
MaxRotation = "359";
SingleColourKeys = "1";
RedKeys = "AZA";
GreenKeys = "AZA";
BlueKeys = "AZA";
BrightnessKeys = "AZA";
RadiusKeys = "AZA";
OffsetKeys = "AZA";
RotationKeys = "AZA";
ColourTime = "5";
BrightnessTime = "5";
RadiusTime = "5";
OffsetTime = "5";
RotationTime = "5";
LerpColour = "1";
LerpBrightness = "1";
LerpRadius = "1";
LerpOffset = "1";
LerpRotation = "1";
StaticLight = "0";
SpotLight = "1";
SpotAngle = "120";
AdvancedLightingModel = "0";
EffectsDTSObjects = "0";
CastsShadows = "0";
DiffuseRestrictZone = "1";
AmbientRestrictZone = "0";
LocalAmbientAmount = "0";
SmoothSpotLight = "0";
DoubleSidedAmbient = "0";
LightingModelName = "SG - Original Stock (Lighting Pack)";
UseNormals = "1";
MountPoint = "0";
MountPosition = "0 0 0";
MountRotation = "-1 0 0 270";
};
//--- OBJECT WRITE END ---I also created a red texture to replace the default one.
#19
mShootLOS = false;
but im testing and see that the collision its not working...
10/09/2009 (5:36 pm)
thanks @ilys, i create a new derived class for dont have to make the changes:mShootLOS = false;
but im testing and see that the collision its not working...
#20
btw: That sgLaser looks awesome!
Edit: Installed and working awesome!
btw:
1. delete lights before mounting vehicles and reattach when unmounting or else you'll get a crash
2. Paul *ilys* Post #8 I had to change his change from &EndVector to &EndPosition
:)
Also, I have Daniel Buckmaster's Image-On-Image Resource installed and I would like to have the Laser coming from the Laser Attachment(LaserPoint) instead of the MuzzlePoint, any hints on on to accomplish this would be great!
@Javier, There could be a problem with your new sgObject because the sgLaser is working with .dts and .dif files with all the above changes
10/09/2009 (7:23 pm)
I know there may (or may not) be the code to implement this, but this would be great as a Resource, always good to show that TGE is still being worked on!btw: That sgLaser looks awesome!
Edit: Installed and working awesome!
btw:
1. delete lights before mounting vehicles and reattach when unmounting or else you'll get a crash
2. Paul *ilys* Post #8 I had to change his change from &EndVector to &EndPosition
:)
Also, I have Daniel Buckmaster's Image-On-Image Resource installed and I would like to have the Laser coming from the Laser Attachment(LaserPoint) instead of the MuzzlePoint, any hints on on to accomplish this would be great!
@Javier, There could be a problem with your new sgObject because the sgLaser is working with .dts and .dif files with all the above changes
Torque Owner Daniel Buckmaster
T3D Steering Committee
I'd maybe make a subclass of volume light that casts a ray along its vector, then alters its brightness/range depending on how far away the hit was.