You may be right, I just threw that post together quickly before making lunch so it may not have the best wording.
Can you clarify what "mutation of a matrix" means technically?
I simply meant that the rotation is achieved by altering the rotation part of the mesh's world matrix. This might be obvious but I typed it out in the hopes of avoiding misinterpretations not the other way around.
Also, it's confusing as you mention "THE" output normal vector for a cube.
Let's rephrase it as vectors then.
I was refering to the fact that all normals (from the normal map) should on the whole be affected by the rotation such that they would align with the cube's orientation.
So that rotating it 90 degrees around the X axis would cause its front face's normals to go from facing the negative Z axis to the positive Y axis instead (generally speaking since the normal map isn't a solid blue (full Z normal with no other directional influence), but you get the point).
Edit: here I'm referring to the normals transformed into world space.
Are you using the word "upward" when you really mean "outward" (i.e., perpendicular to the face)?
Ah yes, I meant that the world space normal would be expected to be facing "upwards" (along the positive Y axis) for the top face of the cube.
The 4 faces meant that when rotating the cube, its final world normal tended to point in this fashion for 4 of the 6 faces when that face was the top one after rotation. I think the back face had a 0 normal (which doesn't make much sense) while one of the side faces when rotated upwards tended towards facing negative X.
This is all just based on visual observation when having the pixel shader return the world normal as a rgb colour by the way.
But yes, in conclusion I guess that the normals weren't facing outward as intended for these faces in that particular rotation. They did however look sensible with other (or no) world matrix rotation.
Because you're calculating the vertex normal/tangent/binormal in the vertex shader, the pixel shader gets as input the linearly interpolated normal/tangent/binormal vectors across the face. Is that what you want?
They're essentially just passed through from the vertex data of the mesh. This was done because I figured I'd rather pay for some more memory usage than to have to recalculate vectors that will never change on each render in the shader.
Without any further information on your program, WRT to the specular highlights: your code is incorrect, the data you're using to calculate the specular contribution is incorrect, or both.
Well my code is the suspect as of now anyway, unless this data is incorrect with regards to normals / tangents / binormals for a cube?
// Front face
vert.SetMember<XMFLOAT3>("POSITION", 0, XMFLOAT3(-xhs, -yhs, -zhs));
vert.SetMember<DWORD> ("COLOR", 0, 0xffffffff);
vert.SetMember<XMFLOAT2>("TEXCOORD", 0, XMFLOAT2(0.0f, 1.0f));
vert.SetMember<XMFLOAT3>("NORMAL", 0, XMFLOAT3(0.0f, 0.0f, 1.0f));
vert.SetMember<XMFLOAT3>("TANGENT", 0, XMFLOAT3(-1.0f, 0.0f, 0.0f));
vert.SetMember<XMFLOAT3>("BINORMAL", 0, XMFLOAT3(0.0f, 1.0f, 0.0f));
vert.CopyData(vbuf);
vert.SetMember<XMFLOAT3>("POSITION", 0, XMFLOAT3(-xhs, yhs, -zhs));
vert.SetMember<DWORD> ("COLOR", 0, 0xffffffff);
vert.SetMember<XMFLOAT2>("TEXCOORD", 0, XMFLOAT2(0.0f, 0.0f));
vert.SetMember<XMFLOAT3>("NORMAL", 0, XMFLOAT3(0.0f, 0.0f, 1.0f));
vert.SetMember<XMFLOAT3>("TANGENT", 0, XMFLOAT3(-1.0f, 0.0f, 0.0f));
vert.SetMember<XMFLOAT3>("BINORMAL", 0, XMFLOAT3(0.0f, 1.0f, 0.0f));
vert.CopyData(vbuf + (vertOffset += vertSize));
vert.SetMember<XMFLOAT3>("POSITION", 0, XMFLOAT3(xhs, yhs, -zhs));
vert.SetMember<DWORD> ("COLOR", 0, 0xffffffff);
vert.SetMember<XMFLOAT2>("TEXCOORD", 0, XMFLOAT2(1.0f, 0.0f));
vert.SetMember<XMFLOAT3>("NORMAL", 0, XMFLOAT3(0.0f, 0.0f, 1.0f));
vert.SetMember<XMFLOAT3>("TANGENT", 0, XMFLOAT3(-1.0f, 0.0f, 0.0f));
vert.SetMember<XMFLOAT3>("BINORMAL", 0, XMFLOAT3(0.0f, 1.0f, 0.0f));
vert.CopyData(vbuf + (vertOffset += vertSize));
vert.SetMember<XMFLOAT3>("POSITION", 0, XMFLOAT3(xhs, -yhs, -zhs));
vert.SetMember<DWORD> ("COLOR", 0, 0xffffffff);
vert.SetMember<XMFLOAT2>("TEXCOORD", 0, XMFLOAT2(1.0f, 1.0f));
vert.SetMember<XMFLOAT3>("NORMAL", 0, XMFLOAT3(0.0f, 0.0f, 1.0f));
vert.SetMember<XMFLOAT3>("TANGENT", 0, XMFLOAT3(-1.0f, 0.0f, 0.0f));
vert.SetMember<XMFLOAT3>("BINORMAL", 0, XMFLOAT3(0.0f, 1.0f, 0.0f));
vert.CopyData(vbuf + (vertOffset += vertSize));
// Back face
vert.SetMember<XMFLOAT3>("POSITION", 0, XMFLOAT3(-xhs, -yhs, zhs));
vert.SetMember<DWORD> ("COLOR", 0, 0xffffffff);
vert.SetMember<XMFLOAT2>("TEXCOORD", 0, XMFLOAT2(1.0f, 0.0f));
vert.SetMember<XMFLOAT3>("NORMAL", 0, XMFLOAT3(0.0f, 0.0f, -1.0f));
vert.SetMember<XMFLOAT3>("TANGENT", 0, XMFLOAT3(1.0f, 0.0f, 0.0f));
vert.SetMember<XMFLOAT3>("BINORMAL", 0, XMFLOAT3(0.0f, 1.0f, 0.0f));
vert.CopyData(vbuf + (vertOffset += vertSize));
vert.SetMember<XMFLOAT3>("POSITION", 0, XMFLOAT3(xhs, -yhs, zhs));
vert.SetMember<DWORD> ("COLOR", 0, 0xffffffff);
vert.SetMember<XMFLOAT2>("TEXCOORD", 0, XMFLOAT2(0.0f, 0.0f));
vert.SetMember<XMFLOAT3>("NORMAL", 0, XMFLOAT3(0.0f, 0.0f, -1.0f));
vert.SetMember<XMFLOAT3>("TANGENT", 0, XMFLOAT3(1.0f, 0.0f, 0.0f));
vert.SetMember<XMFLOAT3>("BINORMAL", 0, XMFLOAT3(0.0f, 1.0f, 0.0f));
vert.CopyData(vbuf + (vertOffset += vertSize));
vert.SetMember<XMFLOAT3>("POSITION", 0, XMFLOAT3(xhs, yhs, zhs));
vert.SetMember<DWORD> ("COLOR", 0, 0xffffffff);
vert.SetMember<XMFLOAT2>("TEXCOORD", 0, XMFLOAT2(0.0f, 1.0f));
vert.SetMember<XMFLOAT3>("NORMAL", 0, XMFLOAT3(0.0f, 0.0f, -1.0f));
vert.SetMember<XMFLOAT3>("TANGENT", 0, XMFLOAT3(1.0f, 0.0f, 0.0f));
vert.SetMember<XMFLOAT3>("BINORMAL", 0, XMFLOAT3(0.0f, 1.0f, 0.0f));
vert.CopyData(vbuf + (vertOffset += vertSize));
vert.SetMember<XMFLOAT3>("POSITION", 0, XMFLOAT3(-xhs, yhs, zhs));
vert.SetMember<DWORD> ("COLOR", 0, 0xffffffff);
vert.SetMember<XMFLOAT2>("TEXCOORD", 0, XMFLOAT2(1.0f, 1.0f));
vert.SetMember<XMFLOAT3>("NORMAL", 0, XMFLOAT3(0.0f, 0.0f, -1.0f));
vert.SetMember<XMFLOAT3>("TANGENT", 0, XMFLOAT3(1.0f, 0.0f, 0.0f));
vert.SetMember<XMFLOAT3>("BINORMAL", 0, XMFLOAT3(0.0f, 1.0f, 0.0f));
vert.CopyData(vbuf + (vertOffset += vertSize));
// Top face
vert.SetMember<XMFLOAT3>("POSITION", 0, XMFLOAT3(-xhs, yhs, zhs));
vert.SetMember<DWORD> ("COLOR", 0, 0xffffffff);
vert.SetMember<XMFLOAT2>("TEXCOORD", 0, XMFLOAT2(0.0f, 1.0f));
vert.SetMember<XMFLOAT3>("NORMAL", 0, XMFLOAT3(0.0f, 1.0f, 0.0f));
vert.SetMember<XMFLOAT3>("TANGENT", 0, XMFLOAT3(1.0f, 0.0f, 0.0f));
vert.SetMember<XMFLOAT3>("BINORMAL", 0, XMFLOAT3(0.0f, 0.0f, 1.0f));
vert.CopyData(vbuf + (vertOffset += vertSize));
vert.SetMember<XMFLOAT3>("POSITION", 0, XMFLOAT3(xhs, yhs, zhs));
vert.SetMember<DWORD> ("COLOR", 0, 0xffffffff);
vert.SetMember<XMFLOAT2>("TEXCOORD", 0, XMFLOAT2(0.0f, 0.0f));
vert.SetMember<XMFLOAT3>("NORMAL", 0, XMFLOAT3(0.0f, 1.0f, 0.0f));
vert.SetMember<XMFLOAT3>("TANGENT", 0, XMFLOAT3(1.0f, 0.0f, 0.0f));
vert.SetMember<XMFLOAT3>("BINORMAL", 0, XMFLOAT3(0.0f, 0.0f, 1.0f));
vert.CopyData(vbuf + (vertOffset += vertSize));
vert.SetMember<XMFLOAT3>("POSITION", 0, XMFLOAT3(xhs, yhs, -zhs));
vert.SetMember<DWORD> ("COLOR", 0, 0xffffffff);
vert.SetMember<XMFLOAT2>("TEXCOORD", 0, XMFLOAT2(1.0f, 0.0f));
vert.SetMember<XMFLOAT3>("NORMAL", 0, XMFLOAT3(0.0f, 1.0f, 0.0f));
vert.SetMember<XMFLOAT3>("TANGENT", 0, XMFLOAT3(1.0f, 0.0f, 0.0f));
vert.SetMember<XMFLOAT3>("BINORMAL", 0, XMFLOAT3(0.0f, 0.0f, 1.0f));
vert.CopyData(vbuf + (vertOffset += vertSize));
vert.SetMember<XMFLOAT3>("POSITION", 0, XMFLOAT3(-xhs, yhs, -zhs));
vert.SetMember<DWORD> ("COLOR", 0, 0xffffffff);
vert.SetMember<XMFLOAT2>("TEXCOORD", 0, XMFLOAT2(1.0f, 1.0f));
vert.SetMember<XMFLOAT3>("NORMAL", 0, XMFLOAT3(0.0f, 1.0f, 0.0f));
vert.SetMember<XMFLOAT3>("TANGENT", 0, XMFLOAT3(1.0f, 0.0f, 0.0f));
vert.SetMember<XMFLOAT3>("BINORMAL", 0, XMFLOAT3(0.0f, 0.0f, 1.0f));
vert.CopyData(vbuf + (vertOffset += vertSize));
// Bottom face
vert.SetMember<XMFLOAT3>("POSITION", 0, XMFLOAT3(-xhs, -yhs, -zhs));
vert.SetMember<DWORD> ("COLOR", 0, 0xffffffff);
vert.SetMember<XMFLOAT2>("TEXCOORD", 0, XMFLOAT2(0.0f, 1.0f));
vert.SetMember<XMFLOAT3>("NORMAL", 0, XMFLOAT3(0.0f, -1.0f, 0.0f));
vert.SetMember<XMFLOAT3>("TANGENT", 0, XMFLOAT3(1.0f, 0.0f, 0.0f));
vert.SetMember<XMFLOAT3>("BINORMAL", 0, XMFLOAT3(0.0f, 0.0f, -1.0f));
vert.CopyData(vbuf + (vertOffset += vertSize));
vert.SetMember<XMFLOAT3>("POSITION", 0, XMFLOAT3(xhs, -yhs, -zhs));
vert.SetMember<DWORD> ("COLOR", 0, 0xffffffff);
vert.SetMember<XMFLOAT2>("TEXCOORD", 0, XMFLOAT2(0.0f, 0.0f));
vert.SetMember<XMFLOAT3>("NORMAL", 0, XMFLOAT3(0.0f, -1.0f, 0.0f));
vert.SetMember<XMFLOAT3>("TANGENT", 0, XMFLOAT3(1.0f, 0.0f, 0.0f));
vert.SetMember<XMFLOAT3>("BINORMAL", 0, XMFLOAT3(0.0f, 0.0f, -1.0f));
vert.CopyData(vbuf + (vertOffset += vertSize));
vert.SetMember<XMFLOAT3>("POSITION", 0, XMFLOAT3(xhs, -yhs, zhs));
vert.SetMember<DWORD> ("COLOR", 0, 0xffffffff);
vert.SetMember<XMFLOAT2>("TEXCOORD", 0, XMFLOAT2(1.0f, 0.0f));
vert.SetMember<XMFLOAT3>("NORMAL", 0, XMFLOAT3(0.0f, -1.0f, 0.0f));
vert.SetMember<XMFLOAT3>("TANGENT", 0, XMFLOAT3(1.0f, 0.0f, 0.0f));
vert.SetMember<XMFLOAT3>("BINORMAL", 0, XMFLOAT3(0.0f, 0.0f, -1.0f));
vert.CopyData(vbuf + (vertOffset += vertSize));
vert.SetMember<XMFLOAT3>("POSITION", 0, XMFLOAT3(-xhs, -yhs, zhs));
vert.SetMember<DWORD> ("COLOR", 0, 0xffffffff);
vert.SetMember<XMFLOAT2>("TEXCOORD", 0, XMFLOAT2(1.0f, 1.0f));
vert.SetMember<XMFLOAT3>("NORMAL", 0, XMFLOAT3(0.0f, -1.0f, 0.0f));
vert.SetMember<XMFLOAT3>("TANGENT", 0, XMFLOAT3(1.0f, 0.0f, 0.0f));
vert.SetMember<XMFLOAT3>("BINORMAL", 0, XMFLOAT3(0.0f, 0.0f, -1.0f));
vert.CopyData(vbuf + (vertOffset += vertSize));
// Left face
vert.SetMember<XMFLOAT3>("POSITION", 0, XMFLOAT3(-xhs, -yhs, zhs));
vert.SetMember<DWORD> ("COLOR", 0, 0xffffffff);
vert.SetMember<XMFLOAT2>("TEXCOORD", 0, XMFLOAT2(0.0f, 1.0f));
vert.SetMember<XMFLOAT3>("NORMAL", 0, XMFLOAT3(-1.0f, 0.0f, 0.0f));
vert.SetMember<XMFLOAT3>("TANGENT", 0, XMFLOAT3(0.0f, 0.0f, -1.0f));
vert.SetMember<XMFLOAT3>("BINORMAL", 0, XMFLOAT3(0.0f, 1.0f, 0.0f));
vert.CopyData(vbuf + (vertOffset += vertSize));
vert.SetMember<XMFLOAT3>("POSITION", 0, XMFLOAT3(-xhs, yhs, zhs));
vert.SetMember<DWORD> ("COLOR", 0, 0xffffffff);
vert.SetMember<XMFLOAT2>("TEXCOORD", 0, XMFLOAT2(0.0f, 0.0f));
vert.SetMember<XMFLOAT3>("NORMAL", 0, XMFLOAT3(-1.0f, 0.0f, 0.0f));
vert.SetMember<XMFLOAT3>("TANGENT", 0, XMFLOAT3(0.0f, 0.0f, -1.0f));
vert.SetMember<XMFLOAT3>("BINORMAL", 0, XMFLOAT3(0.0f, 1.0f, 0.0f));
vert.CopyData(vbuf + (vertOffset += vertSize));
vert.SetMember<XMFLOAT3>("POSITION", 0, XMFLOAT3(-xhs, yhs, -zhs));
vert.SetMember<DWORD> ("COLOR", 0, 0xffffffff);
vert.SetMember<XMFLOAT2>("TEXCOORD", 0, XMFLOAT2(1.0f, 0.0f));
vert.SetMember<XMFLOAT3>("NORMAL", 0, XMFLOAT3(-1.0f, 0.0f, 0.0f));
vert.SetMember<XMFLOAT3>("TANGENT", 0, XMFLOAT3(0.0f, 0.0f, -1.0f));
vert.SetMember<XMFLOAT3>("BINORMAL", 0, XMFLOAT3(0.0f, 1.0f, 0.0f));
vert.CopyData(vbuf + (vertOffset += vertSize));
vert.SetMember<XMFLOAT3>("POSITION", 0, XMFLOAT3(-xhs, -yhs, -zhs));
vert.SetMember<DWORD> ("COLOR", 0, 0xffffffff);
vert.SetMember<XMFLOAT2>("TEXCOORD", 0, XMFLOAT2(1.0f, 1.0f));
vert.SetMember<XMFLOAT3>("NORMAL", 0, XMFLOAT3(-1.0f, 0.0f, 0.0f));
vert.SetMember<XMFLOAT3>("TANGENT", 0, XMFLOAT3(0.0f, 0.0f, -1.0f));
vert.SetMember<XMFLOAT3>("BINORMAL", 0, XMFLOAT3(0.0f, 1.0f, 0.0f));
vert.CopyData(vbuf + (vertOffset += vertSize));
// Right face
vert.SetMember<XMFLOAT3>("POSITION", 0, XMFLOAT3(xhs, -yhs, -zhs));
vert.SetMember<DWORD> ("COLOR", 0, 0xffffffff);
vert.SetMember<XMFLOAT2>("TEXCOORD", 0, XMFLOAT2(0.0f, 1.0f));
vert.SetMember<XMFLOAT3>("NORMAL", 0, XMFLOAT3(1.0f, 0.0f, 0.0f));
vert.SetMember<XMFLOAT3>("TANGENT", 0, XMFLOAT3(0.0f, 0.0f, 1.0f));
vert.SetMember<XMFLOAT3>("BINORMAL", 0, XMFLOAT3(0.0f, 1.0f, 0.0f));
vert.CopyData(vbuf + (vertOffset += vertSize));
vert.SetMember<XMFLOAT3>("POSITION", 0, XMFLOAT3(xhs, yhs, -zhs));
vert.SetMember<DWORD> ("COLOR", 0, 0xffffffff);
vert.SetMember<XMFLOAT2>("TEXCOORD", 0, XMFLOAT2(0.0f, 0.0f));
vert.SetMember<XMFLOAT3>("NORMAL", 0, XMFLOAT3(1.0f, 0.0f, 0.0f));
vert.SetMember<XMFLOAT3>("TANGENT", 0, XMFLOAT3(0.0f, 0.0f, 1.0f));
vert.SetMember<XMFLOAT3>("BINORMAL", 0, XMFLOAT3(0.0f, 1.0f, 0.0f));
vert.CopyData(vbuf + (vertOffset += vertSize));
vert.SetMember<XMFLOAT3>("POSITION", 0, XMFLOAT3(xhs, yhs, zhs));
vert.SetMember<DWORD> ("COLOR", 0, 0xffffffff);
vert.SetMember<XMFLOAT2>("TEXCOORD", 0, XMFLOAT2(1.0f, 0.0f));
vert.SetMember<XMFLOAT3>("NORMAL", 0, XMFLOAT3(1.0f, 0.0f, 0.0f));
vert.SetMember<XMFLOAT3>("TANGENT", 0, XMFLOAT3(0.0f, 0.0f, 1.0f));
vert.SetMember<XMFLOAT3>("BINORMAL", 0, XMFLOAT3(0.0f, 1.0f, 0.0f));
vert.CopyData(vbuf + (vertOffset += vertSize));
vert.SetMember<XMFLOAT3>("POSITION", 0, XMFLOAT3(xhs, -yhs, zhs));
vert.SetMember<DWORD> ("COLOR", 0, 0xffffffff);
vert.SetMember<XMFLOAT2>("TEXCOORD", 0, XMFLOAT2(1.0f, 1.0f));
vert.SetMember<XMFLOAT3>("NORMAL", 0, XMFLOAT3(1.0f, 0.0f, 0.0f));
vert.SetMember<XMFLOAT3>("TANGENT", 0, XMFLOAT3(0.0f, 0.0f, 1.0f));
vert.SetMember<XMFLOAT3>("BINORMAL", 0, XMFLOAT3(0.0f, 1.0f, 0.0f));
vert.CopyData(vbuf + (vertOffset += vertSize));
// Index buffer into the vertices above
DWORD ibuf[] = {
/* Front face */
0, 1, 2,
0, 2, 3,
/* Back face */
4, 5, 6,
4, 6, 7,
/* Top face */
8, 9, 10,
8, 10, 11,
/* Bottom face */
12, 13, 14,
12, 14, 15,
/* Left face */
16, 17, 18,
16, 18, 19,
/* Right face */
20, 21, 22,
20, 22, 23
};
Basically my main question was whether my attempt at building a tangent to world space matrix was incorrect since that's what I'm guessing is wrong.