Jump to content

  • Log In with Google      Sign In   
  • Create Account


Can't get sprite to rotate


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
10 replies to this topic

#1 cheese4432   Members   -  Reputation: 108

Like
0Likes
Like

Posted 09 July 2013 - 12:06 PM

I have been following Beginning directx11 game programming by allen sherod and wendy jones and I'm trying to make an asteroids game. I've been able to get my ship sprite moving, but I can't get it to rotate. I've gathered that a rotation matrix needs to be multiplied with a translation and scale matrix, and that result is then used for rendering; but the sprite still doesn't rotate.

 

Here is the ship header:

struct VertexPos
{
    XMFLOAT3 pos;
    XMFLOAT2 tex0;
};

class Ship : public Dx11Base, SpriteBase
{
public:
	Ship();
	virtual ~Ship();

	bool LoadContent();
	void UnloadContent();

	void Update( float dt);
	void Render();

private:
		VertexPos vertices[6]; //a rectangle
        ID3D11VertexShader* solidColorVS_;
        ID3D11PixelShader* solidColorPS_;

        ID3D11InputLayout* inputLayout_;
        ID3D11Buffer* vertexBuffer_;

        ID3D11ShaderResourceView* colorMap_;
        ID3D11SamplerState* colorMapSampler_;
        ID3D11BlendState* alphaBlendState_;

	SpriteBase sprites_[2];
	ID3D11Buffer* mvpCB_;
	XMMATRIX vpMatrix_;

	float dy;
	float dx;
        float rotation;
};

update function, it gets the input:

#define SHIPSPEED 1.2f
#define SHIPACCEL 0.2f

void Ship::Update(float dt)
{
	XMFLOAT2 sprite0;
	sprite0.x = sprites_[0].getPositionX(); 
	sprite0.y = sprites_[0].getPositionY();
	

keyboardDevice_->GetDeviceState( sizeof( keyboardKeys_ ), ( LPVOID )&keyboardKeys_ );

    // Button press event.
    if( KEYDOWN( prevKeyboardKeys_, DIK_F ) && !KEYDOWN( keyboardKeys_, DIK_F ) )
	{ 
		dy = 0;
		dx = 0;
	}

    // Button up event.
	if( KEYDOWN( prevKeyboardKeys_, DIK_S ) && !KEYDOWN( keyboardKeys_, DIK_S ) )
	{ 
		dy -= SHIPACCEL;
		if (dy <= -SHIPSPEED)
		dy = -1.3f;
	}

    // Button up event.
	if( KEYDOWN( prevKeyboardKeys_, DIK_W ) && !KEYDOWN( keyboardKeys_, DIK_W ) )
	{ 
		dy += SHIPACCEL;
		if (dy >= SHIPSPEED)
		dy = 1.3f;
	}

	if( KEYDOWN( prevKeyboardKeys_, DIK_A ) && !KEYDOWN( keyboardKeys_, DIK_A ) )
	{ 
		dx -= SHIPACCEL;
		if (dx >= SHIPSPEED)
		dx = SHIPSPEED;
	}

	if( KEYDOWN( prevKeyboardKeys_, DIK_D ) && !KEYDOWN( keyboardKeys_, DIK_D ) )
	{ 
		dx += SHIPACCEL;
		if (dx <= -SHIPSPEED)
			dx = -SHIPSPEED;
	}

	if( KEYDOWN( prevKeyboardKeys_, DIK_Q ) && !KEYDOWN( keyboardKeys_, DIK_Q ) )
	{ 
		rotation -= 0.1f; 
	}

	if( KEYDOWN( prevKeyboardKeys_, DIK_E ) && !KEYDOWN( keyboardKeys_, DIK_E ) )
	{ 
		rotation += 0.1f;
	}

	if( BUTTONDOWN( mouseState_, 0 ) && !BUTTONDOWN( prevMouseState_, 0 ) ) 
    {
		 //fire!!!!
        ;
    }
 

    memcpy( prevKeyboardKeys_, keyboardKeys_, sizeof( keyboardKeys_ ) );
	 memcpy( &prevMouseState_, &mouseState_, sizeof( mouseState_ ) );
	
	 if (dy >= SHIPSPEED)
		dy = SHIPSPEED;
	else if (dy <= -SHIPSPEED)
		dy = -SHIPSPEED;
	if (dx >= SHIPSPEED)
		dx = SHIPSPEED;
	else if (dx <= -SHIPSPEED)
		dx = -SHIPSPEED;
	if (rotation >= 6.2)
		rotation = 6.2f;
	else if (rotation <= 0)
		rotation = 0.0f;

	/* mousePosX_ += mouseState_.lX;
    mousePosY_ += mouseState_.lY;
    mouseWheel_ += mouseState_.lZ;*/
	  setRotation(rotation);

	sprite0.y += dy;
	sprite0.x += dx;
	bool wrap = sprites_[0].wrap(sprite0);
	
	sprites_[0].setPosition(sprite0);
}

