Jump to content
  • Advertisement
MarcusAseth

Lost in the Matrix

Recommended Posts

Basically I wanted to become more familiar with matrix usage, starting 2D, so I put up a basic setup where I have an "interactive wheel" that spits out whatever angle its handle is set to (image below)

Now I have my basisVector y and x because I get the feeling those are needed, and I have a horizontal line floating on top of y.

My goal would be to rotate that line with a vector Matrix multiplication based on the angle I get from my interactive wheel, as you would do in 3d I guess (the whole point of this is to get me familiar with matrices usage after all, so it need to be done that way), the problem is that from here I don't know how to proceed to build my rotation matrix, where to place my elements, what multiply with what...I am kind of lost.

so this below is the code situation, and I need some help to get from where I am to where I want to be... :S

float angle = mHandle->getHandleAngle();
D2D1_POINT_2F basisX = { 1,0 };
D2D1_POINT_2F basisY = { 0,1 };

//draw line
mBrush->SetColor(D2D1::ColorF(0.87f, 0.3f, 0.36f, 1.f));
D2D1_POINT_2F lineP1 = D2D1::Point2F(mOriginX - 100, mOriginY - 150);
D2D1_POINT_2F lineP2 = D2D1::Point2F(mOriginX + 100, mOriginY - 150);
mRenderTarget->DrawLine(lineP1, lineP2, mBrush, 2.f);

//replace draw line above with a line rotated by a rotation matrix
mRenderTarget->DrawLine(D2D1::Point2F(),//Begin point
			D2D1::Point2F(),//End point
			mBrush, 2.f);

HY5KITZ.png

Edited by MarcusAseth

Share this post


Link to post
Share on other sites
Advertisement

Check out this article here https://msdn.microsoft.com/en-us/library/windows/desktop/ff684172(v=vs.85).aspx. The classic clock exercise will give you a good idea as to how rotations work and how to use them in Direct2D.

Basically you will need to use the D2D1::Matrix3x2F class (particularly the D2D1::Matrix3x2F::Rotation(angle, center) function) to create a rotation matrix and then apply it to both lineP1 and lineP2 before rendering them. 

Share this post


Link to post
Share on other sites

@ninnghazad:  that link really helped, thanks again :D I started reading the openGL link, didn't finished it because I wanted to test with code after reading about the rotation matrix, and it works. I'll go back finish reading since I need a better grasp on this, meanwhile, below the code and gif of the thing working :P

Ignore the fact I am re-calculating the shape point at every draw even though those won't change, I just needed to see it all together in a single page.

void Matrix2DClient::Update(float dt)
{
	mHandle->update();
}

