# 2D rotation problems

This topic is 2151 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Hi 2 all! I have some problems with rectangle rotation. The sense of my test application: there are player in the center of screen, he can rotate around and shoot; bullets have to reflect from walls. All works fine except of walls rendering. The issues related to walls definition:

struct Line
{
XMFLOAT2 point1;
XMFLOAT2 point2;
Line(XMFLOAT2 p1, XMFLOAT2 p2) : point1(p1), point2(p2) { };
};
vector<Line> SidesCoordList;
vector<GameObject> sides;

SidesCoordList.push_back(Line(XMFLOAT2(0.0f, 0.0f),     XMFLOAT2(0.0f, 600.0f)   ));
SidesCoordList.push_back(Line(XMFLOAT2(0.0f, 600.0f),   XMFLOAT2(800.0f, 600.0f) ));
SidesCoordList.push_back(Line(XMFLOAT2(800.0f, 600.0f), XMFLOAT2(800.0f, 0.0f)   ));
SidesCoordList.push_back(Line(XMFLOAT2(800.0f, 0.0f),   XMFLOAT2(0.0f, 0.0f)     ));

...

for (Line& line: SidesCoordList)
{
GameObject temp;
...
temp.SetPosition(center);
temp.SetRotation(XM_PIDIV2);
temp.SetScale(XMFLOAT2( 20.0f, length ));
sides.push_back(temp);
}

...

for (int i = 0; i<instanceCount; i++)
{
if (i >= sides->size()) break;
XMMATRIX mat = sides->at(i).GetWorldMatrix();
instances[i].M1 = mat.m[0];
instances[i].M2 = mat.m[1];
instances[i].M3 = mat.m[2];
instances[i].M4 = mat.m[3];
}
d3dContext_->UpdateSubresource(instanceBuffer, 0, 0, instances, 0, 0);

...

d3dContext_->DrawInstanced(vertexCount, instanceCount, 0, 0 );


Code for matrices from GameObject class:

XMMATRIX GameObject::GetWorldMatrix( )
{
XMMATRIX translation = XMMatrixTranslation( position_.x, position_.y, 0.0f );
XMMATRIX rotationZ = XMMatrixRotationZ( rotation_ );
XMMATRIX scale = XMMatrixScaling( scale_.x, scale_.y, 1.0f );

return rotationZ * scale * translation;
}

void GameObject::SetPosition( XMFLOAT2& position )
{
position_ = position;
}

void GameObject::SetRotation( float rotation )
{
rotation_ = rotation;
}

void GameObject::SetScale( XMFLOAT2& scale )
{
scale_ = scale;
}


HLSL code:

cbuffer cbMatrices : register( b0 )
{
matrix world;
matrix proj;
};

cbuffer cbParameters : register( b1 )
{
bool isTextured;
float4 color;
};

Texture2D colorMap_ : register( t0 );
SamplerState colorSampler_ : register( s0 );

struct VS_Input
{
float4 position			: POSITION;
float2 tex				: TEXCOORD0;

float4 W0 : TEXCOORD1;
float4 W1 : TEXCOORD2;
float4 W2 : TEXCOORD3;
float4 W3 : TEXCOORD4;
};

struct PS_Input
{
float4 position : SV_POSITION;
float2 tex		: TEXCOORD0;
};

PS_Input VS_Main(VS_Input input)
{
PS_Input vsOut = ( PS_Input )0;

float4x4 world_ = float4x4(input.W0, input.W1, input.W2, input.W3);
float4x4 WVP = mul(world_, proj);
vsOut.position = mul(input.position, WVP);

vsOut.tex = input.tex;
return vsOut;
}

float4 PS_Main( PS_Input frag ) : SV_TARGET
{
if (isTextured)
return colorMap_.Sample( colorSampler_, frag.tex );
else
return float4(color.xyz, 1.0f);

return (float4)(0);
}


