Context

To give some context to my question, I'm currently at the point of applying a generated lightmap to objects by cloning their material and setting UV scale and offset accordingly.

I've added a second set of UV transform uniforms in Uniform.hlsl:

- Code: Select all
`uniform float4 cUOffset;`

uniform float4 cVOffset;

uniform float4 cUOffsetLM;

uniform float4 cVOffsetLM;

uniform float4x3 cZone;

And added a transform function to be used in lightmap shaders (currently testing with LitSolid) in Transforms.hlsl:

- Code: Select all
`float2 GetTexCoord2(float2 iTexCoord)`

{

return float2(dot(iTexCoord, cUOffsetLM.xy) + cUOffsetLM.w, dot(iTexCoord, cVOffsetLM.xy) + cVOffsetLM.w);

};

In Material.h/cpp, I added methods similar to SetUVTransform but corresponding to the second set of UVs, moving the transform calculation into a separate method and calling it from both:

- Code: Select all
`void Material::SetUVTransform2(const Vector2& offset, float rotation, const Vector2& repeat)`

{

Matrix3x4 transform = CalculateUVTransform(offset, rotation, repeat);

SetShaderParameter("UOffsetLM", Vector4(transform.m00_, transform.m01_, transform.m02_, transform.m03_));

SetShaderParameter("VOffsetLM", Vector4(transform.m10_, transform.m11_, transform.m12_, transform.m13_));

}

Matrix3x4 Material::CalculateUVTransform(const Vector2& offset, float rotation, const Vector2& repeat)

{

Matrix3x4 transform(Matrix3x4::IDENTITY);

transform.m00_ = repeat.x_;

transform.m11_ = repeat.y_;

transform.m03_ = -0.5f * transform.m00_ + 0.5f;

transform.m13_ = -0.5f * transform.m11_ + 0.5f;

Matrix3x4 rotationMatrix(Matrix3x4::IDENTITY);

rotationMatrix.m00_ = Cos(rotation);

rotationMatrix.m01_ = Sin(rotation);

rotationMatrix.m10_ = -rotationMatrix.m01_;

rotationMatrix.m11_ = rotationMatrix.m00_;

rotationMatrix.m03_ = 0.5f - 0.5f * (rotationMatrix.m00_ + rotationMatrix.m01_);

rotationMatrix.m13_ = 0.5f - 0.5f * (rotationMatrix.m10_ + rotationMatrix.m11_);

transform = rotationMatrix * transform;

Matrix3x4 offsetMatrix = Matrix3x4::IDENTITY;

offsetMatrix.m03_ = offset.x_;

offsetMatrix.m13_ = offset.y_;

return offsetMatrix * transform;

}

The scale and offset are calculated in the lightmapper and applied to each model (where rect corresponds to where the model's LM is in the full LM atlas):

- Code: Select all
`IntRect& rect = rects[i];`

Vector2 scale((float)rect.Width() / atlasWidth, (float)rect.Height() / atlasHeight);

Vector2 offset((float)rect.left_ / atlasWidth, (float)rect.top_ / atlasHeight);

LMStaticModel* model = generators[i]->GetModel();

model->SetLightmapTexure(atlasTexture);

model->SetLightmapUVTransform(offset, 0, scale);

LMStaticModel::SetLightmapTexure and LMStaticModel::SetLightmapUVTransform just set these values on the cloned material.

The actual question, at last

This is my current lightmap atlas test case (automatically generated, but with numbers added for my sanity afterwards):

As an example mapping the second, smaller cube in the atlas I would expect an offset of approx (0.6, 0.0) and a scale/repeat of approx (0.3, 0.3). Setting these values manually on the material's U/VOffsetLM I get the expected result:

However setting them through SetUVTransform2 (which uses the same transform calculation as SetUVTransform), the calculated values are not what I would expect, and the visual result is way off:

So what is going on here? Is my understanding of UVs completely wrong (not impossible at all) or is that CalculateUVTransform wrong. It's been in Material.cpp as-is since before the Atomic fork, but I see Material::SetUVTransform isn't actually used anywhere so it's possible the calculation is wrong and it's never been noticed.