Triangle rotation causes deformation - opengl

I would like to rotate my triangle but there are some problems.
Its default form:
I am rotating it with my arrow keys but as you see it has some deformations on shape of triangle:
Here is my code:
typedef struct {
point_t pos; // position of the triangle
float angle; // view angle
float r;
} weapon_t;
void drawPlayer(weapon_t tw) {
glBegin(GL_TRIANGLES);
glColor3f(0.1, 0.2, 0.3);
glVertex2f(tw.pos.x, tw.pos.y);
glVertex2f(tw.pos.x + 150 * cos(tw.angle * D2R), tw.pos.y + 100 * sin(tw.angle * D2R) + 8);
glVertex2f(tw.pos.x + 150 * cos(tw.angle * D2R), tw.pos.y + 100 * sin(tw.angle * D2R) - 8);
glEnd();
}
void onTimer(int v) {
glutTimerFunc(TIMER_PERIOD, onTimer, 0);
if (right) {
if (weapon.angle != -45)
turnWeapon(&weapon, -3);
}
if (left) {
if (weapon.angle != 45)
turnWeapon(&weapon, 3);
}
Any idea guys?

I don't know where you got your formulas from but they are wrong. To rotate a 2D vector anti-clockwise around angle x you can use the rotation matrix [cos(x), -sin(x) ; sin(x), cos(x)] (you can prove this easily with exp(i*x) = cos(x) + i*sin(x)). You want to rotate the vectors [150, 108] and [150, 92] if you multiply those by the rotation matrix you get [150*cos(x) - 108*sin(x), 150*sin(x) + 108*cos(x)] and [150*cos(x) - 92*sin(x), 150*sin(x) + 92*cos(x)].
Translated into code this looks like this:
float c = cos(tw.angle * D2R);
float s = sin(tw.angle * D2R);
glVertex2f(tw.pos.x + 150*c - 108*s, tw.pos.y + 150*s + 108*c);
glVertex2f(tw.pos.x + 150*c - 92*s, tw.pos.y + 150*s + 92*c);

Related

Arc fuction c++

Hi i am trying to make a quarter circle in dear imgui for this i need a arc fuction
void ImDrawList::PathArcTo(const ImVec2& centre, float radius, float a_min, float a_max, int num_segments)
{
if (radius == 0.0f)
{
_Path.push_back(centre);
return;
}
_Path.reserve(_Path.Size + (num_segments + 1));
for (int i = 0; i <= num_segments; i++)
{
const float a = a_min + ((float)i / (float)num_segments) * (a_max - a_min);
_Path.push_back(ImVec2(centre.x + ImCos(a) * radius, centre.y + ImSin(a) * radius));
}
}
issue is this does this http://prntscr.com/rsyaaf i want it too do this http://prntscr.com/rsybsj how do i solve this
the code above is from dear imgui
Add _Path.push_back(centre); in all cases to provide right angle centered in arc center instead of chord

Can't get ray picking to work in my 3D scene when the camera moves

I have my own 3D engine implementation around OpenGL (C++) and it has worked fine for everything these last years.
But today I stumbled upon a problem. I have this scene with spheres (planets around a sun, orbit rings and things like that, very very simple) and I want to ray pick them with the mouse.
As long as the camera/view matrix is identity, picking works. When the camera is rotated and then moved, the picking goes completely haywire. I have been searching for a solution for a while now so now I'm asking you guys.
This is the code (summarized for this question):
mat4f mProj = createPerspective(PI / 4.0f, float(res.x) / float(res.y), 0.1f, 100.0f);
mat4f mCamera = createTranslation(-1.5f, 3, -34.0f) * createRotationZ(20.0f * PI / 180.0f) * createRotationX(20.0f * PI / 180.0f);
... render scene, using shaders that transform vertices with gl_Position = mProj * mCamera * aPosition;
mat4f mUnproject = (mProj * mCamera).getInverse();
vec2f mouseClip(2.0f * float(coord.x) / float(res.x) - 1.0f, 1.0f - 2.0f * float(coord.y) / float(res.y));
vec3f rayOrigin = (mUnproject * vec4f(mouseClip, 0, 1)).xyz();
vec3f rayDir = (mUnproject * vec4f(mouseClip, -1, 1)).xyz();
// In a loop over all planets:
mat4f mObject = createRotationY(planet.angle) * createTranslation(planet.distance, 0, 0);
vec3f planetPos = mObject.transformCoord(vec3f(0, 0, 0));
float R = planet.distance;
float a = rayDir.dot(rayDir);
float b = 2 * rayDir.x * (rayOrigin.x - planetPos.x) + 2 * rayDir.y * (rayOrigin.y - planetPos.y) + 2 * rayDir.z * (rayOrigin.z - planetPos.z);
float c = planetPos.dot(planetPos) + rayOrigin.dot(rayOrigin) -2 * planetPos.dot(rayOrigin) - R * R;
float d = b * b - 4 * a * c;
if (d >= 0)
HIT!
So when I use identity for mCamera, everything works fine, even when I use only rotation for mCamera, it works fine. It is when I start using the translation that it goes completely wrong.
Anyone knows where I am going wrong?
BDL's answer was spot on and put me back in the right direction. Indeed, when transforming coordinates myself, I forgot to do the perspective-divide. After writing so much shader code where the gpu does this for you, you forget about these things.
It is logical that this only gave issues when the camera moved and not when it was at (0, 0, 0) as then, the translation part of the transformation matrices stayed 0 and the w-factor of the coordinates were unaffected.
I immediately wrote transformCoord and transformNormal implementations in my matrix classes to prevent this error from happening again.
Also, the ray origin and direction were incorrect, although I don't really understand why yet. I now take the origin from my camera matrix (inverted of course) and calculate the direction the same way but now subtract the camera position from it to make it a direction vector. I normalize it, although I don't think it is really necessary in this case, but normalizing it will make its numbers look more readable when debugging anyway.
This works:
vec2f mouseClip(2.0f * float(coord.x) / float(res.x) - 1.0f, 1.0f - 2.0f * float(coord.y) / float(res.y));
mat4f mUnproject = (mProj * mCamera).getInverse();
mat4f mInvCamera = mCamera.getInverse();
vec3f rayOrigin(mInvCamera.m[12], mInvCamera.m[13], mInvCamera.m[14]);
vec3f rayDir = (mUnproject.transformCoord(vec3f(mouseClip, 1)) - rayOrigin).normalized();
... per planet
vec3f planetPos = mObject.transformCoord(vec3f(0, 0, 0));
float a = rayDir.dot(rayDir);
float b = 2 * rayDir.x * (rayOrigin.x - planetPos.x) + 2 * rayDir.y * (rayOrigin.y - planetPos.y) + 2 * rayDir.z * (rayOrigin.z - planetPos.z);
float c = planetPos.dot(planetPos) + rayOrigin.dot(rayOrigin) -2 * planetPos.dot(rayOrigin) - 0.4f * 0.4f;
float d = b * b - 4 * a * c;
if (d >= 0)
... HIT!

Negative row and column in terrain following algorithm

I'm trying to do terrain following, and I get a negative camera position in the xz plane. Now I get an out of boundary exception, because the row or the col is negative. How would I transform the cell of the grid to the origin correctly, giving negative camera coordinates.
Here is the two functions
int cGrid::getHeightmapEntry(int row, int col)
{
return m_heightmap[row * 300 + col];
}
float cGrid::getHeight(float x, float z, float _width, float _depth, int _cellSpacing)
{
// Translate on xz-plane by the transformation that takes
// the terrain START point to the origin.
x = ((float)_width / 2.0f) + x;
z = ((float)_depth / 2.0f) - z;
// Scale down by the transformation that makes the
// cellspacing equal to one. This is given by
// 1 / cellspacing since; cellspacing * 1 / cellspacing = 1.
x /= (float)_cellSpacing;
z /= (float)_cellSpacing;
// From now on, we will interpret our positive z-axis as
// going in the 'down' direction, rather than the 'up' direction.
// This allows to extract the row and column simply by 'flooring'
// x and z:
float col = ::floorf(x);
float row = ::floorf(z);
if (row < 0 || col<0)
{
row = 0;
}
// get the heights of the quad we're in:
//
// A B
// *---*
// | / |
// *---*
// C D
float A = getHeightmapEntry(row, col);
float B = getHeightmapEntry(row, col + 1);
float C = getHeightmapEntry(row + 1, col);
float D = getHeightmapEntry(row + 1, col + 1);
//
// Find the triangle we are in:
//
// Translate by the transformation that takes the upper-left
// corner of the cell we are in to the origin. Recall that our
// cellspacing was nomalized to 1. Thus we have a unit square
// at the origin of our +x -> 'right' and +z -> 'down' system.
float dx = x - col;
float dz = z - row;
// Note the below compuations of u and v are unneccessary, we really
// only need the height, but we compute the entire vector to emphasis
// the books discussion.
float height = 0.0f;
if (dz < 1.0f - dx) // upper triangle ABC
{
float uy = B - A; // A->B
float vy = C - A; // A->C
// Linearly interpolate on each vector. The height is the vertex
// height the vectors u and v originate from {A}, plus the heights
// found by interpolating on each vector u and v.
height = A + Lerp(0.0f, uy, dx) + Lerp(0.0f, vy, dz);
}
else // lower triangle DCB
{
float uy = C - D; // D->C
float vy = B - D; // D->B
// Linearly interpolate on each vector. The height is the vertex
// height the vectors u and v originate from {D}, plus the heights
// found by interpolating on each vector u and v.
height = D + Lerp(0.0f, uy, 1.0f - dx) + Lerp(0.0f, vy, 1.0f - dz);
}
return height;
}
float height = m_Grid.getHeight(position.x, position.y, 49 * 300, 49 * 300, 6.1224489795918367f);
if (height != 0)
{
position.y = height + 10.0f;
}
m_Camera.SetPosition(position.x, position.y, position.z);
bool cGrid::readRawFile(std::string fileName, int m, int n)
{
// A height for each vertex
std::vector<BYTE> in(m*n);
std::ifstream inFile(fileName.c_str(), std::ios_base::binary);
if (!inFile)
return false;
inFile.read(
(char*)&in[0], // buffer
in.size());// number of bytes to read into buffer
inFile.close();
// copy BYTE vector to int vector
m_heightmap.resize(n*m);
for (int i = 0; i < in.size(); i++)
m_heightmap[i] = (float)((in[i])/255)*50.0f;
return true;
}
m_Grid.readRawFile("castlehm257.raw", 50, 50);
I infer that you’re storing a 50 by 50 matrix inside a 300 by 300 matrix, to represent a grid of 49 by 49 cells. I also infer that m_Grid is an object of type cGrid. Your code appears to contain the following errors:
Argument(2) of call m_Grid.getHeight is not a z value.
Argument(3) of call m_Grid.getHeight is inconsistent with argument(5).
Argument(4) of call m_Grid.getHeight is inconsistent with argument(5).
Implicit cast of literal float to int in argument(5) of call m_Grid.getHeight - the value will be truncated.
Try changing your function call to this:
float height = m_Grid.getHeight(position.x, position.z, 49 * cellspacing, 49 * cellspacing, cellspacing);
-- where cellspacing is as defined in your diagram.
Also, try changing parameter(5) of cGrid::getHeight from int _cellSpacing to float _cellSpacing.
(I have edited this answer a couple of times as my understanding of your code has evolved.)

I need to implement a 2d shape rotate function

this is the formular but i dont know how to implement it. can someone please help
rectangle::rectangle() //rectangle constructor
{
bl.real() = 0; //bottom
bl.imag() = 0; //left
tr.real() = 1; //top
tr.imag() = 1; //right
}
complex<double> rectangle::get_bl() const
{
return bl;
}
complex<double> rectangle::get_tr() const
{
return tr;
}
void rectangle::rotate(double angle)
{
//not sure how to do it tr = tr.real() * cos(angle) + tr.imag() *cos(angle);
}
main
rectangle r;
r.rotate(90);
expected output (not 100% sure)
0 0 -1 1
Move your shape to (0, 0) temporarily (formula assumes you are rotating about origin, so move the bottom-left corner to (0, 0)).
Apply formula.
Move it back.
if (tr.real() < bl.real()) {
float tempX = tr.real() - bl.real();
float tempY = tr.imag() - bl.imag();
} else {
float tempX = bl.real() - tr.real();
float tempY = bl.imag() - tr.imag();
}
tr.real() = tempX * cos(theta) - tempY * sin(theta)
tr.imag() = tempx * sin(theta) + tempY * cos(theta)
The formula is basically saying:
new_x = shape.point[i].x*cos(angle) - shape.point[i].y*sin(angle)
new_y = shape.point[i].x*sin(angle) + shape.point[i].y*cos(angle)
shape.point[i].x = new_x
shape.point[i].y = new_y
angle is in radians, to convert from degrees to radians use
degree*pi/180 where pi is the constant 3.14...
you will need to do this for each point on the shape to fully rotate the shape by the desired degree.
This formula also assumes that the points are centered around (0,0), i.e. the center of the shape is (0,0) and all points are relative to that center.
One tip, if applicable, try and store shapes as points, going clockwise from the 0th point. for instance, this rectangle will be:
point[0] = {-1, 1}
point[1] = { 1, 1}
point[2] = { 1,-1}
point[3] = {-1,-1}
To convert from tl, br to points you will need to do something similar to:
point[0] = {tl.x, tl.y}
point[1] = {br.x, tl.y}
point[2] = {br.x, br.y}
point[3] = {tl.x, br.y}

opengl trackball

I am trying to rotate opengl scene using track ball. The problem i am having is i am getting rotations opposite to direction of my swipe on screen. Here is the snippet of code.
prevPoint.y = viewPortHeight - prevPoint.y;
currentPoint.y = viewPortHeight - currentPoint.y;
prevPoint.x = prevPoint.x - centerx;
prevPoint.y = prevPoint.y - centery;
currentPoint.x = currentPoint.x - centerx;
currentPoint.y = currentPoint.y - centery;
double angle=0;
if (prevPoint.x == currentPoint.x && prevPoint.y == currentPoint.y) {
return;
}
double d, z, radius = viewPortHeight * 0.5;
if(viewPortWidth > viewPortHeight) {
radius = viewPortHeight * 0.5f;
} else {
radius = viewPortWidth * 0.5f;
}
d = (prevPoint.x * prevPoint.x + prevPoint.y * prevPoint.y);
if (d <= radius * radius * 0.5 ) { /* Inside sphere */
z = sqrt(radius*radius - d);
} else { /* On hyperbola */
z = (radius * radius * 0.5) / sqrt(d);
}
Vector refVector1(prevPoint.x,prevPoint.y,z);
refVector1.normalize();
d = (currentPoint.x * currentPoint.x + currentPoint.y * currentPoint.y);
if (d <= radius * radius * 0.5 ) { /* Inside sphere */
z = sqrt(radius*radius - d);
} else { /* On hyperbola */
z = (radius * radius * 0.5) / sqrt(d);
}
Vector refVector2(currentPoint.x,currentPoint.y,z);
refVector2.normalize();
Vector axisOfRotation = refVector1.cross(refVector2);
axisOfRotation.normalize();
angle = acos(refVector1*refVector2);
I recommend artificially setting prevPoint and currentPoint to (0,0) (0,1) and then stepping through the code (with a debugger or with your eyes) to see if each part makes sense to you, and the angle of rotation and axis at the end of the block are what you expect.
If they are what you expect, then I'm guessing the error is in the logic that occurs after that. i.e. you then take the angle and axis and convert them to a matrix which gets multiplied to move the model. A number of convention choices happen in this pipeline --which if swapped can lead to the type of bug you're having:
Whether the formula assumes the angle is winding left or right handedly around the axis.
Whether the transformation is meant to rotate an object in the world or meant to rotate the camera.
Whether the matrix is meant to operate by multiplication on the left or right.
Whether rows or columns of matrices are contiguous in memory.