sprite base class:

class SpriteBase
{
public:
	SpriteBase();
	virtual ~SpriteBase();

	XMMATRIX GetWorldMatrix();

	void setPosition(XMFLOAT2 &position);
	void setRotation(float rotation);
	void setScale(XMFLOAT2 & scale);

	float getPositionX() { return position_.x;}
	float getPositionY() { return position_.y;}

	bool wrap(XMFLOAT2 &position);

private:
	XMFLOAT2 position_;
	float rotation_;
	XMFLOAT2 scale_;
};

the getWorldMatrix function, which should be causing the rotation:

XMMATRIX SpriteBase::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*translation*scale;
}

and the ship render function, which should be showing the rotated sprite:

void Ship::Render()
{
	if(d3dContext_ == 0)
		return;

	float clearColor[4] = {0.0f, 0.0f, 0.0f, 0.0f};
	d3dContext_->ClearRenderTargetView(backBufferTarget_, clearColor);

	unsigned int stride = sizeof(VertexPos);
	unsigned int offset = 0;

	d3dContext_->IASetInputLayout( inputLayout_);
	d3dContext_->IASetVertexBuffers(0, 1, &vertexBuffer_, &stride, &offset);
	d3dContext_->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

	d3dContext_->VSSetShader( solidColorVS_, 0, 0);
	d3dContext_->PSSetShader(solidColorPS_, 0, 0);
	d3dContext_->PSSetShaderResources(0, 1, &colorMap_);
	d3dContext_->PSSetSamplers(0, 1, &colorMapSampler_);


	XMMATRIX world = sprites_[0].GetWorldMatrix();
	XMMATRIX mvp = XMMatrixMultiply(world, vpMatrix_);
	mvp = XMMatrixTranspose(mvp);

	d3dContext_->UpdateSubresource( mvpCB_, 0, 0, &mvp, 0, 0 );
	d3dContext_->VSSetConstantBuffers(0, 1, &mvpCB_);

	d3dContext_->Draw(6, 0 );

	swapChain_->Present(0, 0);
}

I'm wondering what I need to change in order for the rotation to actually happen, as I'm lost on it.


Edited by cheese4432, 09 July 2013 - 01:22 PM.


Sponsor:

#2 LorenzoGatti   Crossbones+   -  Reputation: 2659

Like
0Likes
Like

Posted 10 July 2013 - 02:37 AM

I don't see vpMatrix_ being written to (missing call to GetWorldMatrix?), and it seems you don't apply other transformations.


Produci, consuma, crepa

#3 cheese4432   Members   -  Reputation: 108

Like
0Likes
Like

Posted 10 July 2013 - 12:28 PM

You are correct, it's because the vpMatrix_ was not being written, I have now applied the rotation matrix to it and it rotates counter clockwise, but not clockwise. It currently also rotates around the spawning position, however I think that applying the translation matrix will fix that.



#4 cheese4432   Members   -  Reputation: 108

Like
0Likes
Like

Posted 10 July 2013 - 02:23 PM

Here's the updated ship render function:

void Ship::Render()
{
	if(d3dContext_ == 0)
		return;

	float clearColor[4] = {0.0f, 0.0f, 0.0f, 0.0f};
	d3dContext_->ClearRenderTargetView(backBufferTarget_, clearColor);

	unsigned int stride = sizeof(VertexPos);
	unsigned int offset = 0;

	d3dContext_->IASetInputLayout( inputLayout_);
	d3dContext_->IASetVertexBuffers(0, 1, &vertexBuffer_, &stride, &offset);
	d3dContext_->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

	d3dContext_->VSSetShader( solidColorVS_, 0, 0);
	d3dContext_->PSSetShader(solidColorPS_, 0, 0);
	d3dContext_->PSSetShaderResources(0, 1, &colorMap_);
	d3dContext_->PSSetSamplers(0, 1, &colorMapSampler_);

	
	vpMatrix_ = vpMatrix_*XMMatrixRotationZ(rotation);
	XMMATRIX world = sprites_[0].GetWorldMatrix();
	XMMATRIX mvp = XMMatrixMultiply(world, vpMatrix_);
	mvp = XMMatrixTranspose(mvp);
	

	d3dContext_->UpdateSubresource( mvpCB_, 0, 0, &mvp, 0, 0 );
	d3dContext_->VSSetConstantBuffers(0, 1, &mvpCB_);

	d3dContext_->Draw(6, 0 );

	swapChain_->Present(0, 0);
}

