Scaling objects from a center point by a specific number - c++

I'm not sure if doing something wrong in my program or not but I could use some quick guidance if you could and more than likely the problem is I'm thinking to hard about it (which is always the case for me) and I can't think of the way to explain it (hence the crappy title of this question) and gave me a little trouble simply Googling for help.
I'm aware of how to scale an object by way of:
double scale = 2.0;
Array<Real2> newPoints;
Foreach(Real2 point, points)
{
Vector2 vector = point - centerPoint;
vector *= scale;
newPoints.Add(center + vector);
}
However let's say I wanted to scale the size of the object by 3.6(units) instead of by a percentage.. How would I go about that?
It made sense to me at least that I would do something along the lines of
vector *= 1 - (3.6/vector.length);
but I'm still getting incorrect results running my application. Any help on this issue? Like I said sorry if I explained this incorrectly, I'm horrible when it comes to that stuff so if there's anyway i can clarify let me know. Thank you for your help.

It seems that you want to scale the object so that it's new size is (say) 3.6 units larger than it's old size. In that case, the code would be the same except for
scale = (old_size + 3.6) / old_size;
You still need to scale each vector by the same amount, in order to preserve the overall shape of the object.

Related

My raw primitives cannot be displayed in Raymarching

I encountered a very strange problem while learning Raymarching.
My equation cannot be displayed well.
It can be displayed well in matlab. But it can't be shown on Shadertoy at all.
My equation:
f(x,y,z) = (x^2+y^2+z^2)^2+2*y*(x^2+y^2+z^2)+2*(x^2+z^2);
code in matlab:
f =#(x,y,z) (x.^2+y.^2+z.^2)^2+2*y*(x.^2+y.^2+z.^2)+2*(x.^2+z.^2);
fimplicit3(f)
matlab displays a normal picture
code in shadertoy:
float sdRound(vec3 p)
{
float lengthXYZ = (p.x * p.x+p.y * p.y+p.z * p.z);
return lengthXYZ * lengthXYZ+2.0 * p.y * lengthXYZ+2.0 * (p.x * p.x+p.z * p.z);
}
I learned, practiced, and modified the iq code. (https://www.shadertoy.com/view/Xds3zN).
But it cannot be displayed normally.
Shadertoy displays abnormal pictures
Shadertoy displays abnormal pictures
I don't know where the problem occurred. Please help me. Has troubled me for a long time.
Forgive my poor English. I use Google Translate.
Your problem seems to lay in the very understanding of what raymarching is.
Your formula mathematically describes a surface (that is why it is displayed nicely in matlab), but this is not how raymarching works.
Defining an object for raymarching means defining a distance function for your object (which is different from a function mathematically describing its surface). These functions are identical for zero-returned values (which means coordinates are on the surface), but they are different for other values.
To create something similar to your object, I would suggest to explore the sdRoundCone method from iq's Raymarching primitives, as it seems the closest to what you want to achieve.

Multiple instances of btDefaultMotionState, all ignored, but one

To summarize the problem(s):
I have two bodies in my world so far, one being the ground, the other one being a falling box called "fallingStar".
1) I do not understand why my bullet world is not aligned with my drawn world unless I set an offset of btVector3(2,2,2) to the (btDefault)MotionState.
There is no fancy magic going on anywhere in the code that would explain the offset. Or at least I could not find any reason, not in the shaders, not anywhere.
2) I expected to be able to use multiple instances of btDefaultMotionState, to be precise, I wanted to use one instance for the falling entity and place it somewhere above the ground and then create another instance for the ground that should simply be aligned with my graphics-ground, ever unmoving.
What I am experiencing in regards to 2) is that for whatever reason the btDefaultMotionState instance for the falling entity is always also influencing the one for the ground, without any reference.
Now to the code:
Creation of the fallingBox:
btCollisionShape *fallingBoxShape = new btBoxShape(btVector3(1,1,1));
btScalar fallingBoxMass = 1;
btVector3 fallingBoxInertia(0,0,0);
fallingBoxShape->calculateLocalInertia(fallingBoxMass, fallingBoxInertia);
// TODO this state somehow defines where exactly _ALL_ of the physicsWorld is...
btDefaultMotionState *fallMotionState = new btDefaultMotionState(btTransform(btQuaternion(0,0,0,1), btVector3(2,2,2)));
//btDefaultMotionState *fallMotionState = new btDefaultMotionState();
btRigidBody::btRigidBodyConstructionInfo fallingBoxBodyCI(fallingBoxMass, fallMotionState, fallingBoxShape, fallingBoxInertia);
/*btTransform initialTransform;
initialTransform.setOrigin(btVector3(0,5,0));*/
this->fallingBoxBody = new btRigidBody(fallingBoxBodyCI);
/*fallMotionState->setWorldTransform(initialTransform);
this->fallingBoxBody->setWorldTransform(initialTransform);*/
this->physicsWorld->addBody(*fallingBoxBody);
Now the interesting parts to me are the necessary offset of btVector3(2,2,2) to align it with my drawn world and this:
btTransform initialTransform;
initialTransform.setOrigin(btVector3(0,5,0));
this->fallingStarBody = new btRigidBody(fallingStarBodyCI);
fallMotionState->setWorldTransform(initialTransform);
If I reenable this part of the code ALL the bodies again show an offset, but NOT just 5 up, which I could somehow comprehend if for whatever reason the worldTransform would effect every entity, but about 2,2,2 off... which I cannot grasp at all.
I guess that this line is useless:
fallMotionState->setWorldTransform(initialTransform); as it does not change anything whether it's there or not.
Now to the code of the ground creation:
btCompoundShape *shape = new btCompoundShape();
... just some logic, nothing to do with bullet
btTransform transform;
transform.setIdentity();
transform.setOrigin(btVector3(x + (this->x * Ground::width),
y + (this->y * Ground::height),
z + (this->z * Ground::depth)));
btBoxShape *boxShape = new btBoxShape(btVector3(1,0,1)); // flat surface, no box
shape->addChildShape(transform, boxShape);
(this portion just creates a compoundshape for each surface tile :)
btRigidBody::btRigidBodyConstructionInfo info(0, nullptr, shape);
return new btRigidBody(info);
Here I purposely set the motionstate to nullptr, but this doesn't change anything.
Now I really am curious... I thought maybe the implementation of btDefaultMotionState is a singleton, but it doesn't look so, so... why the hell is setting the motionState of one body affecting the whole world?
Bullet is a good library but only few dedicate time to write good documentation.
To set position of a btRigidBody, try this :-
btTransform transform = body -> getCenterOfMassTransform();
transform.setOrigin(aNewPosition); //<- set orientation / position that you like
body -> setCenterOfMassTransform(transform);
If your code is wrong only at the set transformation part (that is what I guess from skimming your code), it should be solved.
Note that this snippet works only for dynamic body, not static body.
About CompoundBody:-
If it is a compound body, e.g. shape B contains shape C.
Setting transformation of B would work (set body of B), but not work for C.
(because C is just a shape, transformation support only body.)
If I want to change relative transformation of C to B, I would create a whole new compound shape and a new rigid body. Don't forget to remove old body & shape.
That is a library limitation.
P.S.
I can't answer some of your doubt/questions, these information are what I gathered after stalking in Bullet forum for a while, and tested by myself.
(I am also coding game + game library from scratch, using Bullet and other open sources.)
Edit: (about the new problem)
it just slowly falls down (along with the ground itself, which should
not move as I gave it a mass of 0)
I would try to solve it in this order.
Idea A
Set to the compound mass = 0 instead, because setting a child shape's mass has no meaning.
Idea B
First check -> getCenterOfMassTransform() every time-step , is it really falling?
If it is actually falling, to be sure, try dynamicsWorld->setGravity(btVector3(0,0,0));.
If still not work, try with very simple world (1 simple object, no compound) and see.
Idea C (now I start to be desperate)
Ensure your camera position is constant.
If the problem is still alive, I think you now can create a simple test-case and post it in Bullet forum without too much effort.
Lower amounts of lines of code = better feedback
What you are describing is not normal bullet behavior. Your understanding of the library is correct.
What you are most likely dealing with is either a buffer overrun or a dangling pointer. The code you have posted does not have an obvious one of either, so it would be coming from somewhere else in your codebase. You might be able to track that down using a well-placed memory breakpoint.
You "might" be dealing with a header/binary version inconsistency issue, but that's less likely as you would probably be seeing other major issues.
Just had the exact same type of behavior with the DebugDrawer suspended on top of the world. Solved it by passing to Bullet Physics the projectionview matrix alone, without the model matrix that he has and multiplies with already:
glUseProgram(shaderID);
m_MVP = m_camera->getProjectionViewMatrix();
glUniformMatrix4fv(shaderIDMVP, 1, GL_FALSE, &m_MVP[0][0]);
if (m_dynamicWorld) m_dynamicWorld->debugDrawWorld();

