In a directx application, find z (terrain) with known location - c++

My english knowlage is not good enought to tell my problems. and i am using stackoverflow second time.
i am hooking a directx application, i just can wrote something to screen and get input from screen and other things.
This game has a terrain, and a lot of players. I can directly edit the player location (x, z, y). But when i edit x and z coordinate, the player is flying :) because i don't know how to calculate the y coordinate (terrain height), i can't calculate it.
Player coordinate is 700, 5.41, 600
when game edit it to 800 and 700, game makes y to 6.50
when i edit it to 800 and 700, the y coordinate still 5.41
6.50 is coordinate, height of terrain of (800, 700), 5.41 is 700,600 terrain height.
Is there a any way to get height of the terrain for speficed coordinate?
Thank you much more.

I found it.
Thanks to everyone.
The game is using N3Terrain :)
float CN3Terrain::GetHeight(float x, float z)
{
int ix, iz;
ix = ((int)x) / TILE_SIZE;
iz = ((int)z) / TILE_SIZE;
if(ix<0 || ix>(m_ti_MapSize-2)) return -FLT_MAX;
if(iz<0 || iz>(m_ti_MapSize-2)) return -FLT_MAX;
float dX, dZ;
dX = (x - (ix*TILE_SIZE)) / TILE_SIZE;
dZ = (z - (iz*TILE_SIZE)) / TILE_SIZE;
float y;
float h1, h2, h3, h12, h13;
if((ix+iz)%2==0) //»ç°¢ÇüÀÌ / ¸ð¾ç..
{
h1 = m_pMapData[ix*m_ti_MapSize + iz].fHeight;
h3 = m_pMapData[(ix+1)*m_ti_MapSize + (iz+1)].fHeight;
if (dZ > dX) //À­ÂÊ »ï°¢Çü..
{
h2 = m_pMapData[ix*m_ti_MapSize + (iz+1)].fHeight;
h12 = h1 + (h2-h1) * dZ; // h1°ú h2»çÀÌÀÇ ³ôÀÌ°ª
h13 = h1 + (h3-h1) * dZ; // h1°ú h3»çÀÌÀÇ ³ôÀÌ°ª
y = h12 + ((h13-h12) * (dX/dZ)); // ã°íÀÚ ÇÏ´Â ³ôÀÌ°ª
return y;
}
else //¾Æ·¡ÂÊ »ï°¢Çü..
{
if(dX==0.0f) return h1;
h2 = m_pMapData[(ix+1)*m_ti_MapSize + iz].fHeight;
h12 = h1 + (h2-h1) * dX; // h1°ú h2»çÀÌÀÇ ³ôÀÌ°ª
h13 = h1 + (h3-h1) * dX; // h1°ú h3»çÀÌÀÇ ³ôÀÌ°ª
y = h12 + ((h13-h12) * (dZ/dX)); // ã°íÀÚ ÇÏ´Â ³ôÀÌ°ª
return y;
}
}
else if ((ix+iz)%2==1) //»ç°¢ÇüÀÌ ¿ª½½·¹½¬ ¸ð¾ç..
{
h1 = m_pMapData[(ix+1)*m_ti_MapSize + iz].fHeight;
h3 = m_pMapData[ix*m_ti_MapSize + (iz+1)].fHeight;
if ((dX+dZ) > 1.0f) //À­ÂÊ »ï°¢Çü..
{
if(dZ==0.0f) return h1;
h2 = m_pMapData[(ix+1)*m_ti_MapSize + (iz+1)].fHeight;
h12 = h1 + (h2-h1) * dZ;
h13 = h1 + (h3-h1) * dZ;
y = h12 + ((h13-h12) * ((1.0f-dX)/dZ));
return y;
}
else //¾Æ·¡ÂÊ »ï°¢Çü..
{
if(dX==1.0f) return h1;
h2 = m_pMapData[ix*m_ti_MapSize + iz].fHeight;
h12 = h2+(h1-h2)*dX; // h1°ú h2»çÀÌÀÇ ³ôÀÌ°ª
h13 = h3+(h1-h3)*dX; // h1°ú h3»çÀÌÀÇ ³ôÀÌ°ª
y = h12 + ((h13-h12) * (dZ/(1.0f-dX)));
return y;
}
}
return -FLT_MAX;
}

