Ghosting Limits
by Jesse Allen · in Torque 3D Professional · 09/08/2014 (12:47 am) · 212 replies
Greetings fellow Torque-goers! I hadn't been overly active on the boards lately, but that's usually a good thing since it means I'm busy actually developing stuff :) Finally hit a snag today, and I was hoping someone a bit more knowledgeable about these things could perhaps point me in the right direction.
I've been working with generating 1000's of cubes, which I have been largely successful with. I have scripted algorithms to do exactly what I need as far as generation is concerned. I've even managed to work out some basic culling and so on. The problem I'm having, however, is with the following error:
NetConnection::object In Scope: too many ghosts.
I did a bit of searching and I did stumble on Vince Gee's fantastic resources for Limiting Shapebase ghosting and Improved Limiting ghosting . These do appear to be useful by their own rights and I will definitely explore these options. However, these particular resources deal specifically with ghost limiting as related to view distance.
The problem I am having seems to stem from the actual hard limits set on the maximum number of allowed ghosts. I was curious:
Also, bonus points for a clear explanation on how view distance affects ghosts in the first place. If I generate in a bunch of cubes and use the command ServerConnection.getGhostsActive() I can see the current number of ghosts. Check. But if I then reduce the viewDistance to an absurdly low amount (such as 10) and run far away from the generated cubes...the command will still show the same number of ghosts, regardless of my distance from them.
Cheers guys, as always thanks in advance for any help.
I've been working with generating 1000's of cubes, which I have been largely successful with. I have scripted algorithms to do exactly what I need as far as generation is concerned. I've even managed to work out some basic culling and so on. The problem I'm having, however, is with the following error:
NetConnection::object In Scope: too many ghosts.
I did a bit of searching and I did stumble on Vince Gee's fantastic resources for Limiting Shapebase ghosting and Improved Limiting ghosting . These do appear to be useful by their own rights and I will definitely explore these options. However, these particular resources deal specifically with ghost limiting as related to view distance.
The problem I am having seems to stem from the actual hard limits set on the maximum number of allowed ghosts. I was curious:
- Is it possible to increase the number of ghosted objects?
- If it were possible, what sorts of problems would this increase potentially introduce?
Also, bonus points for a clear explanation on how view distance affects ghosts in the first place. If I generate in a bunch of cubes and use the command ServerConnection.getGhostsActive() I can see the current number of ghosts. Check. But if I then reduce the viewDistance to an absurdly low amount (such as 10) and run far away from the generated cubes...the command will still show the same number of ghosts, regardless of my distance from them.
Cheers guys, as always thanks in advance for any help.
About the author
Skilled Artist and Musician. Intermediate Torque Developer.
#122
You are exactly right Andrew, I was confusing the two. I appreciate the clarification :)
09/23/2014 (9:51 am)
As Homer Simpson would say, "Doh!" You are exactly right Andrew, I was confusing the two. I appreciate the clarification :)
#123
Directly Mapping Texels to Pixels
and
Coordinate Systems
From the first link, it appeared as if:
The 2nd link directly refers to the texel/pixel translation problem, eluding to the issue lying with DirectX 9 moreso than 10. Am I correct in assuming the framework we are building with here in Torque's source is DirectX 9 (due to needing the Dx9 SDK to compile)? Thanks for any direction around this :)
09/23/2014 (1:12 pm)
I'm still stumbling over the half-pixel problem. I've done a bit of research around it, and found some very relevant information:Directly Mapping Texels to Pixels
and
Coordinate Systems
From the first link, it appeared as if:
//adjust all the vertices to correctly line up texels with pixels
for (int i=0; i<6; i++)
{
vertices[i].x -= 0.5f;
vertices[i].y -= 0.5f;
}...may solve the problem. Although my lack of understanding of C++ is hindering my progress on actually applying it. The 2nd link directly refers to the texel/pixel translation problem, eluding to the issue lying with DirectX 9 moreso than 10. Am I correct in assuming the framework we are building with here in Torque's source is DirectX 9 (due to needing the Dx9 SDK to compile)? Thanks for any direction around this :)
#124
Don't get into the vertex adjustment solution, it's a little much if you ask me. If you aren't planning on doing some kind of user-generated texture choices or anything, and you're fine with manually entering the UV coordinates for each of the textures you're going to use, I would just offset them manually. Literally just keep subtracting small numbers from the edges until you get it correct. Like instead of 0.5 try 0.49995 or if its in the other direction try 0.50005 etc. With stuff like this it's all about the visual outcome, if it looks good, you're good.
The idea behind making a function is that you can calculate those UV numbers by dividing, for instance, the width of the subtexture you want to grab, by the width of the whole texture. Example: you have a 1024x1024 image split up into 4 images, each 512x512. You need the UV coordinate for the top right of that 512x512 box. So, 512/1024 = 0.5 which is exactly what you're using now. The half-pixel correction means offset the first number by .5 (half of a pixel) before doing the calculation. So instead you'd do 512.5/1024 = 0.500488 and using that number instead of 0.5 will get rid of the discoloration on the edge. The easiest way is to just crunch these numbers yourself or just add/subtract roughly 0.0005 from each end.
09/23/2014 (1:33 pm)
Yeah, it's DirectX 9. Don't get into the vertex adjustment solution, it's a little much if you ask me. If you aren't planning on doing some kind of user-generated texture choices or anything, and you're fine with manually entering the UV coordinates for each of the textures you're going to use, I would just offset them manually. Literally just keep subtracting small numbers from the edges until you get it correct. Like instead of 0.5 try 0.49995 or if its in the other direction try 0.50005 etc. With stuff like this it's all about the visual outcome, if it looks good, you're good.
The idea behind making a function is that you can calculate those UV numbers by dividing, for instance, the width of the subtexture you want to grab, by the width of the whole texture. Example: you have a 1024x1024 image split up into 4 images, each 512x512. You need the UV coordinate for the top right of that 512x512 box. So, 512/1024 = 0.5 which is exactly what you're using now. The half-pixel correction means offset the first number by .5 (half of a pixel) before doing the calculation. So instead you'd do 512.5/1024 = 0.500488 and using that number instead of 0.5 will get rid of the discoloration on the edge. The easiest way is to just crunch these numbers yourself or just add/subtract roughly 0.0005 from each end.
#125
09/23/2014 (1:36 pm)
Yup - Torque's current renderer is DirectX9.
#126
128.5 / 256 = 0.501953125
Then going the other way I came up with: 0.498046875
That didn't cut it, so I proceeded to try to 'edge off' bit by bit finally ending up at:
0.502 and 0.497 - Just trimming off more in each direction.
Unfortunately it hadn't been enough yet and I'm still getting some artifacts on the edges. I'm hoping this problem will just be less evident once the textures themselves are a bit larger. Thanks for the input around the problem though; at least I know I can just fiddle with the actual values instead of trying to devise some overly involved function lol.
09/23/2014 (1:43 pm)
Thanks for the quick replies guys. I get the division part I think. I'm dealing with a 256x256 texture as well so perhaps each pixel is just going to be more evident if it's bleeding over. This won't be the case once this all gets out of the creation phase we're working through (well the entire atlas will be larger, although each 'tile' may not). I did this:128.5 / 256 = 0.501953125
Then going the other way I came up with: 0.498046875
That didn't cut it, so I proceeded to try to 'edge off' bit by bit finally ending up at:
0.502 and 0.497 - Just trimming off more in each direction.
Unfortunately it hadn't been enough yet and I'm still getting some artifacts on the edges. I'm hoping this problem will just be less evident once the textures themselves are a bit larger. Thanks for the input around the problem though; at least I know I can just fiddle with the actual values instead of trying to devise some overly involved function lol.
#127
Anyway, onto the goods:
gist.github.com/andr3wmac/a16781a763cf0a87d49e
I've prefixed all the changes with "Collision:". In order to enable collision you need to fill in the buildConvex function. This is Torque asking for a simple version of your mesh made up of shapes from it's math functions. We already have pretty simple meshes, they're just cubes, or a BoxConvex as Torque calls it. All I had to do was create a BoxConvex for each cube in the list and position it and size it accordingly.
One quirk I noticed:
The size had to be given as 0.5f in order to match the size of the cube. Not entirely sure why, I just noticed using 1 was making it twice the size, so I used 0.5f. Offsetting by 0.5f makes sense because it's the cube center, so I should have to offset each position by half the size of the cube. Maybe mSize means size from the center? Who knows. It works quite well anyway.
The next thing that might throw you off is this whole section:
https://gist.github.com/andr3wmac/a16781a763cf0a87d49e#file-rendermeshexample-cpp-L437-L455
The idea they have there is to not recreate these BoxConvex objects if we don't have to, so it keeps a cache of them and looks them up to see if it already exists, and updates them all. I just copy and pasted this and adapted it. It's present in all the buildConvex functions so I followed suit. I did however have to make my own CubeConvex class, which inherits BoxConvex. All it does is add one thing to it:
I had to make this because if we fill this cache up with a bunch of BoxConvex's how can we tell which one is which to know if we found the one we're looking for? I added cubeIndex and I set it equal to n (the current spot in the cubeList). This way I can tell if I found the cube or not.
There's a few pieces scattered throughout the code related to that cache. It needs to be created, and emptied when the object is destroyed, etc. Just search for "collision:" to find all the changes.
This doesn't take care of ray casting, and projectiles go through them (do they use ray casting?) but one problem at a time! You can climb the cubes now! I built a tower and climbed it. I was quite happy with myself.
09/23/2014 (4:05 pm)
Time for collision! This was definitely one I had to try myself as I haven't written custom collision for anything yet, but I figured it out pretty quickly. I looked at MeshRoad and GroundPlane since both use their own custom collision and I just took the parts that seem relevant and then trimmed it down to the absolute minimum to get collision working for one cube, then expanded it for all them. There's a few minor quirks I'll point but for the most part I think it's pretty straight forward. A good lesson to take from this is that I don't entirely know how to do all of these things, but there are examples everywhere throughout the Torque source. You just need to get used to looking for it and reading it and pulling out what you need. It took me about 6 months before I felt comfortable inside the source, so just keep at it and you'll find you can make Torque do anything you want.Anyway, onto the goods:
gist.github.com/andr3wmac/a16781a763cf0a87d49e
I've prefixed all the changes with "Collision:". In order to enable collision you need to fill in the buildConvex function. This is Torque asking for a simple version of your mesh made up of shapes from it's math functions. We already have pretty simple meshes, they're just cubes, or a BoxConvex as Torque calls it. All I had to do was create a BoxConvex for each cube in the list and position it and size it accordingly.
One quirk I noticed:
boxConvex->mCenter = Point3F( cubeList[n].position.x + 0.5f, cubeList[n].position.y + 0.5f, cubeList[n].position.z + 0.5f );
boxConvex->mSize = Point3F( 0.5f, 0.5f, 0.5f );The size had to be given as 0.5f in order to match the size of the cube. Not entirely sure why, I just noticed using 1 was making it twice the size, so I used 0.5f. Offsetting by 0.5f makes sense because it's the cube center, so I should have to offset each position by half the size of the cube. Maybe mSize means size from the center? Who knows. It works quite well anyway.
The next thing that might throw you off is this whole section:
https://gist.github.com/andr3wmac/a16781a763cf0a87d49e#file-rendermeshexample-cpp-L437-L455
The idea they have there is to not recreate these BoxConvex objects if we don't have to, so it keeps a cache of them and looks them up to see if it already exists, and updates them all. I just copy and pasted this and adapted it. It's present in all the buildConvex functions so I followed suit. I did however have to make my own CubeConvex class, which inherits BoxConvex. All it does is add one thing to it:
// Collision: this is just a copy of BoxConvex but with cubeIndex added so we know which cube
// we're talking about when going through the cache.
class RenderMeshConvex : public BoxConvex
{
public:
U32 cubeIndex;
};I had to make this because if we fill this cache up with a bunch of BoxConvex's how can we tell which one is which to know if we found the one we're looking for? I added cubeIndex and I set it equal to n (the current spot in the cubeList). This way I can tell if I found the cube or not.
There's a few pieces scattered throughout the code related to that cache. It needs to be created, and emptied when the object is destroyed, etc. Just search for "collision:" to find all the changes.
This doesn't take care of ray casting, and projectiles go through them (do they use ray casting?) but one problem at a time! You can climb the cubes now! I built a tower and climbed it. I was quite happy with myself.
#128
gist.github.com/andr3wmac/a16781a763cf0a87d49e#file-rendermeshexample-cpp-L124-L...
I aligned one corner at 0,0,0 so it would start where the first cube starts, then expanded it to 10,10,10. This will cover an area of exactly 10x10x10 cubes. Since you're using these chunks to break up your world, you should probably set these numbers to the area you want each chunk to cover. This is the bounding box, the white box you see when you click on the object. If the bounding box goes out of view the whole object stops drawing.
09/23/2014 (4:17 pm)
Oh yeah! One last change was nessicary for collision. It's only tested within the objects bounding box, that's defined here:gist.github.com/andr3wmac/a16781a763cf0a87d49e#file-rendermeshexample-cpp-L124-L...
I aligned one corner at 0,0,0 so it would start where the first cube starts, then expanded it to 10,10,10. This will cover an area of exactly 10x10x10 cubes. Since you're using these chunks to break up your world, you should probably set these numbers to the area you want each chunk to cover. This is the bounding box, the white box you see when you click on the object. If the bounding box goes out of view the whole object stops drawing.
#129
09/23/2014 (4:21 pm)
This is looking very cool, guys. Maybe this should be stickied so others can find it - or made into a tutorial on the wiki....
#130
:D Going to give it a good run and I'll report!
@Richard: I'm not opposed to assembling the whole works of this into a tutorial, granted it's okay with Andrew. Unless he wants to do it :) He may be better at explaining it all :P If we get a solid and completed working prototype here, I'm sure there would be no short supply of folks interested in the subject matter. Not only is it covering some intricate workings of Torque, it gives a great foundation for block-based games.
I feel there will probably be a few more kinks to work out yet, but so far it's definitely looking good!
EDIT: On second thought, tbh if the person who is learning this stuff doesn't witness firsthand the unique exchange that is taking place in this thread...it would be pretty tough to write out in document form.
09/23/2014 (4:42 pm)
Ah, my instructor returns! *Rushes off to get a little coffee ready*:D Going to give it a good run and I'll report!
@Richard: I'm not opposed to assembling the whole works of this into a tutorial, granted it's okay with Andrew. Unless he wants to do it :) He may be better at explaining it all :P If we get a solid and completed working prototype here, I'm sure there would be no short supply of folks interested in the subject matter. Not only is it covering some intricate workings of Torque, it gives a great foundation for block-based games.
I feel there will probably be a few more kinks to work out yet, but so far it's definitely looking good!
EDIT: On second thought, tbh if the person who is learning this stuff doesn't witness firsthand the unique exchange that is taking place in this thread...it would be pretty tough to write out in document form.
#131
In the header file, after you declare buildConvex, add a declaration for castRay, which is another SceneObject function that does nothing by default, but which we'll override.
NOTE: This should work, but Andrew has had some issues with it so see if it works for you. If not we'll be on hand to do some more detailed debugging!
09/23/2014 (5:24 pm)
For reference on how Torque's collision system works, you might like to have a read of this page. Projectiles do indeed collide using raycasts, so let's add that to the class.In the header file, after you declare buildConvex, add a declaration for castRay, which is another SceneObject function that does nothing by default, but which we'll override.
virtual bool castRay( const Point3F &start, const Point3F &end, RayInfo *info );The method takes two points (in object-local coordinates), and a RayInfo which is used to pass data back out of the call. The implementation looks like this:
bool RenderMeshExample::castRay( const Point3F &start, const Point3F &end, RayInfo *info )
{
// Used for its utility method, collideLine, which you'll see below.
Box3F cube;
// Position along the ray that we hit (0 is the start, 1 is the end).
F32 t = 1.0f;
// Normal vector of the ray collision.
Point3F n;
// Did any of the cubes get hit?
bool hit = false;
// Check each cube.
for(U32 i = 0; i < cubeList.size(); i++)
{
// start and end are already in local coordinates, so we'll just use the
// cube positions directly to create our box.
cube.set(cubeList[i].position, cubeList[i].position + Point3F(1, 1, 1));
// Now collide against the box that represents this cube.
if(cube.collideLine(start, end, &t, &n))
{
// We have a collision, but does it happen before the current collision?
if(t < info->t)
{
// Yup! Fill in the RayInfo's data so whoever's casting the ray has
// access to it.
hit = true;
info->t = t;
info->normal = n;
info->material = mMaterialInst;
info->object = this;
}
}
}
// Return true if one of our cubes was hit.
return hit;
}I think the comments there are fairly self-explanatory. The tricky part is that we have to test collisions against all cubes, but only take the one with the smallest t value, which is the collision that will happen first. And then, only if that t is smaller than the t value that is already in the RayInfo struct, because that one ray might have already been cast against some other objects closer to the source.NOTE: This should work, but Andrew has had some issues with it so see if it works for you. If not we'll be on hand to do some more detailed debugging!
#132
...but I'd be lying if I said I completely grasped all of what's going on that quickly lol. I do get the basics: the added includes, the new class, the bounding box addition, and so on. But the intricate inner workings are going to require a lot more study. Like the new includes would be a good start for me to look over very closely. And lol, that for loop with an empty first argument really opened my mind up! I mean wth! I had no idea that was even possible without the compiler yelling at you.
I'm going to try and work with Danny's example as well, so that I can be prepared to inquire about any and all of it in one fell swoop.
I am going to need more time to study this stuff closer, to be sure that when I do shoot out the questions...they are the right ones.
Last but not least, of course, thanks for the material. I feel like you just handed me a study guide, but I'm not in school...haha I really want this study guide in my hand!
09/23/2014 (6:10 pm)
Nice! Here's my successful application of it:
...but I'd be lying if I said I completely grasped all of what's going on that quickly lol. I do get the basics: the added includes, the new class, the bounding box addition, and so on. But the intricate inner workings are going to require a lot more study. Like the new includes would be a good start for me to look over very closely. And lol, that for loop with an empty first argument really opened my mind up! I mean wth! I had no idea that was even possible without the compiler yelling at you.I'm going to try and work with Danny's example as well, so that I can be prepared to inquire about any and all of it in one fell swoop.
I am going to need more time to study this stuff closer, to be sure that when I do shoot out the questions...they are the right ones.
Last but not least, of course, thanks for the material. I feel like you just handed me a study guide, but I'm not in school...haha I really want this study guide in my hand!
#133
Syntax
The first hurdle is the syntax. There are 2 particular issues I'm having now when reading the code. I will see the asterisk(*) used in contradictory ways. i.e:
Okay, syntax problem #2. I see the & symbol on some variables in some places but not present in others:
I realize this may just be explained away with a good document. Any direction for my personal research could go a long ways.
Conceptually Makes Sense
I would like to say that conceptually this is solid. I see the point of the added mConvexList and how it must be used to keep track of the added collisions. Otherwise we'd just add a bunch of stuff that we'd never be able to reference later. Check. Some of the inner workings of the buildConvex function are honestly being lost on me, perhaps not because I wouldn't otherwise understand what's being said but because the syntax isn't clear. Maybe a little bit of advice by ways of additional comments or just a link to a solid document could help. I'm at a stage where I'm able to follow the concepts but stumbling over the wording. For me, with such dedicated instruction, I'm not willing to accept this as satisfactory. I don't want to be able to 'monkey see, monkey do'. I want to be able to grow personally and walk away from all of this an improved version of what was there before. I guess that makes sense...lol :P
The Raycasting
I read over the linked wiki article(which was a nice overview thanks) and also stepped through all of the code. Here is the intial problem I had with understanding the castRay:
Cheers, thanks so much for the study guide. I haven't dug into the added #includes yet, but that'll be in the morning! Good night :)
09/23/2014 (9:03 pm)
Without staying up too terribly late again grasping at straws, I'll go ahead and drop my initial problems here. Up until now, it's all made perfect sense. Here's the stage where my brain gets wadded into a ball of mush and stomped on repeatedly...lolSyntax
The first hurdle is the syntax. There are 2 particular issues I'm having now when reading the code. I will see the asterisk(*) used in contradictory ways. i.e:
...
// Used at the end of a word before the declared variable?
void RenderMeshExample::buildConvex( const Box3F& box, Convex* convex )
...
// or used at the start of the variable itself?
RenderMeshConvex *boxConvex = NULL;
...What distinguishes one usage from the other? This particularly isn't an extreme show-stopper; I just sort of let my mind accept it's a variable on move on through the example. But I would like to understand on a more genuine level :)Okay, syntax problem #2. I see the & symbol on some variables in some places but not present in others:
... // Here we find the & in Box3F& void RenderMeshExample::buildConvex( const Box3F& box, Convex* convex ) ... // Here we find it in &wl CollisionWorkingList &wl = convex->getWorkingList();I am brand new to this syntax, so I'm used to seeing things like U32, bool, int, and so on. What is the meaning of this & ?
I realize this may just be explained away with a good document. Any direction for my personal research could go a long ways.
Conceptually Makes Sense
I would like to say that conceptually this is solid. I see the point of the added mConvexList and how it must be used to keep track of the added collisions. Otherwise we'd just add a bunch of stuff that we'd never be able to reference later. Check. Some of the inner workings of the buildConvex function are honestly being lost on me, perhaps not because I wouldn't otherwise understand what's being said but because the syntax isn't clear. Maybe a little bit of advice by ways of additional comments or just a link to a solid document could help. I'm at a stage where I'm able to follow the concepts but stumbling over the wording. For me, with such dedicated instruction, I'm not willing to accept this as satisfactory. I don't want to be able to 'monkey see, monkey do'. I want to be able to grow personally and walk away from all of this an improved version of what was there before. I guess that makes sense...lol :P
The Raycasting
I read over the linked wiki article(which was a nice overview thanks) and also stepped through all of the code. Here is the intial problem I had with understanding the castRay:
// start and end are already in local coordinates, so we'll just use the
// cube positions directly to create our box.This part threw me for a loop because I don't understand how the start and end are going to be local coordinates. Isn't the start of the ray either the player object's eyepoint or the camera (preferably the latter). I was able to step through the example and make sense of it, though. Besides being confused by the start and end declarations, I did understand the way that t was being compared to the results to determine which was closest. Which would in turn provide the desired info about the object in question. Cheers, thanks so much for the study guide. I haven't dug into the added #includes yet, but that'll be in the morning! Good night :)
#134
To answer your first question, these three are all identical:
Okay, now you know about that syntax, here's the 50,000 foot overview: a pointer is just a memory address. You declare a pointer type using *. So an int* is a memory address where an int lives. A Point3F* is a memory address where a Point3F lives. NULL is just address 0, where nothing will ever live, so it's like 'no address'.
A reference is basically the same as a pointer, but it can never be NULL. You declare a reference with &, so Point3F& is a memory address where a Point3F lives, but it'll always point to a valid object. With a pointer you're allowed to say Point3F*x = NULL, so x doesn't point to a valid Point3F. References don't let you do that.
Okay, now that's out of the way, go read all about pointers :P. If that's a bit overbearing, let us know, and we can break it down some more. Trust me, pointers and references are one of the scariest concepts in C/C++, but the most fundamental and rewarding.
The global Container, before it calls castRay on each object, transforms the points into the object's local coordinates. It's a bit sneaky, and was presumably done to save people from duplicating that logic everywhere they might need to do that.
09/23/2014 (9:26 pm)
Ah, welcome to the wonderful world of pointers (*) and references (&). I'll be clear here. The symbols * and & are both used in two different contexts. First they can be used as part of a type. That's what you're seeing in function and variable declarations:... void RenderMeshExample::buildConvex( const Box3F& box, Convex* convex ) RenderMeshConvex *boxConvex = NULL; CollisionWorkingList &wl = convex->getWorkingList();In all those three cases, the * or & is part of the type of the variable. You'll also see both of these characters uses as operators, like so:
handle = &something; value = *somethingElse;for example. Try to make sure you're clear, when you're looking at a * or an &, whether it's part of a type, or whether it's an operator.
To answer your first question, these three are all identical:
int * x; int* x; int *x;The spacing doesn't matter. However, some people prefer to attach the * to the variable name, because of this:
int* x, y;You'd think this created two int pointers, but it actually is equivalent to this:
int* x; int y;Which is not what you'd expect. This is an awful part of C syntax. To get around it, either don't declare two variables in the same statement, or do this:
int *x, *y;
Okay, now you know about that syntax, here's the 50,000 foot overview: a pointer is just a memory address. You declare a pointer type using *. So an int* is a memory address where an int lives. A Point3F* is a memory address where a Point3F lives. NULL is just address 0, where nothing will ever live, so it's like 'no address'.
A reference is basically the same as a pointer, but it can never be NULL. You declare a reference with &, so Point3F& is a memory address where a Point3F lives, but it'll always point to a valid object. With a pointer you're allowed to say Point3F*x = NULL, so x doesn't point to a valid Point3F. References don't let you do that.
Okay, now that's out of the way, go read all about pointers :P. If that's a bit overbearing, let us know, and we can break it down some more. Trust me, pointers and references are one of the scariest concepts in C/C++, but the most fundamental and rewarding.
Quote:This part threw me for a loop because I don't understand how the start and end are going to be local coordinates.Basically, when something like a Projectile wants to do a raycast, it calls castRay() on a global scene object, which does the work of efficiently finding objects that might intersect the line. The global container then calls castRay on each object it thinks might intersect the ray, and these objects get to see if they actually do - this castRay is what we just implemented.
The global Container, before it calls castRay on each object, transforms the points into the object's local coordinates. It's a bit sneaky, and was presumably done to save people from duplicating that logic everywhere they might need to do that.
#135
I was a bit surprised to learn about this as well. It's the same for buildConvex. You don't need to change the cube positions into world positions, you just hand it all to it in local coordinates and it works fine. Makes everyones life easier =)
09/24/2014 (6:53 am)
One thing to note: you don't need to master all of this to move forward with what you're doing. If you hit a point where the advanced C++ is getting a bit much, just revisit it later and keep going with your goals. You don't NEED to understand ALL of the specifics. As long as you understand the motivation behind the buildConvex, and the fact we're handing it a bunch of mathematical cubes so it can run some fancy equations to figure out if we hit it.Quote:
// start and end are already in local coordinates, so we'll just use the
// cube positions directly to create our box.
I was a bit surprised to learn about this as well. It's the same for buildConvex. You don't need to change the cube positions into world positions, you just hand it all to it in local coordinates and it works fine. Makes everyones life easier =)
#136
EDIT: Also I forgot to thank Daniel for all the help with pointers. You've definitely put me on course to further my learning around C++. This is good stuff and I know that I can tackle this.
09/24/2014 (7:27 am)
That's a relief lol. I have been reading over the pointer/reference documentation and to be honest it is all making sense. I'm getting a tad bit confused with the way that the pointer changes the actual values, but it's nothing a little time and dedication won't make clear. Quote:I do totally understand this much. The fundamentals are all in place. I see the cubeList being iterated, and the position of cube being set to the position of the current cube in the list. Then checked with t to see what's closest. I've added the castRay function to my .cpp file, as well as the bool declaration in the header, yet I'm not sure exactly how to use it. My projectiles still don't collide with the objects, despite me being able to walk on them with the player. Of course I'm not actually calling on the castRay function; I'm not entirely clear how the function actually gets used. I see what it's doing, but not sure when/how to call on it. From the description above (Danny's post) it seems the projectile should kinda automatically act on it (by initiating the call to castRay).
As long as you understand the motivation behind the buildConvex, and the fact we're handing it a bunch of mathematical cubes so it can run some fancy equations to figure out if we hit it.
Quote:If you hit a point where the advanced C++ is getting a bit much, just revisit it later and keep going with your goalsRoger that, this is where I'm at. Some of the intricacies of the pointers and references are a bit hazy (although they at least make more sense and I know what it is I'm looking at now). Now I guess my biggest goal is trying to actually cast a ray(from the player or the camera), get a hit, and act on that result. I'd be trying this already but the newly created Sumbatrix object doesn't have a Typemask, so I'm not sure what to use as a searchmask.
EDIT: Also I forgot to thank Daniel for all the help with pointers. You've definitely put me on course to further my learning around C++. This is good stuff and I know that I can tackle this.
#137
That guy covers for syntax pretty well in a very short space.
C++ and C are both full of weird - C++ is gaining an accretion of weird as it evolves, too....
09/24/2014 (8:18 am)
Hey Jesse - http://stackoverflow.com/questions/1971311/what-does-it-mean-when-the-first-for-parameter-is-blankThat guy covers for syntax pretty well in a very short space.
C++ and C are both full of weird - C++ is gaining an accretion of weird as it evolves, too....
#138
As for the typemask, that's a good point, you can't tell when you've hit cubes since they're just regular statics. We could tack on another typemask pretty easily and that'll allow you to identify when you've hit cubes.
As far as I can tell it should be as simple as adding a new entry in here:
github.com/GarageGames/Torque3D/blob/69838bdc8c9bc055b9b1ae76f42b0f28d2a33909/En...
Like:
Then I found this, which is where it's exposed to torquescript:
github.com/GarageGames/Torque3D/blob/69838bdc8c9bc055b9b1ae76f42b0f28d2a33909/En...
So, just tack on:
Oh! And, actually make the cube objects have this typemask:
gist.github.com/andr3wmac/a16781a763cf0a87d49e#file-rendermeshexample-cpp-L62-L6...
Into:
That should be all you need. Now can you mask your raycasts in script to only pick up that type.
09/24/2014 (9:44 am)
I tried out the castRay function last night and was met with the same surprise as you Jesse. The weirdest part is, the code is correct and I traced it and it is actually hitting the cube, and hitting the right one. There's something else that's preventing Torque from being satisfied with that hit. I haven't had a chance to truly trace it and confirm. I'm using 3.5.1 master, I assume you're using the same Jesse? Dan says the hits are working in 3.5.1 dev (3.6 I guess you could call it) so I'm going to try to confirm that when I get home.As for the typemask, that's a good point, you can't tell when you've hit cubes since they're just regular statics. We could tack on another typemask pretty easily and that'll allow you to identify when you've hit cubes.
As far as I can tell it should be as simple as adding a new entry in here:
github.com/GarageGames/Torque3D/blob/69838bdc8c9bc055b9b1ae76f42b0f28d2a33909/En...
Like:
/// A section of cubes! /// @see RenderMeshExample CubeChunkObjectType = BIT( 23 ),
Then I found this, which is where it's exposed to torquescript:
github.com/GarageGames/Torque3D/blob/69838bdc8c9bc055b9b1ae76f42b0f28d2a33909/En...
So, just tack on:
Con::setIntVariable("$TypeMasks::CubeChunk", CubeChunkObjectType);Oh! And, actually make the cube objects have this typemask:
gist.github.com/andr3wmac/a16781a763cf0a87d49e#file-rendermeshexample-cpp-L62-L6...
Into:
mTypeMask |= StaticObjectType | StaticShapeObjectType | CubeChunkObjectType;
That should be all you need. Now can you mask your raycasts in script to only pick up that type.
#139
@Andrew: I'm using 3.5.1 dev branch, but it's been a couple weeks since I downloaded it...I'm relatively sure, though, nothing's changed in that span of time relating to this (raycast collision) specifically. Could be wrong :)
About the typemask stuff, thanks that looks very cool! I'm a bit busy atm but I'll plug all that in as soon as I get the chance and report.
09/24/2014 (10:36 am)
@Richard: Thanks, I had pretty much come to the same conclusion about the empty first argument. Although reading the specifics about the scope of the variable does serve to drive the entire point home :)@Andrew: I'm using 3.5.1 dev branch, but it's been a couple weeks since I downloaded it...I'm relatively sure, though, nothing's changed in that span of time relating to this (raycast collision) specifically. Could be wrong :)
About the typemask stuff, thanks that looks very cool! I'm a bit busy atm but I'll plug all that in as soon as I get the chance and report.
#140
Regenerated the project, and recompiled it. Got the following errors on compile:
I tried to drop in an added #include to my submatrix.cpp (objectTypes.h) just in case but no dice. Considering the error above is also occurring in the gameFunctions.cpp file, I imagine there is probably just some other small missing piece to the puzzle. Gotta run for now, but I should be back to check closer within the hour. Cheers!
EDIT: Okay, took a close look at the includes and the objectTypes.h should already be picked up by sceneObject.h, which is already included in submatrix.h. Probably some other reference someplace to the typemasks that we're missing, I'll continue to search.
EDIT2: Found a tiny reference to TypeMasks in sceneObject.h:
09/24/2014 (11:26 am)
In and out the door, but here's what I did:- Copied objectTypes.h and gameFunctions.cpp to my /source folder.
- Added: objectTypes.h
SubmatrixObjectType = BIT( 23 ),gameFunctions.cpp
Con::setIntVariable("$TypeMasks::SubmatrixObjectType", SubmatrixObjectType);submatrix.cppmTypeMask |= StaticObjectType | StaticShapeObjectType | SubmatrixObjectType;
c:devtorque3dtorque3d-developmentmy projectscubessourcesubmatrix.cpp(63): error C2065: 'SubmatrixObjectType' : undeclared identifier c:devtorque3dtorque3d-developmentmy projectscubessourcegamefunctions.cpp(464): error C2065: 'SubmatrixObjectType' : undeclared identifier
I tried to drop in an added #include to my submatrix.cpp (objectTypes.h) just in case but no dice. Considering the error above is also occurring in the gameFunctions.cpp file, I imagine there is probably just some other small missing piece to the puzzle. Gotta run for now, but I should be back to check closer within the hour. Cheers!
EDIT: Okay, took a close look at the includes and the objectTypes.h should already be picked up by sceneObject.h, which is already included in submatrix.h. Probably some other reference someplace to the typemasks that we're missing, I'll continue to search.
EDIT2: Found a tiny reference to TypeMasks in sceneObject.h:
/// Object type mask.
/// @see SimObjectTypes
U32 mTypeMask;Found simObject.h and simObject.cpp in the engine/source/console folder, although tbh none of that seemed related to this. Figured I'd drop it here though in case it was valid(doesn't look like it). I was thinking on this some, and perhaps it would be possible to live without a custom TypeMask if you filtered the raycast result additionally by class or something. You might get additional statics in the raycast, but could probably filter those out. Would be nice to be able to setup a custom TypeMask though. Could come in handy with other applications besides just this one :D
Andrew Mac
Come again? DefineEngineMethod is for exposing particular functions of objects to TorqueScript. It's not used to expose the actual object to TorqueScript for creation. That would be DECLARE_CONOBJECT that's inside the .h file.