void Matrix2DClient::Draw()
{
	mRenderTarget->Clear(D2D1::ColorF(0.34f, 0.36f, 0.4f, 1.0f));
	makeGrid(100, 45.f);

	mHandle->draw();


	float angle = mHandle->getHandleAngle();//angle in degree

	D2D1_POINT_2F basisX = { cos(rad(angle)), sin(rad(-angle)) }; //for angle == 0°,  (1,0)
	D2D1_POINT_2F basisY = { -sin(rad(-angle)), cos(rad(angle)) };//for angle == 0°,  (0,1)
	{
		float displayLenght = 100;
		//draw basisX
		mBrush->SetColor(D2D1::ColorF(0.86f, 0.1f, 0.2f, 1.f));
		float basisXnewX = mOriginX + basisX.x * displayLenght; //draw axis at origin
		float basisXnewY = mOriginY + basisX.y * displayLenght; //draw axis at origin
		mRenderTarget->DrawLine(D2D1::Point2F(mOriginX, mOriginY),
								D2D1::Point2F(basisXnewX, basisXnewY), mBrush, 2.f);
		mRenderTarget->DrawTextW(L"x", 1, mTextFormat, D2D1::RectF(basisXnewX, basisXnewY, 1000, 1000), mBrush);
		
		//draw basisY
		mBrush->SetColor(D2D1::ColorF(0.1f, 0.86f, 0.2f, 1.f));
		float basisYnewX = mOriginX + -basisY.x * displayLenght; //draw axis at origin
		float basisYnewY = mOriginY + -basisY.y * displayLenght; //draw axis at origin
		mRenderTarget->DrawLine(D2D1::Point2F(mOriginX, mOriginY),
								D2D1::Point2F(basisYnewX, basisYnewY), mBrush, 2.f);
		mRenderTarget->DrawTextW(L"y", 1, mTextFormat, D2D1::RectF(basisYnewX, basisYnewY, 1000, 1000), mBrush);
	}

	//star image points
	const unsigned points = 5;
	float r = 100.f;
	D2D1_POINT_2F linePoint[points] = {
	D2D1::Point2F(   r*cos(rad(90))  ,    r* -sin(rad( 90))),//1
	D2D1::Point2F(   r*cos(rad(234)) ,   -(r*sin(rad(234)))),//2
	D2D1::Point2F(    r*cos(rad( 18)),     r*-sin(rad( 18))),//3
	D2D1::Point2F(    r*cos(rad(162)),     r*-sin(rad(162))),//4
	D2D1::Point2F(    r*cos(rad(306)),  -(r* sin(rad(306)))),//5
	};
	//offset 
	float offsetX = 200;
	float offsetY = 20;
	for (auto& p : linePoint)
	{
		p.x += offsetX;
		p.y -= offsetY;
	}

	//rotation matrix|  3rd column is for translate the points to the origin (center of screen)
	  	     //columns-> |   1   | |   2   |  |   3   |
	float R[3][3] = /*row1*/{ basisX.x, basisY.x, mOriginX ,

			/*row2*/  basisX.y, basisY.y, mOriginY ,

			/*row3*/	 0    ,     0   ,       1
	};

	//for every point, apply rotation matrix
	for (size_t i = 0; i < points; i++)
	{
		D2D1_POINT_2F newPoint = D2D1::Point2F(
			R[0][0] * linePoint[i].x + R[0][1] * linePoint[i].y + R[0][2] * 1,//X
			R[1][0] * linePoint[i].x + R[1][1] * linePoint[i].y + R[1][2] * 1 //Y
		);
		linePoint[i] = newPoint;
	}

	//draw line
	mBrush->SetColor(D2D1::ColorF(0.87f, 0.3f, 0.36f, 1.f));
	for (size_t i = 0; i < points; i++)
	{
		if (i == points - 1) {//connect last point with first
			mRenderTarget->DrawLine(linePoint[i], linePoint[0], mBrush, 2.f);
		} else {
			mRenderTarget->DrawLine(linePoint[i], linePoint[i + 1], mBrush, 2.f);
		}

	}

}

 

VY5wCU3.gif

 

Edited by MarcusAseth

Share this post


Link to post
Share on other sites

I've took it a step further, added the third dimension using direct2D, feels like cheating :D

I was so focused on having it work trough trials and errors that the code became real ugly, so I'll refrain from pasting that xD

I guess now is only a matter of deleting the code and do it again, until I can do all the steps without any mistakes :P

rGoTTgn.gif

Edited by MarcusAseth

Share this post


Link to post
Share on other sites

Experiments went too far, the cube took life and seems threatening, I'll call it the "slimy dancing cube of spite" and proceed to abort experiments. It looks fun and I thought was worth sharing :D

Also the bad random code for it in the spoiler, in case someone need a slimy dancing cube 

image:

tte6lRG.gif

Spoiler

Matrix2DClient::Matrix2DClient(HINSTANCE instance, std::wstring caption, float clientWidth, float clientHeight)
    :D2DApp(instance, caption, clientWidth, clientHeight), mOriginX{ 0 }, mOriginY{ 0 }
{
    std::array<std::array<float, 3>, 9> tempCubePoint = {
        -70.82,   -112.90,   -40.75,//0
        -0.34 ,   -170.82,      0.2,//1
        0.11,   -112.90,    81.71,//2
        -70.59,    -54.97,    40.75,//3
        0.34,      2.38,     -0.2,//4
        0.11,    -55.54,   -81.71,//5
        70.59,   -113.46,   -40.75,//6
        70.82,    -55.54,    40.75, //7
        1,1,1
    };

    cubePoint = tempCubePoint;
    //cubes is an array of 250 cubes
    for (auto& c : cubes) { c = tempCubePoint; }
}

