How does this lighting calculation work? - c++

I have that piece of code that is responsible for lighting a pyramid.
float Geometric3D::calculateLight(int vert1, int vert2, int vert3) {
float ax = tabX[vert2] - tabX[vert1];
float ay = tabY[vert2] - tabY[vert1];
float az = tabZ[vert2] - tabZ[vert1];
float bx = tabX[vert3] - tabX[vert1];
float by = tabY[vert3] - tabY[vert1];
float bz = tabZ[vert3] - tabZ[vert1];
float Nx = (ay * bz) - (az * by);
float Ny = (az * bx) - (ax * bz);;
float Nz = (ax * by) - (ay * bx);;
float Lx = -300.0f;
float Ly = -300.0f;
float Lz = -1000.0f;
float lenN = sqrtf((Nx * Nx) + (Ny * Ny) + (Nz * Nz));
float lenL = sqrtf((Lx * Lx) + (Ly * Ly) + (Lz * Lz));
float res = ((Nx * Lx) + (Ny * Ly) + (Nz * Lz)) / (lenN * lenL);
if (res < 0.0f)
res = -res;
return res;
}
I cannot understand calculations at the end. Can someone explain me the maths that is behind them? I know that firstly program calculates two vectors of a plane to compute the normal of it (which goes for vector N). Vector L stand for lighting but what happens next? Why do we calculate length of normal and light then multiply it and divide by their sizes?

Related

3D sphere vs sphere collision resolve problem

I have been watching OneLoneCoder video about circle collision resolve
and use the code from git.
But the code is for 2D case, i.e. circles, and I need a solution for spheres. So I tried to add Z-component to equations but getting failures.
So I am testing the next way: I create two spheres, one above other. Lower is situated a heavy sphere, upper a tiny. The higher sphere is falling. In reality tiny should bounce up, but it just stuck, and they are falling as a single body for a while, but then the higher sphere is bouncing up. Also the sphere per each jump gets higher(see gif):
Here is the code:
/*
vertex - VERTEX **vertex=new VERTEX*[100];
vc - vertex count (how many vertices are currently created)
*/
void Update()
{
auto DoCirclesOverlap = [](float x1, float y1, float z1, float r1, float x2, float y2, float z2, float r2)
{
return ((x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2) + (z1 - z2)*(z1 - z2)) <= (r1 + r2)*(r1 + r2);
};
vector<pair<VERTEX*, VERTEX*>> vecCollidingPairs;
// Update vertex[i] Positions
for (int i = 0;i < vc;i++)
{
// Update vertex[i] physics
vertex[i]->x += vertex[i]->vx * TIME_QUANT_CONSTANT;
vertex[i]->y += vertex[i]->vy * TIME_QUANT_CONSTANT;
vertex[i]->z += vertex[i]->vz * TIME_QUANT_CONSTANT;
}
// Static collisions, i.e. overlap
for (int i(0);i < vc;i++)
{
for(int j(0);j < vc;j++)
{
if (vertex[i]->index != vertex[j]->index)
{
if (DoCirclesOverlap(vertex[i]->x, vertex[i]->y, vertex[i]->z, vertex[i]->size, vertex[j]->x, vertex[j]->y, vertex[j]->z, vertex[j]->size))
{
// Collision has occured
vecCollidingPairs.push_back({ vertex[i], vertex[j] });
// Distance between vertex[i] centers
float fDistance = sqrtf((vertex[i]->x - vertex[j]->x)*(vertex[i]->x - vertex[j]->x) + (vertex[i]->y - vertex[j]->y)*(vertex[i]->y - vertex[j]->y) + (vertex[i]->y - vertex[j]->y)*(vertex[i]->y - vertex[j]->y));
// Calculate displacement required
float fOverlap = 0.5f * (fDistance - vertex[i]->size - vertex[j]->size);
// Displace Current vertex[i] away from collision
vertex[i]->x -= fOverlap * (vertex[i]->x - vertex[j]->x) / fDistance;
vertex[i]->y -= fOverlap * (vertex[i]->y - vertex[j]->y) / fDistance;
vertex[i]->z -= fOverlap * (vertex[i]->z - vertex[j]->z) / fDistance;
// Displace vertex[j] vertex[i] away from collision
vertex[j]->x += fOverlap * (vertex[i]->x - vertex[j]->x) / fDistance;
vertex[j]->y += fOverlap * (vertex[i]->y - vertex[j]->y) / fDistance;
vertex[j]->z += fOverlap * (vertex[i]->z - vertex[j]->z) / fDistance;
}
}
}
}
// Now work out dynamic collisions
for (auto c : vecCollidingPairs)
{
VERTEX *b1 = c.first;
VERTEX *b2 = c.second;
// Distance between vertex[i]s
float fDistance = sqrtf((b1->x - b2->x)*(b1->x - b2->x) + (b1->y - b2->y)*(b1->y - b2->y) + (b1->z - b2->z)*(b1->z - b2->z));
// Normal
float nx = (b2->x - b1->x) / fDistance;
float ny = (b2->y - b1->y) / fDistance;
float nz = (b2->z - b1->z) / fDistance;
// Tangent
float tx = -ny;
float ty = nx;
float tz = nz;
// Dot Product Tangent
float dpTan1 = b1->vx * tx + b1->vy * ty + b1->vz * tz;
float dpTan2 = b2->vx * tx + b2->vy * ty + b2->vz * tz;
// Dot Product Normal
float dpNorm1 = b1->vx * nx + b1->vy * ny + b1->vz * nz;
float dpNorm2 = b2->vx * nx + b2->vy * ny + b2->vz * nz;
// Conservation of momentum in 1D
float m1 = (dpNorm1 * (b1->mass - b2->mass) + 2.0f * b2->mass * dpNorm2) / (b1->mass + b2->mass);
float m2 = (dpNorm2 * (b2->mass - b1->mass) + 2.0f * b1->mass * dpNorm1) / (b1->mass + b2->mass);
// Update ball velocities
b1->vx = tx * dpTan1 + nx * m1;
b1->vy = ty * dpTan1 + ny * m1;
b1->vz = tz * dpTan1 + nz * m1;
b2->vx = tx * dpTan2 + nx * m2;
b2->vy = ty * dpTan2 + ny * m2;
b2->vz = tz * dpTan2 + nz * m2;
}
}
What is the problem?
Thanks for #Tyyppi_77 from Stack GameDev, where I posted the same question, that pointed that the issue was on line
float fDistance = sqrtf((vertex[i]->x - vertex[j]->x)*(vertex[i]->x - vertex[j]->x) + (vertex[i]->y - vertex[j]->y)*(vertex[i]->y - vertex[j]->y) + (vertex[i]->y - vertex[j]->y)*(vertex[i]->y - vertex[j]->y));
And the correct one is
float fDistance = sqrtf((vertex[i]->x - vertex[j]->x)*(vertex[i]->x - vertex[j]->x) + (vertex[i]->y - vertex[j]->y)*(vertex[i]->y - vertex[j]->y) + (vertex[i]->z - vertex[j]->z)*(vertex[i]->z - vertex[j]->z));
It just solved almost all of issues. The only terrible thing is, because of static collision, the lower and much more heavier sphere is a little bit shifts down while it is hit by the sphere above. Do You know how it can be solved?