Sorting objects to the front or back depending on their position

I am trying to sort my renderables/actors correctly and noticed that I have some troubles with walls since they get sorted by their centerpoint. So I am sorting all my actors before I draw them depending on their distance to the camera with an insertion sort. After that, I am trying to determine if the wall should be drawn behind or in front of the gamefield. To explain this, the game takes place inside of a cube which is out of 6 planes. Since I can rotate the camera around that cube I need a sorting which would put the planes in front/back depending on that. So here is a picture so you know what we are talking about:
You can clearly see the rendermisstake whats happening at the front of those kind of snake.
Okay here is my current sorting:
//list of Actors the abstract class which Wall and cube and so on extend
void Group::insertionSort(vector<Actor *> &actors)
{
int j;
for (int i = 1; i < actors.size(); i++)
{
Actor *val = actors[i];
j = i - 1;
while (j >= 0 && distanceToCamera(*actors[j]) < distanceToCamera(*val))
{
actors[j + 1] = actors[j];
j = j - 1;
}
actors[j + 1] = val;
}
}
float Group::distanceToCamera(Actor &a)
{
float result = 0;
XMVECTOR posActor = XMLoadFloat3(&a.getPosition()); //here i get the centerpoint of the object
XMVECTOR posCamera = XMLoadFloat3(&m_camera->getPosition());
XMVECTOR length = XMVector3Length(posCamera - posActor);
XMStoreFloat(&result, length);
return result;
}
To determine if it's a Wall I used kind like this dynamic_cast<Wall*>(val) but I don't get them in front/back of the vector depending on that. To remember the objects return their centerpoint. Can anyone lead me to the right way?
It's difficult to answer your question because it is a complex system which you haven't fully explained here and which you should also reduce to something simpler before posting. Chances are that you would find a fix yourself on the way. Anyway, I'll do some guessing...
Now, the first thing I'd fix is the sorting algorithm. Without analysing it in depth whether it works correctly in all cases or not, I'd throw it out and use std::sort(), which is both efficient and very unlikely to contain errors.
While replacing it, you need to think about the ordering between two rendered objects carefully: The question is when exactly does one object need to be drawn before the other? You are using the distance of the center point to the camera. I'm not sure if you are sorting 2D objects or 3D objects, but in both cases it's easy to come up with examples where this doesn't work! For example, a large square that doesn't directly face the camera could cover up a smaller one, even if the smaller square's center is closer. Another problem is when two objects intersect. Similarly for 3D objects, if they have different sizes or intersect then your algorithm doesn't work. If your objects all have the same size and they can't intersect, you should be fine though.
Still, and here I suspect one problem, it could be that a surface of an object and a surface of the cube grid have exactly the same position. One approach is that you shrink the objects slightly or enlarge the outside grid, so that the order is always clear. This would also work around an issue that you suffer from floating point rounding errors. Due to these, two objects that don't have an order mathematically could end up in different positions depending on the circumstances. This can manifest as them flickering between visible to covered depending on the camera angle.
One last thing: I'm assuming you want to solve this yourself for educational reasons, right? Otherwise, it would be a plain waste of time with existing rendering toolkits in place that would even offload all the computations to the graphics hardware.

