I am creating a 3D scene and I have just inserted a cube object into it. It is rendered fine at the origin but when I try to rotate it and then translate it I get a huge deformed cube. Here is the problem area in my code:
D3DXMATRIX cubeROT, cubeMOVE;
D3DXMatrixRotationY(&cubeROT, D3DXToRadian(45.0f));
D3DXMatrixTranslation(&cubeMOVE, 10.0f, 2.0f, 1.0f);
D3DXMatrixTranspose(&worldMatrix, &(cubeROT * cubeMOVE));
// Put the model vertex and index buffers on the graphics pipeline to prepare them for drawing.
m_Model->Render(m_Direct3D->GetDeviceContext());
// Render the model using the light shader.
result = m_LightShader->Render(m_Direct3D->GetDeviceContext(), m_Model->GetIndexCount(), worldMatrix, viewMatrix, projectionMatrix,
m_Model->GetTexture(), m_Light->GetDirection(), m_Light->GetDiffuseColor());
// Reset the world matrix.
m_Direct3D->GetWorldMatrix(worldMatrix);
I have discovered that it's the cubeMOVE part of the transpose that is giving me the problem but I have no idea why.
This rotates the cube properly:
D3DXMatrixTranspose(&worldMatrix, &cubeROT);
This translates the cube properly:
D3DXMatrixTranslation(&worldMatrix, 10.0f, 2.0f, 1.0f);
But this creates the deformed mesh:
D3DXMatrixTranspose(&worldMatrix, &cubeMOVE);
I'm quite new to DirectX so any help would be very much appreciated.
I don't think transpose does what you think it does. To combine transformation matrices, you just multiply them -- no need to transpose. I guess it should be simply:
worldMatrix = cubeROT * cubeMOVE;
Edit
The reason "transpose" seems to work for rotation but not translation, is that transpose flips the non-diagonal parts of the matrix. But for an axis-rotation matrix, that leaves the matrix nearly unchanged. (It does change a couple of signs, but that would only affect the direction of the rotation.) For a translation matrix, applying a transpose would completely deform it -- hence the result you see.
Related
I use DirectX Toolkit to display a 3d model, following the 'Rendering the model' and my pyramid is displayed:
When trying to transform the object, the scaling and rotation work well but I'm not sure how to move the object (translate) around. Basically I'm looking for an algorithm that determines, given the current camera position, focus, viewport and the rendered model (which the DirectX toolkit gives me the bounding box so it's "size") the minimum and maximum values for XYZ translation so the object remains visible.
The bounding box is always the same, no matter the view port size, so how do I compare it's size against my viewport?
Please excuse my newbiness, I'm not a 3D developer, at least yet.
The "Simple Rendering" example which draws a triangle:
Matrix proj = Matrix::CreateScale( 2.f/float(backBufferWidth),
-2.f/float(backBufferHeight), 1.f)
* Matrix::CreateTranslation( -1.f, 1.f, 0.f );
m_effect->SetProjection(proj);
says that the normalized triangle size is [1,1,1] but here normalized values do not work.
TL:DR: To move your model around the world, create a matrix for the translation and set it as the world matrix with SetWorld.
Matrix world = Matrix::CreateTranslation( 2.f, 1.f, 3.f);
m_effect->SetWorld(world);
// Also be sure you have called SetView and SetProjection for the 3D camera setup
//covered in the 3D shapes / Rendering a model tutorial
You should start with a basic review of 3D transformations, in particular the world -> view -> projection transformation pipeline.
The world transformation performs the affine transformation to get the model you are rendering into it's 'world' position. (a.k.a. 'local coordinates to world coordinates transformation').
The view transformation performs the transformation to get world positions into the camera's point of view (i.e. position and direction) (a.k.a. 'world coordinates to view coordinates transformation').
The projection transformation performs the transformation to get the view positions into the canonical "-1 to 1" range that the actual hardware uses, including any perspective projection (a.k.a. 'view coordinates to 'clip' coordinates transformation).
The hardware itself performs the final step of converting the "-1 to 1" to pixel locations in the render target based on the Direct3D SetViewport information (a.k.a. 'clip' coordinates to pixel coordinates transformation).
This Direct3D 9 era article is a bit dated, but it covers the overall idea well.
In the DirectX Tool Kit BasicEffect system, there are distinct methods for each of these matrices: SetWorld, SetView, and SetProjection. There is also a helper if you want to set all three at once SetMatrices.
The simple rendering tutorial is concerned with the simplest form of rendering, 2D rendering, where you want the coordinates you provide to be in natural 'pixel coordinates'
Matrix proj = Matrix::CreateScale( 2.f/float(backBufferWidth),
-2.f/float(backBufferHeight), 1.f)
* Matrix::CreateTranslation( -1.f, 1.f, 0.f );
m_effect->SetProjection(proj);
The purpose of this matrix is to basically 'undo' what the SetViewport will do so that you can think in simple pixel coordinates. It's not suitable for 3D models.
In the 3D shapes tutorial I cover the basic camera model, but I leave the world matrix as the identity so the shape is sitting at the world origin.
m_view = Matrix::CreateLookAt(Vector3(2.f, 2.f, 2.f),
Vector3::Zero, Vector3::UnitY);
m_proj = Matrix::CreatePerspectiveFieldOfView(XM_PI / 4.f,
float(backBufferWidth) / float(backBufferHeight), 0.1f, 10.f);
In the Rendering a model tutorial, I also leave the world matrix as identity. I get into the basics of this in Basic game math tutorial.
One of the nice properties of affine transformations is that you can perform them all at once by transforming by the concatenation of the individual transforms. Point p transformed by matrix W, then transformed by matrix V, then transformed by matrix P is the same as point p transformed by matrix W * V * P.
I am just playing around the template setup in MTKView; and, I have been trying to understand the followings:
Default location of the camera.
The default location when creating primitives using MDLMesh and MTKMesh.
Why does a rotation involve also a translation.
Relevant code:
matrix_float4x4 base_model = matrix_multiply(matrix_from_translation(0.0f, 0.0f, 5.0f), matrix_from_rotation(_rotation, 0.0f, 1.0f, 0.0f));
matrix_float4x4 base_mv = matrix_multiply(_viewMatrix, base_model);
matrix_float4x4 modelViewMatrix = matrix_multiply(base_mv, matrix_from_rotation(_rotation, 0.0f, 1.0f, 0.0f));
The preceding code is from the _update method by the template; evidently, it is trying to rotate the model instead of the camera. But what baffles me is the fact that it requires also a translation. I have read claims such as "because it always rotates at (0, 0, 0)". But why (0, 0, 0), if the object is placed somewhere else? Also, it appears to me that the camera is looking at the positive z-axis (question 1) instead of the usual negative z-axis because if I change:
matrix_float4x4 base_model = matrix_multiply(matrix_from_translation(0.0f, 0.0f, 5.0f), matrix_from_rotation(_rotation, 0.0f, 1.0f, 0.0f));
to:
matrix_float4x4 base_model = matrix_multiply(matrix_from_translation(0.0f, 0.0f, -5.0f), matrix_from_rotation(_rotation, 0.0f, 1.0f, 0.0f));
nothing will be displayed on the screen because it appears that the object is behind the camera, which means that the camera is looking at the positive z-axis.
If I set matrix_from_translation(0.0f, 0.0f, 0.0f) (all zeros), the object simply rotate not on the y-axis (question 3) as I expected.
I have tried to find out where the MDLMesh and MTKMesh is placed by default (question 2), but I could not find a property that logs its position. The following is, also by the template, how the primitive is created:
MDLMesh *mdl = [MDLMesh newBoxWithDimensions:(vector_float3){2,2,2} segments:(vector_uint3){1,1,1}
geometryType:MDLGeometryTypeTriangles inwardNormals:NO
allocator:[[MTKMeshBufferAllocator alloc] initWithDevice: _device]];
_boxMesh = [[MTKMesh alloc] initWithMesh:mdl device:_device error:nil];
Without knowing its location generated by the above method, it hinders my understanding of how the rotation and translation work and the default location the camera in Metal.
Thanks.
I think the order in which the matrices are written in the code somewhat obfuscates the intent, so I've boiled down what's actually happening into the following pseudocode to make it easier to explain.
I've replaced that last matrix with the one from the template, since your modification just has the effect of doubling the rotation about the Y axis.
modelViewMatrix = identity *
translate(0, 0, 5) *
rotate(angle, axis(0, 1, 0)) *
rotate(angle, axis(1, 1, 1))
Since the matrix is multiplied on the left of the vector in the shader, we're going to read the matrices from right to left to determine their cumulative effect.
First, we rotate the cube around the axis (1, 1, 1), which passes diagonally through the origin. Then, we rotate about the cube about the Y axis. These rotations combine to form a sort of "tumble" animation. Then, we translate the cube by 5 units along the +Z axis (which, as you observe, goes into the screen since we're regarding our world as left-handed). Finally, we apply our camera transformation, which is hard-coded to be the identity matrix. We could have used an additional positive translation along +Z as the camera matrix to move the cube even further from the camera, or a negative value to move the cube closer.
To answer your questions:
There is no default location for the camera, other than the origin (0, 0, 0) if you want to think of it like that. You "position" the camera in the world by multiplying the vertex positions by the inverse of the transformation that represents how the camera is placed in the world.
Model I/O builds meshes that are "centered" around the origin, to the extent this makes sense for the shape being generated. Cylinders, ellipsoids, and boxes are actually centered around the origin, while cones are constructed with their apex at the origin and their axis extending along -Y.
The rotation doesn't really involve the translation as much as it's combined with it. The reason for the translation is that we need to position the cube away from the camera; otherwise we'd be inside it when drawing.
One final note on order of operations: If we applied the translation before the rotation, it would cause the box to "orbit" around the camera, since as you note, rotations are always relative to the origin of the current frame of reference.
I'm trying out D3D11 and struggling to render a model correctly.
Here's my problem; while my world and view transformations seem right,
my perspective transformation seems to be wrong.
When I first rendered a model, something felt wrong, so I tried rotating the model to see what it was.
Then I noticed that, parts of the model closer to the camera appears smaller, and further parts appear larger.
If it's relevant, I'm using assimp to load my model, and here's how I do it.
mScene = aiImportFile(filename.c_str(), aiProcessPreset_TargetRealtime_MaxQuality | aiProcess_GenSmoothNormals | aiProcess_ConvertToLeftHanded | aiProcess_TransformUVCoords);
And here's how I build my projection matrix.
mProjection = XMMatrixPerspectiveFovLH(XMConvertToRadians(45.0f), 800.0f / 600.0f, -1.0f, 1.0f);
I fiddled with nearZ and farZ arguments of XMMatrixPerspectiveFovLH.
I tried increasing farZ gradually every frame, and then realized that as the value increases, the far clipping plane comes closer and closer to the camera, which is exactly the opposite of what I thought would happen.
In vertex shader, here's what I'm doing with vertex positions. It's pretty basic.
Out.Position = mul(mul(mul(position, World), CameraView), CameraProjection);
The model renders correctly in terms of position, scaling, rotation, and view-position.
So I'm assuming that world and view transforms are fine, and the problem is about the projection matrix.
To summarize, I'm thinking that Z values of projected vertices are, somehow, "flipped".
I google-searched many many times to no avail.
If someone could point out what I could be doing wrong, it would be very much appreciated.
If you need to see some of my code to help, please tell me.
Your near and far plane distances should be positive.
Use something like:
mProjection = XMMatrixPerspectiveFovLH(XMConvertToRadians(45.0f), 800.0f / 600.0f, 0.1f, 10.0f);
I'll make a note to consider adding assert( NearZ > 0.f); assert( NearZ < FarZ ); to those DirectXMath functions and make sure that's explicit in the docs. distance means positive number here.
PS: You should take a look at DirectX Tool Kit
I want to create the same transforming effect on XNA 4 as Photoshop does:
Transform tool is used to scale, rotate, skew, and just distort the perspective of any graphic you’re working with in general
This is what all the things i want to do in XNA with any textures http://www.tutorial9.net/tutorials/photoshop-tutorials/using-transform-in-photoshop/
Skew: Skew transformations slant objects either vertically or horizontally.
Distort: Distort transformations allow you to stretch an image in ANY direction freely.
Perspective: The Perspective transformation allows you to add perspective to an object.
Warping an Object(Im interesting the most).
Hope you can help me with some tutorial or somwthing already made :D, iam think vertex has the solution but maybe.
Thanks.
Probably the easiest way to do this in XNA is to pass a Matrix to SpriteBatch.Begin. This is the overload you want to use: MSDN (the transformMatrix argument).
You can also do this with raw vertices, with an effect like BasicEffect by setting its World matrix. Or by setting vertex positions manually, perhaps transforming them with Vector3.Transform().
Most of the transformation matrices you want are provided by the Matrix.Create*() methods (MSDN). For example, CreateScale and CreateRotationZ.
There is no provided method for creating a skew matrix. It should be something like this:
Matrix skew = Matrix.Identity;
skew.M12 = (float)Math.Tan(MathHelper.ToRadians(36.87f));
(That is to skew by 36.87f degrees, which I pulled off this old answer of mine. You should be able to find the full maths for a skew matrix via Google.)
Remember that transformations happen around the origin of world space (0,0). If you want to, for example, scale around the centre of your sprite, you need to translate that sprite's centre to the origin, apply a scale, and then translate it back again. You can combine matrix transforms by multiplying them. This example (untested) will scale a 200x200 image around its centre:
Matrix myMatrix = Matrix.CreateTranslation(-100, -100, 0)
* Matrix.CreateScale(2f, 0.5f, 1f)
* Matrix.CreateTranslation(100, 100, 0);
Note: avoid scaling the Z axis to 0, even in 2D.
For perspective there is CreatePerspective. This creates a projection matrix, which is a specific kind of matrix for projecting a 3D scene onto a 2D display, so it is better used with vertices when setting (for example) BasicEffect.Projection. In this case you're best off doing proper 3D rendering.
For distort, just use vertices and place them manually wherever you need them.
I have been wondering for a while about how the transform matrix in spriteBatch is implemented. I've created a 2D camera, and the transform matrix is as follows:
if (needUpdate)
transformMatrix =
Matrix.CreateTranslation(-Position.X, -Position.Y, 0) *
Matrix.CreateScale(curZoom, curZoom, 1) ; needUpdate = false;
The camera works as good as I want, but I just want to know how the transformation is applied: Does the transformation only affects the axis of the sprites, or the screen co-ordinates too?
Thanks in advance!
I see you've answered your own question, but to provide complete information - SpriteBatch provides a similar interface to the traditional world-view-projection system of transformations.
The SpriteBatch class has an implicit projection matrix that takes coordinates in the "client space" of the viewport ((0,0) at the top left, one unit per pixel) and puts them on screen.
The Begin call has an overload that accepts a transformation matrix, which is the equivalent of a view matrix used for moving the camera around.
And the Draw call, while not actually using a matrix, allows you to specify position, rotation, scale, etc - equivalent to a world matrix used for positioning a model in the scene (model space to world space).
So you start with your "model" equivalent - which for SpriteBatch is a quad (sprite) of the size of the texture (or source rectangle). When drawn, that quad is transformed to its world coordinates, then that is transformed to its view coordinates, and then finally that is transformed to its projection coordinates.