Treating 6 quadrangles as a cube with a world transform.

This topic is 2839 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

Recommended Posts

In order to batch draw my quadrangles the world transform is created in my HLSL shader. This means that all my quadrangles are defined in terms of scale, rotation and translation as separate values and not as one matrix.

If I wanted to create a cube then I would define a quadrangle for each cube face:

 faces[0] = new Quadrangle( position + (0.5f * size * -Vector3.UnitX), size, size, -Vector3.UnitX, 0, 0 ); 

where the Quadrangle constructor is as follows:

 public Quadrangle(Vector3 position, float width, float height, Vector3 normal, int texture0Index, int texture1Index) : this(position, width, height, RotationFrom(normal), texture0Index, texture1Index) { } 

The problem I would like some help solving is how can I treat all 6 faces as a cube when it comes to scaling, rotating and translating?

For example if the cube moves then each quadrangle face will have to move according to the centroid position. I'm currently doing this by storing the original position and adding the current position of the cube:

 faces[0].Position = originalFacePositions[0] + cube.Position; faces[1].Position = originalFacePositions[1] + cube.Position; faces[2].Position = originalFacePositions[2] + cube.Position; faces[3].Position = originalFacePositions[3] + cube.Position; faces[4].Position = originalFacePositions[4] + cube.Position; faces[5].Position = originalFacePositions[5] + cube.Position; 

This doesn't seem like the correct way to approach this as adopting the same technique for rotations doesn't produce the correct result:

 faces[0].Rotation = localRotations[0] * rotation; // localRotation = original rotation for this face faces[1].Rotation = localRotations[1] * rotation; faces[2].Rotation = localRotations[2] * rotation; faces[3].Rotation = localRotations[3] * rotation; faces[4].Rotation = localRotations[4] * rotation; faces[5].Rotation = localRotations[5] * rotation; 

How can I correctly scale, rotate and translate each quadrangle face so it would behave like a cube model?

Share on other sites
You shouldn't need to decompose the affine transformation before passing it to the shader. Just store the rows or columns in the per-vertex attributes like in POSITION1, TEXCOORD1, etc. and then reconstruct it first thing in the vertex shader.

There are some limitations on the sort of ranges and accuracies these attributes allow in older shader models, but I think everything from 3.0 and later has uniform, reasonable ranges and accuracies, so not something you have to worry about probably.

...

I don't understand the latter part of your post. Are you trying to apply a transformation to the original cube? Why? Why not just leave it centered at the origin? In fact, if you're going this route, don't be afraid to go full tilt. You can probably stuff all quads into a single draw call. Just make the vertex buffer large enough. Any overhead from larger vertex and index buffers, for instance, is more than offset by the lower draw call count. Then, there's no reason to set up the quads in the shape of a cube in the first place. You can set it up as n unit quads, centered at the origin, all overlapping. Each frame you update the attributes in the vertex buffer corresponding to the rows of your transformation matrix.

I do something similar in my own shader for drawing 2D shapes. I can show it if you're interested (still a work in progress, but might give you an idea).

Share on other sites
[color="#1C2837"]
[color="#1C2837"]
You shouldn't need to decompose the affine transformation before passing it to the shader. Just store the rows or columns in the per-vertex attributes like in POSITION1, TEXCOORD1, etc. and then reconstruct it first thing in the vertex shader.
[color="#1C2837"][/quote]
[color="#1C2837"]
[color="#1C2837"]Are you saying I should calculate the world transform on the CPU and pass that into the shader?

[color="#1C2837"]I currently require the orientation as Up, Right and Normal for correct UV orientation (and lighting):
[color="#1C2837"] [color="#1C2837"] [color="#1C2837"] // [uv coordinates] // • Keep textures vertically aligned to world y Axis (0,1,0) [Quad.Rotation.Up = Vector3.Cross(Vector3.UnitY, normal)] // • Textures are aligned to vector 'v' where [Rotation.Up = Vector3.Cross(v, normal)] float3 v0 = input.Position.xyz - float3(input.IData0.x, input.IData0.y, input.IData0.z); float widthInverse = 1.0f / input.IData3.x; // 1.0f / Width float heightInverse = 1.0f / input.IData3.y; // 1.0f / Height // [Perspective 3D] // • dot(v0, up) input.TextureCoordinates.x = dot(v0, normalize(float3(input.IData1.z, input.IData1.w, input.IData2.x))) * heightInverse + 0.5f; // • dot(v0, right) input.TextureCoordinates.y = dot(v0, normalize(float3(input.IData0.w, input.IData1.x, input.IData1.y))) * widthInverse + 0.5f; [color="#1C2837"]
[color="#1C2837"]
[color="#1C2837"]This would mean that I would have to pass in the world transform along with the rotation, or alternatively a non scaled world transform and scale into the shader. What would you recommend?