How to add camera damping?

I asked a question about how to add camera damping in Ogre but didnt get any answer so here is a more vague question.
How would you add camera damping?
I googled this question and got answers in XNA and Unity and each is different than the other so I cant even figure out what technique, function or maths they are using.
I have a camera and its position, I have an object and the position where I want the camera to be and slowly move it to that position, how can I do this?
I tried using lerp but it didnt work, I dont know if that is the wrong way of doing it or my lerp function might be wrong so I dont know.
Can someone please help me out. Thanks
Here is my lerp function
Ogre::Vector3 lerp (Ogre::Vector3 &sourceLocation, Ogre::Vector3 &destLocation, Ogre::Real Time)
{
return sourceLocation+ (destLocation - sourceLocation) * Time;
}
in cpp file
this->camPos = this->lerp(this->camPos, this->playerNode->getSceneNode()->getPosition() + Ogre::Vector3(0,60,-100), 1000.0f);
this->getCamera()->setPosition(this->camPos);
but the camera just ends up miles away from the object
Thanks for answering Peter. Makes a bit more sense now, the lerp function is just returning a long vector since the time is constant however Im not sure about the second part.
I need to have a variable that increments with the frame?
Ogre::Real frametime += frame_event.timeSinceLastFrame * 0.01;
this->camPos = this->lerp(this->camPos, this->playerNode->getSceneNode()->getPosition() + Ogre::Vector3(0,60,-100), frametime);
this does slowly move the camera towards the target and then stop but since the frametime is increasing, the time it takes to get to the target destination gets quicker as well. do I just set the frametime to 0 when it reaches destination?
can you please explain a bit more about the second part. I would really really appreciate your help.
Thanks
Your calculation for lerp is the issue, your getting the vector between dest and source and massively scaling it up.
Your lerp time should not be constant, it should be scaling from 0 to 1 based on the time period you want to go from source to dest.
Before moving:
float length= (dest -start).Length();
Update ()
float distancedTravelled = (CurrentTime - StartTime) * cameraSpeed;
float lerp = distanceTravelled /length;
Pass lerp to function.
Faster camera speed is the quicker you go