One engine I used allowed you to cast rays and determine their intersection with objects. I found the "ground" by casting a ray from above aimed down and found the intersection with the terrain.

It works on Knight OnLine. its a wrapper to CN3Terrain::GetHeight(float x, float z).
float getY(float x, float z) {
__asm {
PUSH 0
PUSH z
PUSH x
MOV ECX,DWORD PTR DS:[0x0C26C20]
MOV ECX,DWORD PTR DS:[ECX+1Ch]
MOV EDX,DWORD PTR DS:[ECX]
CALL DWORD PTR DS:[EDX+34h]
}}

Related

Interpreting visual studio profiler, is this subtraction slow? Can I make all this any faster?

I'm using the Visual Studio profiler for the first time and I'm trying to interpret the results. Looking at the percentages on the left, I found this subtraction's time cost a bit strange:
Other parts of the code contain more complex expressions, like:
Even a simple multiplication seems way faster than the subtraction :
Other multiplications take way longer and I really don't get why, like this :
So, I guess my question is if there is anything weird going on here.
Complex expressions take longer than that subtraction and some expressions take way longer than similar other ones. I run the profiler several times and the distribution of the percentages is always like this. Am I just interpreting this wrong?
Update:
I was asked to give the profile for the whole function so here it is, even though it's a bit big. I ran the function inside a for loop for 1 minute and got 50k samples. The function contains a double loop. I include the text first for ease, followed by the pictures of profiling. Note that the code in text is a bit updated.
for (int i = 0; i < NUMBER_OF_CONTOUR_POINTS; i++) {
vec4 contourPointV(contour3DPoints[i], 1);
float phi = angles[i];
float xW = pose[0][0] * contourPointV.x + pose[1][0] * contourPointV.y + contourPointV.z * pose[2][0] + pose[3][0];
float yW = pose[0][1] * contourPointV.x + pose[1][1] * contourPointV.y + contourPointV.z * pose[2][1] + pose[3][1];
float zW = pose[0][2] * contourPointV.x + pose[1][2] * contourPointV.y + contourPointV.z * pose[2][2] + pose[3][2];
float x = -G_FU_STRICT * xW / zW;
float y = -G_FV_STRICT * yW / zW;
x = (x + 1) * G_WIDTHo2;
y = (y + 1) * G_HEIGHTo2;
y = G_HEIGHT - y;
phi -= extraTheta;
if (phi < 0)phi += CV_PI2;
int indexForTable = phi * oneKoverPI;
//vec2 ray(cos(phi), sin(phi));
vec2 ray(cos_pre[indexForTable], sin_pre[indexForTable]);
vec2 ray2(-ray.x, -ray.y);
float outerStepX = ray.x * step;
float outerStepY = ray.y * step;
cv::Point2f outerPoint(x + outerStepX, y + outerStepY);
cv::Point2f innerPoint(x - outerStepX, y - outerStepY);
cv::Point2f contourPointCV(x, y);
cv::Point2f contourPointCVcopy(x, y);
bool cut = false;
if (!isInView(outerPoint.x, outerPoint.y) || !isInView(innerPoint.x, innerPoint.y)) {
cut = true;
}
bool outside2 = true; bool outside1 = true;
if (cut) {
outside2 = myClipLine(contourPointCV.x, contourPointCV.y, outerPoint.x, outerPoint.y, G_WIDTH - 1, G_HEIGHT - 1);
outside1 = myClipLine(contourPointCVcopy.x, contourPointCVcopy.y, innerPoint.x, innerPoint.y, G_WIDTH - 1, G_HEIGHT - 1);
}
myIterator innerRayMine(contourPointCVcopy, innerPoint);
myIterator outerRayMine(contourPointCV, outerPoint);
if (!outside1) {
innerRayMine.end = true;
innerRayMine.prob = true;
}
if (!outside2) {
outerRayMine.end = true;
innerRayMine.prob = true;
}
vec2 normal = -ray;
float dfdxTerm = -normal.x;
float dfdyTerm = normal.y;
vec3 point3D = vec3(xW, yW, zW);
cv::Point contourPoint((int)x, (int)y);
float Xc = point3D.x; float Xc2 = Xc * Xc; float Yc = point3D.y; float Yc2 = Yc * Yc; float Zc = point3D.z; float Zc2 = Zc * Zc;
float XcYc = Xc * Yc; float dfdxFu = dfdxTerm * G_FU; float dfdyFv = dfdyTerm * G_FU; float overZc2 = 1 / Zc2; float overZc = 1 / Zc;
pixelJacobi[0] = (dfdyFv * (Yc2 + Zc2) + dfdxFu * XcYc) * overZc2;
pixelJacobi[1] = (-dfdxFu * (Xc2 + Zc2) - dfdyFv * XcYc) * overZc2;
pixelJacobi[2] = (-dfdyFv * Xc + dfdxFu * Yc) * overZc;
pixelJacobi[3] = -dfdxFu * overZc;
pixelJacobi[4] = -dfdyFv * overZc;
pixelJacobi[5] = (dfdyFv * Yc + dfdxFu * Xc) * overZc2;
float commonFirstTermsSum = 0;
float commonFirstTermsSquaredSum = 0;
int test = 0;
while (!innerRayMine.end) {
test++;
cv::Point xy = innerRayMine.pos(); innerRayMine++;
int x = xy.x;
int y = xy.y;
float dx = x - contourPoint.x;
float dy = y - contourPoint.y;
vec2 dxdy(dx, dy);
float raw = -glm::dot(dxdy, normal);
float heavisideTerm = heaviside_pre[(int)raw * 100 + 1000];
float deltaTerm = delta_pre[(int)raw * 100 + 1000];
const Vec3b rgb = ante[y * 640 + x];
int red = rgb[0]; int green = rgb[1]; int blue = rgb[2];
red = red >> 3; red = red << 10; green = green >> 3; green = green << 5; blue = blue >> 3;
int colorIndex = red + green + blue;
pF = pFPointer[colorIndex];
pB = pBPointer[colorIndex];
float denAsMul = 1 / (pF + pB + 0.000001);
pF = pF * denAsMul;
float pfMinusPb = 2 * pF - 1;
float denominator = heavisideTerm * (pfMinusPb)+pB + 0.000001;
float commonFirstTerm = -pfMinusPb / denominator * deltaTerm;
commonFirstTermsSum += commonFirstTerm;
commonFirstTermsSquaredSum += commonFirstTerm * commonFirstTerm;
}
}
Visual Studio profiles by sampling: it interrupts execution often and records the value of the instruction pointer; it then maps it to the source and calculates the frequency of hitting that line.
There are few issues with that: it's not always possible to figure out which line produced a specific assembly instruction in the optimized code.
One trick I use is to move the code of interest into a separate function and declare it with __declspec(noinline) .
In your example, are you sure the subtraction was performed as many times as multiplication? I would be more puzzled by the difference in subsequent multiplication (0.39% and 0.53%)
Update:
I believe that the following lines:
float phi = angles[i];
and
phi -= extraTheta;
got moved together in assembly and the time spent getting angles[i] was added to that subtraction line.