How do I resolve a collision's position properly in 2D collision detection?

My current implementation looks like this:
if (shapesCollide) {
if (velocity.y > 0) entity.position.y = other.position.y - entity.size.y;
else entity.position.y = other.position.y + other.size.y;
velocity.y = 0;
if (velocity.x > 0) entity.position.x = other.position.x - entity.size.x;
else entity.position.x = other.position.x + other.size.x;
velocity.x = 0;
}
However, this leads to weird handling when movement is happening on both axes - for example, having entity moving downward to the left of object, and then moving it to collide with object, will correctly resolve the horizontal collision, but will break the vertical movement.
I previously simply went
if (shapesCollide) {
position = oldPosition;
velocity = { 0, 0 };
}
But this lead to another multi-axis issue: if I have my entity resting atop the object, it will be unable to move, as the gravity-induced movement will constantly cancel out both velocities. I also tried considering both axes separately, but this lead to issues whenever the collision only occurs when both velocities are taken into account.
What is the best solution to resolving collision on two axes?
I assume that the entities can be considered to be more or less round and that size is the radius of the entities?
We probably need a little vector math to resolve this. (I don't know the square-root function in c++, so be aware at sqrt.) Try replacing your code inside if(shapesCollide) with this and see how it works for you.
float rEntity = sqrt(entity.size.x * entity.size.x + entity.size.y * entity.size.y);
float rOther = sqrt(other.size.x * other.size.x + other.size.y * other.size.y);
float midX = (entity.position.x + other.position.x) / 2.0;
float midY = (entity.position.y + other.position.y) / 2.0;
float dx = entity.position.x - midX;
float dy = entity.position.y - midY;
float D = sqrt(dx * dx + dy * dy);
rEntity and rOther are the radii of the objects, and midX and midY are their center coordinates. dx and dy are the distances to the center from the entity.
Then do:
entity.position.x = midX + dx * rEntity / D;
entity.position.y = midY + dy * rEntity / D;
other.position.x = midX - dx * rOther / D;
other.position.y = midY - dy * rOther / D;
You should probably check that D is not 0, and if it is, just set dx = 1, dy = 0, D = 1 or something like that.
You should also still do:
velocity.x = 0;
velocity.y = 0;
if you want the entities to stop.
For more accurate modelling, you could also try the following:
float rEntity = sqrt(entity.size.x * entity.size.x + entity.size.y * entity.size.y);
float rOther = sqrt(other.size.x * other.size.x + other.size.y * other.size.y);
float midX = (entity.position.x * rOther + other.position.x * rEntity) / (rEntity + rOther);
float midY = (entity.position.y * rOther + other.position.y * rEntity) / (rEntity + rOther);
float dxEntity = entity.position.x - midX;
float dyEntity = entity.position.y - midY;
float dEntity = sqrt(dxEntity * dxEntity + dyEntity * dyEntity);
float dxOther = other.position.x - midX;
float dyOther = other.position.y - midY;
float dOther = sqrt(dxOther * dxOther + dyOther * dyOther);
entity.position.x = midX + dxEntity * rEntity / dEntity;
entity.position.y = midY + dyEntity * rEntity / dEntity;
other.position.x = midX + dxOther * rOther / dOther;
other.position.y = midY + dyOther * rOther / dOther;
which finds the midpoints when the radii are taken into account. But I won't guarantee that that works. Also, the signs on the last additions are important.
I hope this helps (and works). Let me know if something is unclear.

C++ Angles between a vector and a point

I got 2 points own=(x, y, z) and en=(x, y, z) which represents my own position in the world and some other player position. the other player also got pitch (from 90 degrees to -90) and yaw (0 to 360). I want to calculate the angles between the other player look and my own position.
In 2D, alpha is what I'm trying to calculate:
int main()
{
float own_x = 1, own_y = 1, own_z = 1;
float en_x = 10, en_y = 1, en_z = 10;
float pi = 3.14159265;
float pitch = 0.f * (pi / 180), yaw = 45.f * (pi / 180);
float x = sin(yaw) * cos(pitch);
float y = sin(pitch);
float z = cos(pitch) * cos(yaw);
float vec_length = sqrt(pow(en_x - own_x, 2) + pow(en_y - own_y, 2) + pow(en_y - own_y, 2));
x /= vec_length;
y /= vec_length;
z /= vec_length;
float cos_t = ((en_x - own_x)*x + (en_y - own_y)*y + (en_z - own_z)*z) / sqrt(pow(en_x - own_x, 2) + pow(en_y - own_y, 2) + pow(en_y - own_y, 2));
float arc = acos(cos_t) * (180 / pi);
return 0;
}
you divide twice with the length of en-own: You should remove
vec_length, and xyz /= vec_length.
your division at cos_t is buggy, you use _y twice in the
expression instead of _y and _z
Note: instead of pow(x, 2), use x*x, it is faster usually (compilers may not optimize pow(x, 2) to x*x).

Half of my ellipse drawn in the wrong place

Here is the code for an oval drawing method I am working on. I am applying the Bresenham method to plot its co-ordinates, and taking advantage of the ellipse's symmetrical properties to draw the same pixel in four different places.
void cRenderClass::plotEllipse(int xCentre, int yCentre, int width, int height, float angle, float xScale, float yScale)
{
if ((height == width) && (abs(xScale - yScale) < 0.005))
plotCircle(xCentre, yCentre, width, xScale);
std::vector<std::vector <float>> rotate;
if (angle > 360.0f)
{
angle -= 180.0f;
}
rotate = maths.rotateMatrix(angle, 'z');
//rotate[0][0] = cos(angle)
//rotate[0][1] = sin(angle)
float theta = atan2(-height*rotate[0][1], width*rotate[0][0]);
if (angle > 90.0f && angle < 180.0f)
{
theta += PI;
}
//add scalation in at a later date
float xShear = (width * (cos(theta) * rotate[0][0])) - (height * (sin(theta) * rotate[0][1]));
float yShear = (width * (cos(theta) * rotate[0][1])) + (height * (sin(theta) * rotate[0][0]));
float widthAxis = abs(sqrt(((rotate[0][0] * width) * (rotate[0][0] * width)) + ((rotate[0][1] * height) * (rotate[0][1] * height))));
float heightAxis = (width * height) / widthAxis;
int aSquared = widthAxis * widthAxis;
int fourASquared = 4*aSquared;
int bSquared = heightAxis * heightAxis;
int fourBSquared = 4*bSquared;
x0 = 0;
y0 = heightAxis;
int sigma = (bSquared * 2) + (aSquared * (1 - (2 * heightAxis)));
while ((bSquared * x0) <= (aSquared * y0))
{
drawPixel(xCentre + x0, yCentre + ((floor((x0 * yShear) / xShear)) + y0));
drawPixel(xCentre - x0, yCentre + ((floor((x0 * yShear) / xShear)) + y0));
drawPixel(xCentre + x0, yCentre + ((floor((x0 * yShear) / xShear)) - y0));
drawPixel(xCentre - x0, yCentre + ((floor((x0 * yShear) / xShear)) - y0));
if (sigma >= 0)
{
sigma += (fourASquared * (1 - y0));
y0--;
}
sigma += (bSquared * ((4 * x0) + 6));
x0++;
}
x0 = widthAxis;
y0 = 0;
sigma = (aSquared * 2) + (bSquared * (1 - (2 * widthAxis)));
while ((aSquared * y0) <= (bSquared * x0))
{
drawPixel(xCentre + x0, yCentre + ((floor((x0 * yShear) / xShear)) + y0));
drawPixel(xCentre - x0, yCentre + ((floor((x0 * yShear) / xShear)) + y0));
drawPixel(xCentre + x0, yCentre + ((floor((x0 * yShear) / xShear)) - y0));
drawPixel(xCentre - x0, yCentre + ((floor((x0 * yShear) / xShear)) - y0));
if (sigma >= 0)
{
sigma += (fourBSquared * (1 - x0));
x0--;
}
sigma += (aSquared * (4 * y0) + 6);
y0++;
}
//the above algorithm hasn't been quite completed
//there are still a few things I want to enquire Andy about
//before I move on
//this other algorithm definitely works
//however
//it is computationally expensive
//and the line drawing isn't as refined as the first one
//only use this as a last resort
/* std::vector<std::vector <float>> rotate;
rotate = maths.rotateMatrix(angle, 'z');
float s = rotate[0][1];
float c = rotate[0][0];
float ratio = (float)height / (float)width;
float px, py, xNew, yNew;
for (int theta = 0; theta <= 360; theta++)
{
px = (xCentre + (cos(maths.degToRad(theta)) * (width / 2))) - xCentre;
py = (yCentre - (ratio * (sin(maths.degToRad(theta)) * (width / 2)))) - yCentre;
x0 = (px * c) - (py * s);
y0 = (px * s) + (py * c);
drawPixel(x0 + xCentre, y0 + yCentre);
}*/
}
Here's the problem. When testing the rotation matrix on my oval drawing function, I expect it to draw an ellipse at a slant from its original horizontal position as signified by 'angle'. Instead, it makes a heart shape. This is sweet, but not the result I want.
I have managed to get the other algorithm (as seen in the bottom part of that code sample) working successfully, but it takes more time to compute, and doesn't draw lines quite as nicely. I only plan to use that if I can't get this Bresenham one working.
Can anyone help?

Optimizing circle-circle collision response

With SFML, I made an algorithm that calculates the trajectoris of two balls after a collision; it works fine, but if I try with more than 30 balls, it freezes instantly or after 10-20 seconds.
I tried to avoid doing the same calculations multiple times, but it doesn't work.
Any suggestions?(I have an high-end PC, the problem is not there)
Phi is the collision angle, dis is distance;
void collisionResponse(Circle &a, Circle &b)
{
float mass1 = a.getMass();
float mass2 = b.getMass();
float disX = a.pos.x - b.pos.x;
float disY = a.pos.y - b.pos.y;
float phi = atan2(disY, disX);
float speed1 = a.getSpeed();
float speed2 = b.getSpeed();
float angle1 = a.getAngle();
float angle2 = b.getAngle();
float v1x = speed1*cos((angle1 - phi));
float v1y = speed1*sin((angle1 - phi));
float v2x = speed2*cos((angle2 - phi));
float v2y = speed2*sin((angle2 - phi));
float f1x = ((mass1 - mass2)*v1x + (mass2 + mass2)*v2x) / (mass1+mass2);
float f2x = ((mass1 + mass1)*v1x + (mass2 - mass1)*v2x) / (mass1+mass2);
float f1y = v1y;
float f2y = v2y;
float cosphi = cos(phi);
float sinphi = sin(phi);
float cosphiPI = cos(phi + PI / 2);
float sinphiPI = sin(phi + PI / 2);
a.speed.x = cosphi*f1x + cosphiPI*f1y;
a.speed.y = sinphi*f1x + sinphiPI*f1y;
b.speed.x = cosphi*f2x + cosphiPI*f2y;
b.speed.y = sinphi*f2x + sinphiPI*f2y;
while (sqr(a.pos.x - b.pos.x) + sqr(a.pos.y - b.pos.y) <= sqr(a.getRadius()+ b.getRadius()))
{
a.Move();
b.Move();
}
}