and the new ship update function:

void Ship::Update(float dt)
{
	XMFLOAT2 sprite0;
	sprite0.x = sprites_[0].getPositionX(); 
	sprite0.y = sprites_[0].getPositionY();
	rotation = 0; //don't spin constantly

keyboardDevice_->GetDeviceState( sizeof( keyboardKeys_ ), ( LPVOID )&keyboardKeys_ );

    // Button press event.
    if( KEYDOWN( prevKeyboardKeys_, DIK_F ) && !KEYDOWN( keyboardKeys_, DIK_F ) )
	{ 
		dy = 0;
		dx = 0;
		rotation = 0;
	}

    // Button up event.
	if( KEYDOWN( prevKeyboardKeys_, DIK_S ))
	{ 
		dy -= SHIPACCEL;
		if (dy <= -SHIPSPEED)
		dy = -SHIPSPEED;
	}

    // Button up event.
	if( KEYDOWN( prevKeyboardKeys_, DIK_W ))
	{ 
		dy += SHIPACCEL;
		if (dy >= SHIPSPEED)
		dy = SHIPSPEED;
	}

	if( KEYDOWN( prevKeyboardKeys_, DIK_A ))
	{ 
		dx -= SHIPACCEL;
		if (dx >= SHIPSPEED)
		dx = SHIPSPEED;
	}

	if( KEYDOWN( prevKeyboardKeys_, DIK_D ))
	{ 
		dx += SHIPACCEL;
		if (dx <= -SHIPSPEED)
			dx = -SHIPSPEED;
	}

	if( KEYDOWN( prevKeyboardKeys_, DIK_Q ))
	{ 
		rotation = 0.004f; 
	}

	if( KEYDOWN( prevKeyboardKeys_, DIK_E ))
	{ 
		rotation = -0.004f;
	}

	if( BUTTONDOWN( mouseState_, 0 ) && !BUTTONDOWN( prevMouseState_, 0 ) ) 
    {
		 //fire!!!!
        ;
    }
 

    memcpy( prevKeyboardKeys_, keyboardKeys_, sizeof( keyboardKeys_ ) );
	 memcpy( &prevMouseState_, &mouseState_, sizeof( mouseState_ ) );
	
	 if (dy >= SHIPSPEED)
		dy = SHIPSPEED;
	else if (dy <= -SHIPSPEED)
		dy = -SHIPSPEED;
	if (dx >= SHIPSPEED)
		dx = SHIPSPEED;
	else if (dx <= -SHIPSPEED)
		dx = -SHIPSPEED;

	/* mousePosX_ += mouseState_.lX;
    mousePosY_ += mouseState_.lY;
    mouseWheel_ += mouseState_.lZ;*/
	  setRotation(rotation);

	sprite0.y += dy;
	sprite0.x += dx;
	bool wrap = sprites_[0].wrap(sprite0);
	
	sprites_[0].setPosition(sprite0);
}

I fixed the ship so that it can rotate clockwise and counter clockwise, I had an if statement that was resetting the rotation value to 0 when it was less than 0, not allowing counter clockwise rotations. However I still haven't got the sprite to rotate around its own origin and not its starting position.



#5 HappyCoder   Members   -  Reputation: 2554

Like
0Likes
Like

Posted 10 July 2013 - 02:34 PM

When you multiply the rotation matrix with the world matrix, try switching the order of the matrices.

XMMATRIX mvp = XMMatrixMultiply(vpMatrix_, world);
When multiplying matrices, remember that the matrix closer to the vertex gets applied first. For example.

transformedPoint = vertex * R * W

suppose R and W are matrices. R rotates, W is the existing world matrix. Notice how the vertex is next to R first then W. That means the rotation happens first, then any transformations found in W.

#6 cheese4432   Members   -  Reputation: 108

Like
0Likes
Like

Posted 10 July 2013 - 03:16 PM