Rotating four lines around a common point

I have four lines held in a Rectangle object. I'm trying to rotate the entire box by any angle, but I'm getting weird results.
Here's my current code:
void Line::rotate(int x_anchor, int y_anchor, double angle) {
// Change the coordinate system
int xOffset = m_pt1.x() - x_anchor;
int yOffset = m_pt1.y() - y_anchor;
// Move to 0, 0
int xTemp = m_pt2.x() - xOffset;
int yTemp = m_pt2.y() - yOffset;
// Rotate
double tCos = cos(angle);
double tSin = sin(angle);
double xNew = (xTemp * tCos) - (yTemp * tSin);
double yNew = (xTemp * tSin) + (yTemp * tCos);
// Make new
m_pt2 = Point(xNew + xOffset, yNew + yOffset);
}
What I'm trying to do is move the origin, then move the line down to that orgin, rotate it, then put it back. By doing this, if I do something like:
void Rectangle::rotate(int x_anchor, int y_anchor, double angle) {
m_t.rotate(x_anchor, y_anchor, angle);
m_r.rotate(x_anchor, y_anchor, angle);
m_b.rotate(x_anchor, y_anchor, angle);
m_l.rotate(x_anchor, y_anchor, angle);
}
The box should rotate together. However, this doesn't even work for a line, so I'm not sure where I've gone wrong on my formula. This thread is what I'm referencing for the formula.
Thanks.
EDIT:
I've modified my code according to FalconUA's suggestion:
void Line::rotate(int x_anchor, int y_anchor, double angle) {
/* Change the coordinate system */
// Start point
int xStartOffset = m_pt1.x() - x_anchor;
int yStartOffset = m_pt1.y() - y_anchor;
// End point
int xEndOffset = m_pt2.x() - x_anchor;
int yEndOffset = m_pt2.y() - y_anchor;
/* Move to 0, 0 */
// Start point
int xStartTemp = m_pt2.x() - xStartOffset;
int yStartTemp = m_pt2.y() - yStartOffset;
// End point
int xEndTemp = m_pt2.x() - xEndOffset;
int yEndTemp = m_pt2.y() - yEndOffset;
// Precalculate sin and cos
double tCos = cos(angle);
double tSin = sin(angle);
/* Rotate */
// Start point
double xStartNew = (xStartTemp * tCos) - (yStartTemp * tSin);
double yStartNew = (xStartTemp * tSin) + (yStartTemp * tCos);
// End point
double xEndNew = (xEndTemp * tCos) - (yEndTemp * tSin);
double yEndNew = (xEndTemp * tSin) + (yEndTemp * tCos);
// Make new points
m_pt1 = Point(xStartNew + xStartOffset, yStartNew + yStartOffset);
m_pt2 = Point(xEndNew + xEndOffset, yEndNew + yEndOffset);
}
However, still not quite getting what I should.
Given:
Rectangle r(5, 5, 10, 10);
Which outputs:
xxxxxx
x x
x x
x x
x x
xxxxxx
And then if I rotate by 90 (PI / 2) degrees, which is done by this:
// Use the bottom left corner as the common point
rotate(m_l.getEnd().x(), m_l.getEnd().y(), PI / 2);
I get
x x
x x
x x
x x
x x
x
x
x
x
x x
x
x
x
x
x
Seems like it happens because you're rotating lines relatively to the first point of the line. So, rotate not the line relatively to the first point, but rotate two points separately.
Update: if you have an anchor (xa, ya), and you want to rotate the point (x, y) around it. Your point can be represented as (xa + u, ya + v), where (u, v) = (x - xa, y - ya). So all you have to do is rotate teh vector (u, v) by using the formula with sin and cos that you've used above and the resulting point will be (xa + u_rotated, ya + v_rotated).
void Line::rotate(int x_anchor, int y_anchor, double angle) {
// the vector to rotate
int rotvec_x1 = m_pt1.x() - x_anchor;
int rotvec_y1 = m_pt1.y() - y_anchor;
// the vector to rotate
int rotvec_x2 = m_pt2.x() - x_anchor;
int rotvec_y2 = m_pt2.y() - y_anchor;
// pre-calculation for sin and cos
double tCos = cos(angle);
double tSin = sin(angle);
// rotating first vector
double rotvec_x1_new = (rotvec_x1 * tCos) - (rotvec_y1 * tSin);
double rotvec_y1_new = (rotvec_x1 * tSin) + (rotvec_y1 * tCos);
// rotating second vector
double rotvec_x2_new = (rotvec_x2 * tCos) - (rotvec_y2 * tSin);
double rotvec_y2_new = (rotvec_x2 * tSin) + (rotvec_y2 * tCos);
// Make new
m_pt1 = Point(x_anchor + rotvec_x1_new, y_anchor + rotvec_y1_new);
m_pt2 = Point(x_anchor + rotvec_x2_new, y_anchor + rotvec_y2_new);
}