Calculating the bearing between two vectors then diff that against a passed angle

I am trying to find the 2D vector in a set that is closest to the provided angle from another vector.
So if I have v(10, 10) and I would like to find the closest other vector along an angle of 90 degrees it should find v(20, 10), for example. I have written a method that I think returns the correct bearing between two vectors.
float getBearing(
const sf::Vector2f& a, const sf::Vector2f& b)
{
float degs = atan2f(b.y - a.y, b.x - a.x) * (180 / M_PI);
return (degs > 0.0f ? degs : (360.0f + degs)) + 90.0f;
}
This seems to work okay although if I place one above another it returns 180, which is fine, and 360, which is just odd. Shouldn't it return 0 if it is directly above it? The best way to do that would be to check for 360 and return 0 I guess.
My problem is that I can't work out the difference between the passed angle, 90 degrees for example, and the one returned from getBearing. I'm not even sure if the returned bearing is correct in all situations.
Can anyone help correct any glaringly obvious mistakes in my bearing method and suggest a way to get the difference between two bearings? I have been hunting through the internet but there are so many ways to do it, most of which are shown in other languages.
Thanks.
If what you need is just to find the vectors nearest to a certain angle, you can follow #swtdrgn method; if, instead, you actually need to compute the angle difference between two vectors, you can exploit a simple property of the dot product:
where theta is the angle between the two vectors; thus, inverting the formula, you get:
I would suggest to take the two vectors that are being compared and do an unit dot product. The closest bearing should be greatest, 1 being the maximum (meaning the vectors are pointing to the same direction) and -1 being the minimum (meaning the vectors are pointing to opposite directions).
I have found a solution for now. I have spent a good few hours trying to solve this and I finally do it minutes after asking SO, typical. There may be a much better way of doing this, so I am still open to suggestions from other answers.
I am still using my bearing method from the question at the moment, which will always return a value between 0 and 360. I then get the difference between the returned value and a specified angle like so.
fabs(fmodf(getBearing(vectorA, vectorB) + 180 - angle, 360) - 180);
This will return a positive float that measures the distance in degrees between the bearing between two vectors. #swtdrgn's answer suggests using the dot product of the two vectors, this may be much simpler than my bearing method because I don't actually need the angle, I just need the difference.