[color="#1C2837"]

[color="#1C2837"]I don't understand the latter part of your post. Are you trying to apply a transformation to the original cube?
[color="#1C2837"][/quote]

[color="#1C2837"]- I have 6 quads (all batch drawn/single draw call) that create a cube of unit length.
[color="#1C2837"]- I have a physics engine that provides the world transform of a cube in the physics space
[color="#1C2837"]- I would like to represent the scale, rotation, transformation of the physics cube using the 6 quads

[color="#1C2837"]However, I can't seem to transform the 6 quadrangles by the physics based cube's transform correctly.

[color="#1C2837"]

[color="#1C2837"]You can set it up as n unit quads, centered at the origin, all overlapping. Each frame you update the attributes in the vertex buffer corresponding to the rows of your transformation matrix.
[color="#1C2837"][/quote]

[color="#1C2837"]If I am only provided with one world transform for the cube would it be better this way or would it be better to have the 6 quads arranged as a unit cube around the origin and transform them that way?

[color="#1C2837"]Thanks for offering to help with this.

Share on other sites
I've rewritten my vertex format as suggested:

 struct VertexShaderInputAlt { float4 Position : POSITION0; // Local Vertex Position float4 TexCoordDimension : TEXCOORD0; // [x, y] Texture Coordinates [z, w] Width & Height float4 Column1 : TEXCOORD1; // M11...M14 float4 Column2 : TEXCOORD2; // M21...M24 float4 Column3 : TEXCOORD3; // M31...M34 float4 Column4 : TEXCOORD4; // M41...M44 float4 SourceRectangle0 : TEXCOORD5; // Source Rectangle (Texture Layer 0) float4 SourceRectangle1 : TEXCOORD6; // Source Rectangle (Texture Layer 1) }; 

If I create a cube out of quadrangles:

 public static Quadrangle[] CreateCube() { Quadrangle[] faces = new Quadrangle[6]; // -X faces[0] = new Quadrangle( 0.5f * -Vector3.UnitX, 1, 1, -Vector3.UnitX, 0, 0 ); // +X faces[1] =new Quadrangle( 0.5f * Vector3.UnitX, 1, 1, Vector3.UnitX, 0, 0 ); // -Y faces[2] = new Quadrangle( 0.5f * -Vector3.UnitY, 1, 1, -Vector3.UnitY, 0, 0 ); // +Y faces[3] = new Quadrangle( 0.5f * Vector3.UnitY, 1, 1, Vector3.UnitY, 0, 0 ); // -Z faces[4] = new Quadrangle( 0.5f * -Vector3.UnitZ, 1, 1, -Vector3.UnitZ, 0, 0 ); // +Z faces[5] = new Quadrangle( 0.5f * Vector3.UnitZ, 1, 1, Vector3.UnitZ, 0, 0 ); return faces; } 

and then transform the quadrangle vertices using new vertex format:

 public void Transform(Matrix transform) { // Ignore scale as rotation and scale are required separately in the shader code Matrix worldTransform = rotation; worldTransform.M41 = position.X; worldTransform.M42 = position.Y; worldTransform.M43 = position.Z; worldTransform.M44 = 1f; worldTransform *= transform; vertices[0].Column1.X = worldTransform.M11; vertices[0].Column1.Y = worldTransform.M12; vertices[0].Column1.Z = worldTransform.M13; vertices[0].Column1.W = worldTransform.M14; vertices[0].Column2.X = worldTransform.M21; vertices[0].Column2.Y = worldTransform.M22; vertices[0].Column2.Z = worldTransform.M23; vertices[0].Column2.W = worldTransform.M24; vertices[0].Column3.X = worldTransform.M31; vertices[0].Column3.Y = worldTransform.M32; vertices[0].Column3.Z = worldTransform.M33; vertices[0].Column3.W = worldTransform.M34; vertices[0].Column4.X = worldTransform.M41; vertices[0].Column4.Y = worldTransform.M42; vertices[0].Column4.Z = worldTransform.M43; vertices[0].Column4.W = worldTransform.M44; vertices[1].Column1.X = worldTransform.M11; vertices[1].Column1.Y = worldTransform.M12; vertices[1].Column1.Z = worldTransform.M13; vertices[1].Column1.W = worldTransform.M14; vertices[1].Column2.X = worldTransform.M21; vertices[1].Column2.Y = worldTransform.M22; vertices[1].Column2.Z = worldTransform.M23; vertices[1].Column2.W = worldTransform.M24; vertices[1].Column3.X = worldTransform.M31; vertices[1].Column3.Y = worldTransform.M32; vertices[1].Column3.Z = worldTransform.M33; vertices[1].Column3.W = worldTransform.M34; vertices[1].Column4.X = worldTransform.M41; vertices[1].Column4.Y = worldTransform.M42; vertices[1].Column4.Z = worldTransform.M43; vertices[1].Column4.W = worldTransform.M44; vertices[2].Column1.X = worldTransform.M11; vertices[2].Column1.Y = worldTransform.M12; vertices[2].Column1.Z = worldTransform.M13; vertices[2].Column1.W = worldTransform.M14; vertices[2].Column2.X = worldTransform.M21; vertices[2].Column2.Y = worldTransform.M22; vertices[2].Column2.Z = worldTransform.M23; vertices[2].Column2.W = worldTransform.M24; vertices[2].Column3.X = worldTransform.M31; vertices[2].Column3.Y = worldTransform.M32; vertices[2].Column3.Z = worldTransform.M33; vertices[2].Column3.W = worldTransform.M34; vertices[2].Column4.X = worldTransform.M41; vertices[2].Column4.Y = worldTransform.M42; vertices[2].Column4.Z = worldTransform.M43; vertices[2].Column4.W = worldTransform.M44; vertices[3].Column1.X = worldTransform.M11; vertices[3].Column1.Y = worldTransform.M12; vertices[3].Column1.Z = worldTransform.M13; vertices[3].Column1.W = worldTransform.M14; vertices[3].Column2.X = worldTransform.M21; vertices[3].Column2.Y = worldTransform.M22; vertices[3].Column2.Z = worldTransform.M23; vertices[3].Column2.W = worldTransform.M24; vertices[3].Column3.X = worldTransform.M31; vertices[3].Column3.Y = worldTransform.M32; vertices[3].Column3.Z = worldTransform.M33; vertices[3].Column3.W = worldTransform.M34; vertices[3].Column4.X = worldTransform.M41; vertices[3].Column4.Y = worldTransform.M42; vertices[3].Column4.Z = worldTransform.M43; vertices[3].Column4.W = worldTransform.M44; vertices[0].Normal = Normal; vertices[1].Normal = Normal; vertices[2].Normal = Normal; vertices[3].Normal = Normal; recreateWorld = false; } 
then create the world position in the shader (including scale):

 // [Rotation, Scale] World._11 = input.Column1.x * input.TexCoordDimension.z; // * Scale X World._12 = input.Column1.y * input.TexCoordDimension.z; World._13 = input.Column1.z * input.TexCoordDimension.z; World._14 = input.Column1.w; World._21 = input.Column2.x * input.TexCoordDimension.w; // * Scale Y World._22 = input.Column2.y * input.TexCoordDimension.w; World._23 = input.Column2.z * input.TexCoordDimension.w; World._24 = input.Column2.w; World._31 = input.Column3.x; World._32 = input.Column3.y; World._33 = input.Column3.z; World._34 = input.Column3.w; // [Translation] World._41 = input.Column4.x; World._42 = input.Column4.y; World._43 = input.Column4.z; World._44 = input.Column4.w; // [Transformation] // • Multiplying input.Position by World, then the result by ViewProjection is fast // • Concatenating World and ViewProjection matrices then multiplying input.Position by the result is slower input.Position = mul(input.Position, World); Output.Position = mul(input.Position, ViewProjection); 

the quadrangle positions do not scale correctly. This error can be shown with a model representation surrounded by the quadrangles:

Each of the 6 faces should be where the tan cube model faces are but the scaling doesn't work. How can this be fixed?

• What is your GameDev Story?

In 2019 we are celebrating 20 years of GameDev.net! Share your GameDev Story with us.

• 13
• 9
• 15
• 14
• 46
• Forum Statistics

• Total Topics
634060
• Total Posts
3015300
×