Why are my openGL ellipses pointed?

I copied this ellipse code directly from the opengl textbook:
void ellipseMidpoint (int xCenter, int yCenter, int Rx, int Ry)
{
int Rx2 = Rx * Rx;
int Ry2 = Ry * Ry;
int twoRx2 = 2 * Rx2;
int twoRy2 = 2 * Ry2;
int p;
int x = 0;
int y = Ry;
int px = 0;
int py = twoRx2 * y;
//initial points in both quadrants
ellipsePlotPoints (xCenter, yCenter, x, y);
//Region 1
p = round (Ry2 - (Rx2 * Ry) + (0.25 * Rx2));
while (px < py) {
x++;
px += twoRy2;
if (p < 0)
p += Ry2 + px;
else {
y--;
py -= twoRx2;
p += Ry2 + px - py;
}
ellipsePlotPoints (xCenter, yCenter, x, y);
}
//Region 2
p = round (Ry2 * (x+0.5) * (x+0.5) + Rx2 * (y-1) * (y-1) - Rx2 * Ry2);
while (y > 0) {
y--;
py -= twoRx2;
if (p > 0)
p += Rx2 - py;
else {
x++;
px += twoRy2;
p += Rx2 - py + px;
}
ellipsePlotPoints (xCenter, yCenter, x, y);
}
}
void ellipsePlotPoints (int xCenter, int yCenter, int x, int y)
{
setPixel (xCenter + x, yCenter + y);
setPixel (xCenter - x, yCenter + y);
setPixel (xCenter + x, yCenter - y);
setPixel (xCenter - x, yCenter - y);
}
void setPixel (GLint xPos, GLint yPos)
{
glBegin (GL_POINTS);
glVertex2i(xPos, yPos);
glEnd();
}
The smaller ellipses seem to be fine but the larger ones are pointy and sort of flat at the ends.
Any ideas why?
Here is a current screenshot:
I think you're encountering overflow. I played with your code. While I never saw exactly the same "lemon" type shapes from your pictures, things definitely fell apart at large sizes, and it was caused by overflowing the range of the int variables used in the code.
For example, look at one of the first assignments:
int py = twoRx2 * y;
If you substitute, this becomes:
int py = 2 * Rx * Rx * Ry;
If you use a value of 1000 each for Rx and Ry, this is 2,000,000,000. Which is very close to the 2^31 - 1 top of the range of a 32-bit int.
If you want to use this algorithm for larger sizes, you could use 64-bit integer variables. Depending on your system, the type would be long or long long. Or more robustly, int64_t after including <stdint.h>.
Now, if all you want to do is draw an ellipsis with OpenGL, there are much better ways. The Bresenham type algorithms used in your code are ideal if you need to draw a curve pixel by pixel. But OpenGL is a higher level API, which knows how to render more complex primitives than just pixels. For a curve, you will most typically use a connected set of line segments to approximate the curve. OpenGL will then take care of turning those line segments into pixels.
The simplest way to draw an ellipsis is to directly apply the parametric representation. With phi an angle between 0 and PI, and using the naming from your code, the points on the ellipsis are:
x = xCenter + Rx * cos(phi)
y = yCenter + Ry * sin(phi)
You can use an increment for phi that meets your precision requirements, and the code will look something to generate an ellipsis approximated by DIV_COUNT points will look something like this:
float angInc = 2.0f * m_PI / (float)DIV_COUNT;
float ang = 0.0f;
glBegin(GL_LINE_LOOP);
for (int iDiv = 0; iDiv < DIV_COUNT; ++iDiv) {
ang += angInc;
float x = xCenter + Rx * cos(ang);
float y = yCenter + Ry * sin(ang);
glVertex2f(x, y);
glEnd();
If you care about efficiency, you can avoid calculating the trigonometric functions for each point, and apply an incremental rotation to calculate each point from the previous one:
float angInc = 2.0f * M_PI / (float)DIV_COUNT;
float cosInc = cos(angInc);
float sinInc = sin(angInc);
float cosAng = 1.0f;
float sinAng = 0.0f
glBegin(GL_LINE_LOOP);
for (int iDiv = 0; iDiv < DIV_COUNT; ++iDiv) {
float newCosAng = cosInc * cosAng - sinInc * sinAng;
sinAng = sinInc * cosAng + cosInc * sinAng;
cosAng = newCosAng;
float x = xCenter + Rx * cosAng;
float y = yCenter + Ry * sinAng;
glVertex2f(x, y);
glEnd();
This code is of course just for illustrating the math, and to get you started. In reality, you should use current OpenGL rendering methods, which includes vertex buffers, etc.

Bilinear Interpolation, something wrong with my implementation

I am trying to implement a bilinear interpolation function, but for some reason I am getting bad output. I cant seem to figure out what's wrong, any help getting on the right track will be appreciated.
double lerp(double c1, double c2, double v1, double v2, double x)
{
if( (v1==v2) ) return c1;
double inc = ((c2-c1)/(v2 - v1)) * (x - v1);
double val = c1 + inc;
return val;
};
void bilinearInterpolate(int width, int height)
{
// if the current size is the same, do nothing
if(width == GetWidth() && height == GetHeight())
return;
//Create a new image
std::unique_ptr<Image2D> image(new Image2D(width, height));
// x and y ratios
double rx = (double)(GetWidth()) / (double)(image->GetWidth()); // oldWidth / newWidth
double ry = (double)(GetHeight()) / (double)(image->GetHeight()); // oldWidth / newWidth
// loop through destination image
for(int y=0; y<height; ++y)
{
for(int x=0; x<width; ++x)
{
double sx = x * rx;
double sy = y * ry;
uint xl = std::floor(sx);
uint xr = std::floor(sx + 1);
uint yt = std::floor(sy);
uint yb = std::floor(sy + 1);
for (uint d = 0; d < image->GetDepth(); ++d)
{
uchar tl = GetData(xl, yt, d);
uchar tr = GetData(xr, yt, d);
uchar bl = GetData(xl, yb, d);
uchar br = GetData(xr, yb, d);
double t = lerp(tl, tr, xl, xr, sx);
double b = lerp(bl, br, xl, xr, sx);
double m = lerp(t, b, yt, yb, sy);
uchar val = std::floor(m + 0.5);
image->SetData(x,y,d,val);
}
}
}
//Cleanup
mWidth = width; mHeight = height;
std::swap(image->mData, mData);
}
Input Image (4 pixels wide and high)
My Output
Expected Output (Photoshop's Bilinear Interpolation)
Photoshop's algorithm assumes that each source pixel's color is in the center of the pixel, while your algorithm assumes that the color is in its topleft. This causes your results to be shifted half a pixel up and left compared to Photoshop.
Another way to look at it is that your algorithm maps the x coordinate range (0, srcWidth) to (0, dstWidth), while Photoshop maps (-0.5, srcWidth-0.5) to (-0.5, dstWidth-0.5), and the same in y coordinate.
Instead of:
double sx = x * rx;
double sy = y * ry;
You can use:
double sx = (x + 0.5) * rx - 0.5;
double sy = (y + 0.5) * ry - 0.5;
to get similar results. Note that this can give you a negative value for sx and sy.

Separating Axis Theorem is driving me nuts!

i am working on an implementation of the Separting Axis Theorem for use in 2D games. It kind of works but just kind of.
I use it like this:
bool penetration = sat(c1, c2) && sat(c2, c1);
Where c1 and c2 are of type Convex, defined as:
class Convex
{
public:
float tx, ty;
public:
std::vector<Point> p;
void translate(float x, float y) {
tx = x;
ty = y;
}
};
(Point is a structure of float x, float y)
The points are typed in clockwise.
My current code (ignore Qt debug):
bool sat(Convex c1, Convex c2, QPainter *debug)
{
//Debug
QColor col[] = {QColor(255, 0, 0), QColor(0, 255, 0), QColor(0, 0, 255), QColor(0, 0, 0)};
bool ret = true;
int c1_faces = c1.p.size();
int c2_faces = c2.p.size();
//For every face in c1
for(int i = 0; i < c1_faces; i++)
{
//Grab a face (face x, face y)
float fx = c1.p[i].x - c1.p[(i + 1) % c1_faces].x;
float fy = c1.p[i].y - c1.p[(i + 1) % c1_faces].y;
//Create a perpendicular axis to project on (axis x, axis y)
float ax = -fy, ay = fx;
//Normalize the axis
float len_v = sqrt(ax * ax + ay * ay);
ax /= len_v;
ay /= len_v;
//Debug graphics (ignore)
debug->setPen(col[i]);
//Draw the face
debug->drawLine(QLineF(c1.tx + c1.p[i].x, c1.ty + c1.p[i].y, c1.p[(i + 1) % c1_faces].x + c1.tx, c1.p[(i + 1) % c1_faces].y + c1.ty));
//Draw the axis
debug->save();
debug->translate(c1.p[i].x, c1.p[i].y);
debug->drawLine(QLineF(c1.tx, c1.ty, ax * 100 + c1.tx, ay * 100 + c1.ty));
debug->drawEllipse(QPointF(ax * 100 + c1.tx, ay * 100 + c1.ty), 10, 10);
debug->restore();
//Carve out the min and max values
float c1_min = FLT_MAX, c1_max = FLT_MIN;
float c2_min = FLT_MAX, c2_max = FLT_MIN;
//Project every point in c1 on the axis and store min and max
for(int j = 0; j < c1_faces; j++)
{
float c1_proj = (ax * (c1.p[j].x + c1.tx) + ay * (c1.p[j].y + c1.ty)) / (ax * ax + ay * ay);
c1_min = min(c1_proj, c1_min);
c1_max = max(c1_proj, c1_max);
}
//Project every point in c2 on the axis and store min and max
for(int j = 0; j < c2_faces; j++)
{
float c2_proj = (ax * (c2.p[j].x + c2.tx) + ay * (c2.p[j].y + c2.ty)) / (ax * ax + ay * ay);
c2_min = min(c2_proj, c2_min);
c2_max = max(c2_proj, c2_max);
}
//Return if the projections do not overlap
if(!(c1_max >= c2_min && c1_min <= c2_max))
ret = false; //return false;
}
return ret; //return true;
}
What am i doing wrong? It registers collision perfectly but is over sensitive on one edge (in my test using a triangle and a diamond):
//Triangle
push_back(Point(0, -150));
push_back(Point(0, 50));
push_back(Point(-100, 100));
//Diamond
push_back(Point(0, -100));
push_back(Point(100, 0));
push_back(Point(0, 100));
push_back(Point(-100, 0));
I am getting this mega-adhd over this, please help me out :)
http://u8999827.fsdata.se/sat.png
OK, I was wrong the first time. Looking at your picture of a failure case it is obvious a separating axis exists and is one of the normals (the normal to the long edge of the triangle). The projection is correct, however, your bounds are not.
I think the error is here:
float c1_min = FLT_MAX, c1_max = FLT_MIN;
float c2_min = FLT_MAX, c2_max = FLT_MIN;
FLT_MIN is the smallest normal positive number representable by a float, not the most negative number. In fact you need:
float c1_min = FLT_MAX, c1_max = -FLT_MAX;
float c2_min = FLT_MAX, c2_max = -FLT_MAX;
or even better for C++
float c1_min = std::numeric_limits<float>::max(), c1_max = -c1_min;
float c2_min = std::numeric_limits<float>::max(), c2_max = -c2_min;
because you're probably seeing negative projections onto the axis.