如何在DirectX 11中实现2D纹理绕自身中心旋转?
Hey there, let's tackle your rotation issue—this is a super common gotcha with 2D transformations in DirectX, so you're not alone here!
The core problem is that when you apply a rotation directly to your texture's position, the rotation happens around the world origin (0,0) (usually the top-left corner of the screen) instead of the texture's own center. To fix this, you need to adjust the order of your transformations:
The Correct Transformation Sequence
You need three steps to rotate around the texture center:
- Translate the texture to the world origin: Shift the texture so its center lines up with (0,0). This means subtracting half the texture's width and height from its position.
- Apply the Z-axis rotation: Rotate the texture around the origin using your rotation value.
- Translate the texture back to its original position: Shift it back to where it started, but now centered around its original position.
How to Implement This in Your Code
Let's adjust your existing functions to handle this:
1. Update GraphicsClass::Render to Calculate the Transformation Matrix
First, you'll need to compute the combined world matrix that handles the translate-rotate-translate sequence. Use DirectX's math library (like DirectXMath) for clean matrix operations:
bool GraphicsClass::Render(float rotation) { // Add GetWidth()/GetHeight() methods to BitmapClass if you don't have them already int texWidth = m_bitmap->GetWidth(); int texHeight = m_bitmap->GetHeight(); int positionX = /* Your existing X position value */; int positionY = /* Your existing Y position value */; // Step 1: Shift texture so its center aligns with world origin XMMATRIX translateToOrigin = XMMatrixTranslation(-(texWidth / 2.0f), -(texHeight / 2.0f), 0.0f); // Step 2: Apply Z-axis rotation XMMATRIX rotateMat = XMMatrixRotationZ(rotation); // Step 3: Shift texture back to its original centered position XMMATRIX translateBack = XMMatrixTranslation(positionX + (texWidth / 2.0f), positionY + (texHeight / 2.0f), 0.0f); // Combine matrices (order matters: right-to-left for multiplication in DirectX) XMMATRIX worldMatrix = translateToOrigin * rotateMat * translateBack; // Pass the precomputed world matrix to BitmapClass instead of raw position values m_bitmap->Render(m_deviceContext, worldMatrix); // Rest of your existing rendering logic... return true; }
2. Modify BitmapClass to Use the World Matrix
Your current BitmapClass functions probably set vertex positions directly using positionX/positionY. Instead, shift the transformation work to the GPU (more efficient for dynamic rotations) by passing the world matrix to your vertex shader:
bool BitmapClass::Render(ID3D11DeviceContext* deviceContext, XMMATRIX worldMatrix) { // Update your shader's constant buffer with the world matrix m_shader->SetWorldMatrix(deviceContext, worldMatrix); // Skip manual position updates in UpdateBuffers—let the shader handle transformation RenderBuffers(deviceContext); m_shader->Render(deviceContext, m_indexCount); return true; }
Key Notes
- Matrix Order: DirectX uses row-major matrices, so the multiplication order
translateToOrigin * rotateMat * translateBackcorrectly applies the transforms in the sequence we want (translate to origin → rotate → translate back). - Texture Dimensions: Use the actual pixel dimensions of your texture (not scaled values) when calculating the center offset—this ensures the rotation point is truly the texture's center.
- Vertex Shader Adjustment: Your vertex shader needs to accept the world matrix and apply it to vertex positions. Here's a quick example:
struct VS_INPUT { float4 position : POSITION; float2 texCoord : TEXCOORD0; }; struct PS_INPUT { float4 position : SV_POSITION; float2 texCoord : TEXCOORD0; }; cbuffer MatrixBuffer { matrix world; matrix view; matrix projection; }; PS_INPUT VS(VS_INPUT input) { PS_INPUT output; input.position.w = 1.0f; // Apply world → view → projection transforms output.position = mul(input.position, world); output.position = mul(output.position, view); output.position = mul(output.position, projection); output.texCoord = input.texCoord; return output; }
That should get your texture rotating smoothly around its own center instead of an off-screen origin. If you need help tweaking any specific parts of your existing code, feel free to dig into the details!
内容的提问来源于stack exchange,提问作者adrotter