Quit strangely that all the objects (player, bullets) are rendered correctly, except of walls. Walls don't want to rotate on Pi/2, another values of angles make distortions similar to incorrect setting of projection matrix. I've used VS Graphics debugger to track values in matrices and it seems correct. On the attached image the first one is matrix of player object, the second one - wall.

I try to understand what I made wrong and debug code during the whole day. Help please

Edited by oler117

##### Share on other sites
You store your instance's world transformation in row-major layout (XMMatrix is row-major, too), the mul of your vertex shader wants them in column-major. Solution: Transpose them:
for (int i = 0; i<instanceCount; i++)
{
if (i >= sides->size()) break;
XMMATRIX mat = XMMatrixTranspose(sides->at(i).GetWorldMatrix());
instances[i].M1 = mat.m[0];
instances[i].M2 = mat.m[1];
instances[i].M3 = mat.m[2];
instances[i].M4 = mat.m[3];
}

The reason it "works" for the player is probably because the origin of the normalized device coordinates "is" at the screen center

Edit: I don't see the code for updating the constant buffer. You probably need to do that for those matrices, too. Edited by unbird

##### Share on other sites

unbird, with transposing all crashed: player is displayed wrong (must be quad, but now line), walls disappeared. See attached images. First - with transposing, second - without.

Here is my project: http://www.filedropper.com/bulletmanagerproject

Edited by oler117

##### Share on other sites
I'm really sorry for the confusion. I have a similar instancing setup, but a minor difference made this transpose necessary on my side. Reading over your description again more carefully it should have been clear. Sorry again.

Hmmm, your angle calculation looks a bit suspect:

	float A = abs(line.point1.y - line.point2.y);
float B = abs(line.point2.x - line.point1.x);
float angle = atan(A/B);

This is a potential division by zero. Also no need to use abs. There's a version of atan which handles all the cases

	float dy = line.point1.y - line.point2.y;
float dx = line.point2.x - line.point1.x;
float angle = atan2(dy, dx);

If that doesn't help, show us the world transformations for all four walls, please.

##### Share on other sites

I've handled problem. The problem was in world matrix. The right variant (in my case) is World = scale * rotationZ * translation. And this line of code killed 2 days of my life

unbird, you are right about coefficients calculating and atan2, but it was another bug.

So the correct variant of setting GameObjects to draw lines:

for (Line& line: SidesCoordList)
{
shared_ptr<GameObject> temp(new GameObject());
float length = sqrt( pow(line.point2.x - line.point1.x, 2) + pow(line.point2.y - line.point1.y, 2) );

float A = line.point1.y - line.point2.y;
float B = line.point1.x - line.point2.x;
float angle = atan2(A, B);

XMFLOAT2 center = XMFLOAT2(  (line.point2.x + line.point1.x) / 2.0f, (line.point2.y + line.point1.y) / 2.0f );

temp->SetPosition(center);
temp->SetRotation(-(XM_PIDIV2 - angle));
temp->SetScale(XMFLOAT2( 5.0f, length ));

sides.push_back(temp);
}


And here is function that defines if the object reach the line:

bool BulletManager::IsIntersecting(Line line, XMFLOAT2 point, float eps)
{
if (!((point.x >= min(line.point1.x, line.point2.x) &&
point.x <= max(line.point1.x, line.point2.x)) ||
(point.y >= min(line.point1.y, line.point2.y) &&
point.y <= max(line.point1.y, line.point2.y))) )
return false;

// Constructing canonical line equation
float A = line.point1.y - line.point2.y;
float B = line.point2.x - line.point1.x;
float C = (-B * line.point2.y) - (A * line.point2.x);

// Calculating distance from bullet to line
float Dist = (abs((A * point.x) + (B * point.y) + C)) / sqrt(pow(A,2) + pow(B,2));

if (Dist <= eps)
return true;

return false;
}


Maybe it will be useful for someone. Who knows...

• ### Game Developer Survey

We are looking for qualified game developers to participate in a 10-minute online survey. Qualified participants will be offered a \$15 incentive for your time and insights. Click here to start!

• 9
• 11
• 15
• 21
• 26