void Matrix2DClient::Draw()
{
    static D2D1_COLOR_F clearColor = D2D1::ColorF(0.34f, 0.39f, 0.4f, 1.0f);
    mRenderTarget->Clear(clearColor);
    makeGrid(100, 45.f);

    static float constRotation;
    constRotation += constRotation + 1.7 < 360 ? 1.7 : -constRotation;

    float RX[3][3] = { 1     ,      0     ,     0     ,

                         0       ,cos(rad(constRotation)) ,sin(rad(constRotation)),

                         0     ,-sin(rad(constRotation)),cos(rad(constRotation))
    };

    float RY[3][3] = { cos(rad(constRotation)),     0     ,-sin(rad(constRotation)),

                               0      ,             1     ,           0            ,

                       sin(rad(constRotation)),     0,      cos(rad(constRotation))
    };

    float RZ[3][3] = { cos(rad(0)),  sin(rad(0)),  0,

                      -sin(rad(0)),  cos(rad(0)),  0,

                             0        ,         0       ,  1
    };

    for (size_t c = 0; c < cubes.size(); c++)
    {
        std::array<std::array<float, 3>, 3> finalMatrix = mBasisVectors;
        std::array<std::array<float, 3>, 3> intermediateMatrix1 = mBasisVectors;
        std::array<std::array<float, 3>, 3> intermediateMatrix2 = mBasisVectors;


        //rotate on axis X  (basisVectors x RotationX) = intermediateMatrix1
        for (size_t i = 0; i < 3; i++)
        {
            for (size_t j = 0; j < 3; j++)
            {
                float sum = 0;
                for (size_t k = 0; k < 3; k++)
                {
                    sum += mBasisVectors[i][k] * RX[k][j];
                }
                intermediateMatrix1[i][j] = sum;
            }
        }

        //add scale
        static float size = 0.02f;
        static int sign = 1;
        if (c == 0)
        {
            float increase = 0.0012f;
            if (size + increase*sign > 0.02f || size + increase*sign < 0.01f) { sign *= -1; }
            size += increase*sign;
        }

        intermediateMatrix1[0][0] = intermediateMatrix1[0][0] * size*(((c + 1))/2);
        intermediateMatrix1[1][1] = intermediateMatrix1[1][1] * size*(((c + 1))/2);
        intermediateMatrix1[2][2] = intermediateMatrix1[2][2] * size*(((c + 1))/2);



        //rotate on axis Y (intermediateMatrix1 x RotationY) = intermediateMatrix2
        for (size_t i = 0; i < 3; i++)
        {
            for (size_t j = 0; j < 3; j++)
            {
                float sum = 0;
                for (size_t k = 0; k < 3; k++)
                {
                    sum += intermediateMatrix1[i][k] * RY[k][j];
                }
                intermediateMatrix2[i][j] = sum;
            }
        }


        //rotate on axis Z (intermediateMatrix2 x RotationZ) = finalMatrix
        for (size_t i = 0; i < 3; i++)
        {
            for (size_t j = 0; j < 3; j++)
            {
                float sum = 0;
                for (size_t k = 0; k < 3; k++)
                {
                    sum += intermediateMatrix2[i][k] * RZ[k][j];
                }
                finalMatrix[i][j] = sum;
            }
        }
        //for every point, apply the rotation finalMatrix

        for (size_t i = 0; i < cubePoint.size(); i++)
        {
            cubes[c][i][0] = cubePoint[i][0] * finalMatrix[0][0] + cubePoint[i][1] * finalMatrix[0][1] + cubePoint[i][2] * finalMatrix[0][2];//X
            cubes[c][i][1] = cubePoint[i][0] * finalMatrix[1][0] + cubePoint[i][1] * finalMatrix[1][1] + cubePoint[i][2] * finalMatrix[1][2];//Y
            cubes[c][i][2] = cubePoint[i][0] * finalMatrix[2][0] + cubePoint[i][1] * finalMatrix[2][1] + cubePoint[i][2] * finalMatrix[2][2];//Z
            cubes[c][8][0] = abs(size*(c / 2)); //color
            cubes[c][8][1] = abs(size*(c / 2)); //color
            cubes[c][8][2] = abs(size*(c / 2)); //color
        }
    }


    //draw cube
    for (size_t c = 0; c < cubes.size(); c++)
    {
        mBrush->SetColor(D2D1::ColorF(sin(rad(cubes[c][1][1]*2)), cos(rad(cubes[c][0][0])) , cos(rad(cubes[c][0][0])), 1.f));
        float strokeSize = 2.f;
        mRenderTarget->DrawLine(D2D1::Point2F(mOriginX + cubes[c][0][0], mOriginY + cubes[c][0][1]), D2D1::Point2F(mOriginX + cubes[c][1][0], mOriginY + cubes[c][1][1]), mBrush, strokeSize);
        mRenderTarget->DrawLine(D2D1::Point2F(mOriginX + cubes[c][1][0], mOriginY + cubes[c][1][1]), D2D1::Point2F(mOriginX + cubes[c][6][0], mOriginY + cubes[c][6][1]), mBrush, strokeSize);
        mRenderTarget->DrawLine(D2D1::Point2F(mOriginX + cubes[c][6][0], mOriginY + cubes[c][6][1]), D2D1::Point2F(mOriginX + cubes[c][5][0], mOriginY + cubes[c][5][1]), mBrush, strokeSize);
        mRenderTarget->DrawLine(D2D1::Point2F(mOriginX + cubes[c][5][0], mOriginY + cubes[c][5][1]), D2D1::Point2F(mOriginX + cubes[c][0][0], mOriginY + cubes[c][0][1]), mBrush, strokeSize);
        mRenderTarget->DrawLine(D2D1::Point2F(mOriginX + cubes[c][1][0], mOriginY + cubes[c][1][1]), D2D1::Point2F(mOriginX + cubes[c][2][0], mOriginY + cubes[c][2][1]), mBrush, strokeSize);
        mRenderTarget->DrawLine(D2D1::Point2F(mOriginX + cubes[c][6][0], mOriginY + cubes[c][6][1]), D2D1::Point2F(mOriginX + cubes[c][7][0], mOriginY + cubes[c][7][1]), mBrush, strokeSize);
        mRenderTarget->DrawLine(D2D1::Point2F(mOriginX + cubes[c][5][0], mOriginY + cubes[c][5][1]), D2D1::Point2F(mOriginX + cubes[c][4][0], mOriginY + cubes[c][4][1]), mBrush, strokeSize);
        mRenderTarget->DrawLine(D2D1::Point2F(mOriginX + cubes[c][0][0], mOriginY + cubes[c][0][1]), D2D1::Point2F(mOriginX + cubes[c][3][0], mOriginY + cubes[c][3][1]), mBrush, strokeSize);
        mRenderTarget->DrawLine(D2D1::Point2F(mOriginX + cubes[c][3][0], mOriginY + cubes[c][3][1]), D2D1::Point2F(mOriginX + cubes[c][2][0], mOriginY + cubes[c][2][1]), mBrush, strokeSize);
        mRenderTarget->DrawLine(D2D1::Point2F(mOriginX + cubes[c][2][0], mOriginY + cubes[c][2][1]), D2D1::Point2F(mOriginX + cubes[c][7][0], mOriginY + cubes[c][7][1]), mBrush, strokeSize);
        mRenderTarget->DrawLine(D2D1::Point2F(mOriginX + cubes[c][7][0], mOriginY + cubes[c][7][1]), D2D1::Point2F(mOriginX + cubes[c][4][0], mOriginY + cubes[c][4][1]), mBrush, strokeSize);
        mRenderTarget->DrawLine(D2D1::Point2F(mOriginX + cubes[c][4][0], mOriginY + cubes[c][4][1]), D2D1::Point2F(mOriginX + cubes[c][3][0], mOriginY + cubes[c][3][1]), mBrush, strokeSize);
    }
}

 

 

Edited by MarcusAseth

Share this post


Link to post
Share on other sites

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!