Jump to content
  • Advertisement
Sign in to follow this  
domino1011

Problem with parallax mapping

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

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi all, I have stupid problem with implementing parallax mapping. I had implemented it (basing on my old dot3 shader) few days ago but there is something wrong and I have no idea what :|. I've got results of 'swimming' texture instead of parallax mapping effect - see http://www.dimmension3.spine.pl/temp/wrong_parallax.JPG . I used textures from some demo (humus I suppose), so I'm sure that height map is correct, my input data is also correct. Shaders are in Cg, all objects are assumed not to have world transformations, height map is on alpha channel of normal map. Vertex:
struct SVertexIn
{
  float4 position  : POSITION;
  float3 normal    : NORMAL;
  float2 texcoord0 : TEXCOORD0;
  float3 tangent   : TANGENT;
  float3 binormal  : BINORMAL;
};

struct SVertexOut
{
  float4 position  : POSITION;
  float2 texcoord0 : TEXCOORD0;
  float3 lightVect : TEXCOORD1;
  float3 viewVect  : TEXCOORD2;
};

SVertexOut vertexMain( SVertexIn IN, uniform float4x4 modelViewProjection, uniform float4x4 world, uniform float3 lightPos, uniform float3 cameraPos )
{
  SVertexOut OUT;

  float4 tempPosition = float4( IN.position.x, IN.position.y, IN.position.z, 1.0f );
  float3x3 world3x3 = (float3x3)world;

  OUT.position = mul( modelViewProjection, tempPosition );
  OUT.texcoord0 = IN.texcoord0;
  
  float4 worldPosition = mul(world, tempPosition);
  float3 worldNormal   = mul(world3x3, IN.normal);
  float3 worldTangent  = mul(world3x3, IN.tangent);
  float3 worldBinormal = mul(world3x3, IN.binormal);

  float3 lightVect = lightPos.xyz - worldPosition.xyz;
  float3 viewVect  = cameraPos.xyz - worldPosition.xyz;

  OUT.lightVect.x = dot(lightVect, worldTangent);
  OUT.lightVect.y = dot(lightVect, worldBinormal);
  OUT.lightVect.z = dot(lightVect, worldNormal);
  
  OUT.viewVect.x = dot(viewVect, worldTangent);
  OUT.viewVect.y = dot(viewVect, worldBinormal);
  OUT.viewVect.z = dot(viewVect, worldNormal);
  
  return OUT;
}
and fragment program:
struct SVertexOut
{
  float4 position  : POSITION;
  float2 texcoord0 : TEXCOORD0;
  float3 lightVect : TEXCOORD1;
  float3 viewVect  : TEXCOORD2;
};

float4 fragmentMain (SVertexOut IN, uniform sampler2D DiffuseMap, uniform sampler2D NormalMap) : COLOR
{
  float3 lightVect = normalize(IN.lightVect.xyz);
  float3 viewVect  = normalize(IN.viewVect.xyz);
 
  float  height = tex2D(NormalMap, IN.texcoord0.xy).w;
  float2 offset = (viewVect.xy * ((height * 2.0f) - 1.0f)) * 0.04f;

  float2 newTexCoord  = IN.texcoord0.xy + offset.xy;  
  float4 diffuseTexel  = tex2D(DiffuseMap, newTexCoord.xy);
  
  return diffuseTexel;
}
Any idea?

Share this post


Link to post
Share on other sites
Advertisement
Have you tried to output the same rendering without warping the texture coordinates? That would tell you if the problem is with the actual texcoords or not.

If that doesn't show any problems, could it be that you have to invert the y coordinate in the added modification of the texture coordinates? I'm not sure how CG uses texcoords, so I don't know for sure.

Also, does this effect seem to stay in the same position? For example, if it does stay in the same position when the object or viewer moves, then it must be something along the lines of a negated vector in TBN matrix or something like that.

I hope this helps!

Share this post


Link to post
Share on other sites
Quote:
Original post by Jason Z
Have you tried to output the same rendering without warping the texture coordinates? That would tell you if the problem is with the actual texcoords or not.

Yes, tex coords are ok (not mentioning y=1-y ;) ).

Quote:
Original post by Jason Z
If that doesn't show any problems, could it be that you have to invert the y coordinate in the added modification of the texture coordinates?

Hymm, this seems to help a little bit - now y=1-y. However the result is still far away from what it should be. It now looks like this:
http://www.dimmension3.spine.pl/temp/wrong_parallax_1.JPG
and this:
http://www.dimmension3.spine.pl/temp/wrong_parallax_2.JPG
and should look like this:
http://www.dimmension3.spine.pl/temp/proper_parallax.JPG
(this is screen from Humus demo)

Quote:
Original post by Jason Z
Also, does this effect seem to stay in the same position?

No, in fact it moves all the time when I move camera and it is really visible (the offset is too big or something) - interesting that the parts of image that should be higher moves faster. You can see this on screens _1, _2 - camera was moved only a little.

Share this post


Link to post
Share on other sites
Not sure, but I looked at my own shader code and saw that the viewVector for the parallax is inverted. In that case, keep your code exactly the same, but add this in your Vertex Program:

OUT.invertedViewVec = worldPos - cameraPos