So I tried that and my sprite disappeared :( .  So I changed:

vpMatrix_ = vpMatrix_*XMMatrixRotationZ(rotation);

to:

vpMatrix_ = XMMatrixRotationZ(rotation)*vpMatrix_;

and the sprite changed to rotating around the bottom left corner of the screen.



#7 HappyCoder   Members   -  Reputation: 2554

Like
0Likes
Like

Posted 10 July 2013 - 03:41 PM

Oops, sorry. I didn't notice that you are multiplying the rotation matrix by vpMatrix_ when you make it. Rotating in the bottom corner means you are rotating properly, you just need t properly apply the translation matrix. Just multiply what you have now with your translation matrix and that should do it. Just as a side note you generally multiply transformation matrices in this order.

result = vertex * ScaleMatrix * RotationMatrix * TranslationMatrix

That means you scale it in place first, rotate around its local origin, then move the origin of the sprite.

#8 BornToCode   Members   -  Reputation: 918

Like
0Likes
Like

Posted 10 July 2013 - 04:40 PM

If it is rotating in the wrong direction, why don't you rotate in the opposite direction.



#9 cheese4432   Members   -  Reputation: 108

Like
0Likes
Like

Posted 10 July 2013 - 05:34 PM

I've gotten the sprite to rotate the correct direction, but still around the wrong point, right now I have this:

vpMatrix_ = XMMatrixRotationZ(rotation)*vpMatrix_*XMMatrixTranslation(sprites_[0].getPositionX(), sprites_[0].getPositionY(), 0.0f);
XMMATRIX world = sprites_[0].GetWorldMatrix();
XMMATRIX mvp = XMMatrixMultiply(world, vpMatrix_);
mvp = XMMatrixTranspose(mvp);

in the render function. Multiplying the translation matrix in makes the sprite disappear, and I can't find where else I could multiply it in in order to apply especially since that should already be happening in the getWorldMatrix function.



#10 BornToCode   Members   -  Reputation: 918

Like
0Likes
Like

Posted 10 July 2013 - 08:29 PM

To have it rotate around a point you want to translate to the point first then perform the rotation and translated it back to his original position.



#11 cheese4432   Members   -  Reputation: 108

Like
0Likes
Like

Posted 10 July 2013 - 11:03 PM

So I want the sprite to rotate around its origin, at the moment it's rotating around the bottom left hand corner. right now I am modifying vpMatrix_ and the world matrix to move the sprite around. vpMatrix_ is created in my loadContent function which sets up the shaders and buffers for directx, and vpMatrix_ is created by the following:

XMMATRIX view = XMMatrixIdentity();
XMMATRIX projection = XMMatrixOrthographicOffCenterLH(0.0f, 800.0f, 0.0f, 600.0f, 0.1f, 100.0f);

vpMatrix_ = XMMatrixMultiply(view, projection);

Now as far as I know I want to modifying a matrix that the sprite is part of, but I don't have a matrix for the sprite. Should I make one? Right now the vertices of the sprite are stored in an array. And if I should make one what do I put in it, and how do I initialize it?

 

The array of vertices for the sprite goes as follows:

struct VertexPos
{
    XMFLOAT3 pos;
    XMFLOAT2 tex0;
};

VertexPos vertices[6]; //a rectangle

	ID3D11Resource* colorTex;
	colorMap_->GetResource( &colorTex);

	//ID3D11Texture2D
	 D3D11_TEXTURE2D_DESC colorTexDesc;
    ( ( ID3D11Texture2D* )colorTex )->GetDesc( &colorTexDesc );
	 float halfWidth = ( float )colorTexDesc.Width / 2.0f;
    float halfHeight = ( float )colorTexDesc.Height / 2.0f;
	colorTex->Release();

	/*VertexPos*/
	 vertices[0].pos = XMFLOAT3( halfWidth, halfHeight, 1.0f); vertices[0].tex0 =  XMFLOAT2(1.0f, 0.0f);		
	 vertices[1].pos =	XMFLOAT3(halfWidth, -halfHeight, 1.0f); vertices[1].tex0 = XMFLOAT2( 1.0f, 1.0f);
	 vertices[2].pos =	XMFLOAT3(-halfWidth, -halfHeight, 1.0f); vertices[2].tex0 = XMFLOAT2(0.0f, 1.0f);
	 vertices[3].pos =	XMFLOAT3(-halfWidth, -halfHeight, 1.0f); vertices[3].tex0 = XMFLOAT2(0.0f, 1.0f);
	 vertices[4].pos =	XMFLOAT3(-halfWidth, halfHeight, 1.0f); vertices[4].tex0 = XMFLOAT2(0.0f, 0.0f);
	 vertices[5].pos =	XMFLOAT3(halfWidth, halfHeight, 1.0f); vertices[5].tex0 = XMFLOAT2(1.0f, 0.0f);





Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS