2D rotation problems

Started by
3 comments, last by ????? ????? 10 years, 4 months ago

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

Advertisement
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 wink.png

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

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

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.

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 angry.png

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...

This topic is closed to new replies.

Advertisement