Use that vector for the parallax part, instead of the non-inverted view vector.

Greetings,
Rick

Share this post


Link to post
Share on other sites
Quote:
Original post by spek
In that case, keep your code exactly the same, but add this in your Vertex Program:

OUT.invertedViewVec = worldPos - cameraPos

Unfortunately it doesn't help.

Share this post


Link to post
Share on other sites
It looks like it is actually doing what you want, the stretching is in the right place in the final image. You may have to tweak the offset limit and see what you can get out of it. Remember that regular parallax mapping isn't all that great at oblique angles, so as your geometry tapers off to the horizon you will lose the parallax effect.

Also, that image that you linked for the proper parallax effect - that looks like relief mapping more than regular parallax mapping. That image is probably generated using some form of raytracing in the pixel shader (you can check out my article on it HERE.

That screen shot also is shading based on the heightmap in the texture - which is not possible with regular parallax mapping either.

Share this post


Link to post
Share on other sites
Quote:
Original post by Jason Z
Remember that regular parallax mapping isn't all that great at oblique angles, so as your geometry tapers off to the horizon you will lose the parallax effect.

Yes I know that but still the texels are quite 'still'. In my version texels swimms while moving camera - first I was assuming that the offset is to big and change the 0.04 value, but event with very low bumpScale the effect is still visible (while there is almost no parallax effect). I have no idea what this could be.

Quote:
Original post by Jason Z
Also, that image that you linked for the proper parallax effect - that looks like relief mapping more than regular parallax mapping. That image is probably

No, it's parallax mapping - it's taken from humus site - www.humus.ca. I removed lines for shadows and it still gives me good parallax mapping. The code:

[Vertex shader]

float4x4 view_proj_matrix;
float3 lightPos;
float3 camPos;
float scale;
float texWorldSize;

struct VS_OUTPUT {
float4 Pos: POSITION;
float2 texCoord: TEXCOORD0;
float3 lightVec: TEXCOORD1;
float3 viewVec: TEXCOORD2;
float3 pos: TEXCOORD3;
float3 tangent: TEXCOORD4;
float3 binormal: TEXCOORD5;
};

VS_OUTPUT main(float4 pos: POSITION, float2 texCoord: TEXCOORD0,
float3 tangent: TEXCOORD1, float3 binormal: TEXCOORD2,
float3 normal: TEXCOORD3){
VS_OUTPUT Out;

Out.Pos = mul(view_proj_matrix, pos);
Out.texCoord = texCoord;

float3 lightVec = 0.0009 * (lightPos - pos);
Out.lightVec.x = dot(lightVec, tangent);
Out.lightVec.y = dot(lightVec, binormal);
Out.lightVec.z = dot(lightVec, normal);

float3 viewVec = camPos - pos;
Out.viewVec.x = dot(viewVec, tangent);
Out.viewVec.y = dot(viewVec, binormal);
Out.viewVec.z = dot(viewVec, normal);

Out.pos = scale * (pos - lightPos);
Out.tangent = texWorldSize * scale * tangent;
Out.binormal = texWorldSize * scale * binormal;

return Out;
}


[Fragment shader]

sampler Base: register(s0);
sampler Bump: register(s1);
sampler Shadow: register(s2);

float ambient;
float bias;

float4 main(float2 texCoord: TEXCOORD0, float3 lightVec: TEXCOORD1,
float3 viewVec: TEXCOORD2, float3 pos: TEXCOORD3,
float3 tangent: TEXCOORD4, float3 binormal: TEXCOORD5) : COLOR
{
float atten = 1 / (1 + dot(lightVec, lightVec));

lightVec = normalize(lightVec);
viewVec = normalize(viewVec);


float height = tex2D(Bump, texCoord).a;
float2 offset = viewVec.xy * (height * 2.0 - 1.0) * 0.04;
float2 newTexCoord = texCoord + offset;


float4 base = tex2D(Base, newTexCoord);
float3 bump = tex2D(Bump, newTexCoord) * 2 - 1;
bump = normalize(bump);

pos += (offset.x * tangent + offset.y * binormal);

float shadow = texCUBE(Shadow, pos) + bias;
shadow = (shadow * shadow > dot(pos, pos));


float diffuse = saturate(dot(lightVec, bump));

return base * (ambient + diffuse * atten * shadow);
}

Share this post


Link to post
Share on other sites
I solved it :). I had swapped X coordinate in viewVect parameter (that means that my camera is not working as it should). Thanks a lot for answers.

Share this post


Link to post
Share on other sites
@Domino

Wow.. does your code really work? I mean youre not using any 'ray casting' in your pixel shader, it looks like you just take one sample. Can you post screens? It looks like your method would be 100x faster than traditional methods, but does it really look the same?

Share this post


Link to post
Share on other sites
Quote:
Original post by ZealousEngine
Wow.. does your code really work? I mean youre not using any 'ray casting' in your pixel shader, it looks like you just take one sample. Can you post screens?

This is not my method ;) I have just implemented it as well as others. It looks cool if you remember about limitations (and do proper calculations for view vector :PP). I can post few screens but I suppose it's better to se it in action. Look at humus site - http://www.humus.ca/index.php?page=3D&ID=38 . You can disable self-shadowing and see only parallax mapping in action.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!