# (Effects) Parallax mapping and World transformation

Hi all,
I wrote a basic parallax effect that works good from all angles, but when I rotate the surface itself (ie change its world transform) - the illusion breaks.

Whats the right way to apply world transformations on the parallax effect so that no matter how the surface is rotated or scaled it will look good? Moving the surface looks OK btw, the only problem is with rotation.

``````// Vertex Shader
{

// Transform Position
//float4 viewPosition = mul(worldPosition, View);
//output.Position = mul(viewPosition, Projection);
output.Position = mul(input.Position, WorldViewProjection);

// Pass Depth
output.Depth.x = output.Position.z;
output.Depth.y = output.Position.w;

// Build TBN Matrix (Tangent, Bitangent, Normals)
output.TangentToWorld[0] = (mul(input.Tangent, World));
output.TangentToWorld[1] = (mul(input.BiTangent, World));
output.TangentToWorld[2] = (mul(input.Normal, World));

// calculate eye dir for displacement
if (EnableDisplacement == true)
{
float4 worldPosition = mul(input.Position, World);
float3x3 tbn = float3x3(input.Tangent, input.BiTangent, input.Normal);
output.EyeVector = normalize(mul(normalize(CameraPosition.xyz - worldPosition), tbn));
float3x3 rotation;
rotation[0] = normalize(World[0]);
rotation[1] = normalize(World[1]);
rotation[2] = normalize(World[2]);
output.EyeVector = mul(output.EyeVector, rotation);
}
else
{
output.EyeVector = 1;
}

// Pass UV and return
output.UV = TextureOffset + input.UV * TexturesTiling;
return output;
}
``````

and hereâ€™s the relevant part in the pixel shader:

``````	float height = tex2D(NormalSampler, UV).a * DisplacementScale - DisplacementBias;
UV += (input.EyeVector.xy * height);
``````

How do I fix it to work with rotation?
Thanks!

Pretty sure you need to cast your World to a float3x3 and normalize your vectors.

``````// Build TBN Matrix (Tangent, Bitangent, Normals)
float3x3 worldRot = (float3x3)World;
output.TangentToWorld[0] = normalize(mul(input.Tangent, worldRot));
output.TangentToWorld[1] = normalize(mul(input.BiTangent, worldRot));
output.TangentToWorld[2] = normalize(mul(input.Normal, worldRot));
``````

â€¦ though that may not be true because I have no idea what youâ€™re doing there with your eye vector. I would think itâ€™d make more sense to pass the camera-position in a uniform and just add the world-position as a vertex interpolator in the VS output than to interpolate the eye-vector.

Iâ€™ve never seen it done like you appear to be doing it, could you point to where you got that idea - Iâ€™m curious.

I really donâ€™t think you should need to rotate that eye-vector though. If your world-position is good and your camera-position is good, then your eye-vector will be good without the rotation.

Yes that eye thing doesnâ€™t look right.

When i was doing a couple normal mapping tutorials i had similar things in them about the eye vector.
Which were in fact wrong and i had to end up writing it out myself.

Seems to me that should be a dot operation to find intensity after a transform.
Then again im not entirely sure what is wrong in the posted image.
Or what the difference is in parallax mapping.

Dunno if this will help. Here is how i apply the world transform when i was working on normal mapping.

float3 NormalMap = tex2D(TextureNormalSampler, input.TexureCoordinateA).rgb;
NormalMap = normalize(NormalMap * 2.0 - 1.0);
float3 normal = input.Normal;
float3 tangent = input.Tangent;
float3x3 mat;
mat[0] = cross(normal, tangent); // right
mat[1] = tangent; // up
mat[2] = normal; // forward
NormalMap = mul(NormalMap, mat);
NormalMap = mul(NormalMap, World); // <<<<< world
NormalMap = normalize(NormalMap);

Here is one of my shaders were it was applied.

``````//_______________________________________________________________
// technique
//
// requires a tangent in the vertex data and 3 textures pixel , normalmap, depthmap
//
// ToDo fix
// I think the side opposite the light still can get some specular reflection when using normal maps.
//_______________________________________________________________

{
float4 Position : POSITION0;
float3 Normal : NORMAL0;
float2 TexureCoordinateA : TEXCOORD0;
float3 Tangent : NORMAL1;
};

{
float4 Position : SV_Position;//: SV_POSITION;
float4 Position3D : TEXCOORD4;
float2 TexureCoordinateA : TEXCOORD0;
float3 Normal: TEXCOORD1;
float3 Tangent : TEXCOORD2;
};

{

output.Position3D = mul(input.Position, World);
float4x4 vp = mul(View, Projection);
output.Position = mul(output.Position3D, vp);
output.Normal = input.Normal;
output.Tangent = input.Tangent;
output.TexureCoordinateA = input.TexureCoordinateA;
return output;
}

{
// Normal Map
float3 NormalMap = tex2D(TextureNormalSampler, input.TexureCoordinateA).rgb;
NormalMap.g = 1.0f - NormalMap.g; // flips the y. the program i used fliped the green.
NormalMap = normalize(NormalMap * 2.0 - 1.0);
float3 normal = input.Normal;
float3 tangent = input.Tangent;
float3x3 mat;
mat[0] = cross(normal, tangent); // right
mat[1] = tangent; // up
mat[2] = normal; // forward
NormalMap = mul(NormalMap, mat);
NormalMap = mul(NormalMap, World);
NormalMap = normalize(NormalMap); // we do this to ensure scaling wont break the normal.
// prep
float3 temp = WorldLightPosition - input.Position3D;
float distancePixelToLight = length(temp);
float3 surfaceToCamera = normalize(CameraPosition - input.Position3D);
float3 surfaceToLight = temp / distancePixelToLight; // cheapen the normalize. normalize(pixelToLight);
float3 lightToSurface = -surfaceToLight;
float shadowDepth = texCUBE(TextureDepthSampler, float4(lightToSurface, 0)).x;
float4 TexelColor = tex2D(TextureSamplerA, input.TexureCoordinateA) * (1.0f - LightVsTexelRatio) + (LightColor * LightVsTexelRatio); // LightVsTexelRatio == .5 is normal
float lightFalloff = (1.0f - saturate(distancePixelToLight / (IlluminationRange + 0.001f)));
float LightDistanceIntensity = saturate(sign((shadowDepth + .2f) - distancePixelToLight)) * lightFalloff; // if removal.
// lighting
float3 surfNom = NormalMap;
float diffuse = saturate((dot(lightToSurface, -surfNom) + DiffuseCresting) * (1.0f / (1.0f + DiffuseCresting))); // I've added over or underdraw to the diffuse.
diffuse *= diffuse;
float3 reflectionTheta = dot(surfaceToCamera, -reflect(surfaceToLight, surfNom));
float specular = saturate(reflectionTheta - SpecularSharpness) * (1.0f / (1.0f - SpecularSharpness)); // this is for sharpness i didn't want to use powers.
// finalize it.
float3 inverseAmbientControl = 1.0f - AmbientStrength;
float3 additiveDiffuse = diffuse * DiffuseStrength * LightDistanceIntensity * inverseAmbientControl;
float3 additiveSpecular = specular * SpecularStrength  * LightDistanceIntensity  * inverseAmbientControl;