DX11 - HLSL - Parallax Mapping

Started by
12 comments, last by Migi0027 10 years, 11 months ago

Now I've been trying to implement parallax mapping for a short while now, and I'm not quite sure if the result is right. The result (look at the plane):

1q04cp.png

Now there I have shown you the result of Diffuse, Parallax, Parallax with Normal Mapping rendering, and a blank space of course!

Now to some code:

(Relevant) Vertex Shader:


float binormal = cross(tangent,normal);

float3x3 tbnmatrix = transpose(float3x3(tangent,binormal,normal));
output.toeyetangent = mul((eyepos - output.position),tbnmatrix);

(Relevant) Pixel Shader:


float height = parallaxmap.Sample(ss, texCoord);

float3 toeyetangent = normalize(input.toeyetangent);
float2 offset = toeyetangent.xy*height*0.04f;

texCoord += offset;

And If you wan't, the full shader:


cbuffer ConstantObjectBuffer : register (b0)
{
	matrix worldMatrix; 
	matrix viewMatrix; 
	matrix projectionMatrix; 

	float4x4 rotation;
	float4 ambientcol;
	float texture_repeat;
	float3 tr_sace;
	float4 clipColor;
	float3 _instancePos;
	float inSPACE;
};

cbuffer ConstantFrameBuffer : register (b1)
{
	float4 lightvec;
	float4 lightcol;
	float time;
	float _wireframe;
	float2 wffspace;

	matrix tmat;
	matrix svp;
};

cbuffer UberData : register (b2)
{
	float _diffuse;
	float _texture;
	float _opacityEnable;
	float _directionall;
	float _bumpmap;
	float _fog;
	float _wind;
	float _pixelDisorter;
	float _disorterAmount;
	float _specular;
	float _doClip;
	float _terrain;
	float _instance;
	float _selected;
	float _windspeed;
	float _windamount;
	float _particle;
	float _shadows;
	float _envreflect;
	float _invDoClip;
	float _parallaxMapping;
	float3 ssspace;
};

cbuffer ConstantMatrixBuffer : register (b3)
{
	float4x4 world;
	float4x4 view;
	float4x4 projection;
	float4 eyepos;
	float3 cforward;
	float _space;
};

cbuffer ConstantFogBuffer : register (b4)
{
	float FogStart;
	float FogEnd;
	float2 __space;
	float3 FogColor;
	float __space2;
};

cbuffer ConstantSpecularBuffer : register (b5)
{
	float specularPower;
	float3 ____space;
    float4 specularColor;
};

cbuffer ConstantTerrainBuffer : register (b6)
{
	float t_nchannels;
	float3 t_space;
	float4 slopeActivation;
};

cbuffer ConstantParticleBuffer : register (b7)
{
	float particle_pastTime;
	float particle_lifeTime;
	float particle_fallOff;
	float _cpbspace;
};

cbuffer ShadowBuffer : register (b8)
{
	matrix sWorld;
	matrix lightViewMatrix;
	matrix lightProjectionMatrix;
	float3 sLightPos;
}

// Meshes
Texture2D txt : register(t0); // base
Texture2D txt2 : register(t1); // bump
Texture2D parallaxmap : register(t12); // parallax
Texture2D txt3 : register(t2); // opacity
TextureCube env : register (t11);

//Terrain
Texture2D terrChannel1 : register(t3);
Texture2D terrChannel2 : register(t4);
Texture2D terrChannel3 : register(t5);
Texture2D terrChannel4 : register(t6);

Texture2D gBuffer_Normals : register(t7);
Texture2D gBuffer_Position : register(t8);
Texture2D gBuffer_Random : register(t9);
Texture2D gBuffer_Shadows : register(t10);

sampler shadowss = 
sampler_state
{
    Texture = <gBuffer_Shadows>;
    MipFilter = LINEAR;
    MinFilter = LINEAR;
    MagFilter = LINEAR;
};

SamplerState ss;

sampler NormalMapSampler = sampler_state
{
   Texture = <txt2>;
   MinFilter = Linear;
   MagFilter = Linear;
   MipFilter = Linear;   
   AddressU  = Clamp;
   AddressV  = Clamp;
};

struct VOut
{
    float4 worldPos : POSITION; 
	float3 normal : NORMAL; 
	float3 Specnormal : NORMAL2; 
    float2 texcoord : TEXCOORD; 
	float4 tangent : TANGENT; 
    float4 position : SV_POSITION;
    float3 WorldNormal : TEXCOORD2;
	float Depth : FOG;
    float4 color : COLOR;
    float3 View : VIEWD;
	float4 lightViewPosition : TEXCOORD5;
	float3 L : TEXCOORD6;
	float3 N : TEXCOORD7;
	float3 lightPos : TEXCOORD8;
	float3 toeyetangent : EYET;
};

VOut VShader(float4 position : POSITION, float4 normal : NORMAL, float2 texcoord : TEXCOORD, float4 tangent : TANGENT, float3 instancePosition : INSTANCEPOS)
{
    VOut output;

	if (_wind == 1)
	{
		position.x += sin(time+position.x*10);
		position.y += cos(time+position.y*10);
		position.z += sin(time+position.y*10);

		// Parameters controlling the wind effect.
		float3 WindDirection = float3(1, 0, 0);
		float WindWaveSize = 0.1;
		float WindRandomness = 1;
		float WindSpeed = _windspeed;
		float WindAmount = _windamount;

		// Work out how this vertex should be affected by the wind effect.
		float waveOffset = dot(position, WindDirection) * WindWaveSize;
    
		waveOffset += 2 * WindRandomness;
    
		// Wind makes things wave back and forth in a sine wave pattern.
		float wind = sin(time * WindSpeed + waveOffset) * WindAmount;
    
		// But it should only affect the top two vertices of the billboard!
		wind *= (1 - texcoord.y);
    
		position += float4(WindDirection * wind, position.w);
	}

	if (_instance == 1)
	{
		position.x += instancePosition.x;
		position.y += instancePosition.y;
		position.z += instancePosition.z;
	}

	position.w = 1.0f;

	// Calculate the position of the vertex against the world, view, and projection matrices.
    output.position = mul(position, worldMatrix);
    output.position = mul(output.position, viewMatrix);
    output.position = mul(output.position, projectionMatrix);

    output.worldPos = mul(position, worldMatrix);
	output.WorldNormal = normalize(mul(normal, worldMatrix));

	output.color = float4(0,0,0,1);

    // set the ambient light
	if (_diffuse == 1)
	{
		output.color += ambientcol;
	}

	if (_texture == 1)
	{
		output.texcoord = texcoord;
	}

	// Stuff for dir and bump
	if (_directionall == 1)
	{
		float4 norm = normalize(mul(rotation, normal));
		float diffusebrightness = saturate(dot(norm, lightvec));
		output.color += lightcol * diffusebrightness;
	}

	if (_bumpmap == 1)
	{
		output.normal = normal;
		output.tangent = tangent;
	}

	float3 Cnormal = normalize(mul(normal, worldMatrix));
	output.Specnormal = Cnormal;
	output.View = normalize(eyepos - output.worldPos);

	// SHADOW
    
	if (_shadows == 1)
	{
		// Calculate the position of the vertice as viewed by the light source.
		output.lightViewPosition = mul(position, worldMatrix);
		output.lightViewPosition = mul(output.lightViewPosition, lightViewMatrix);
		output.lightViewPosition = mul(output.lightViewPosition, lightProjectionMatrix);
    
		// Calculate the normal vector against the world matrix only.
		output.normal = mul(normal, (float3x3)worldMatrix);
	
		// Normalize the normal vector.
		output.normal = normalize(output.normal);

		// Calculate the position of the vertex in the world.
		float4 worldPosition = mul(position, worldMatrix);

		// Determine the light position based on the position of the light and the position of the vertex in the world.
		output.lightPos = sLightPos - worldPosition.xyz;

		// Normalize the light position vector.
		output.lightPos = normalize(output.lightPos);
	}
	// END

	if (_parallaxMapping == 1)
	{
		float binormal = cross(tangent,normal);

		float3x3 tbnmatrix = transpose(float3x3(tangent,binormal,normal));
		output.toeyetangent = mul((eyepos - output.position),tbnmatrix);
	}

	// Final stuff
	output.Depth = output.position.z;
	output.color.a = 1;

    return output;
}

// SSAO Operations
float3 getPosition(in float2 uv)
{
	return gBuffer_Position.Sample(ss, uv).xyz;
}

float3 getNormal(in float2 uv)
{
	return normalize(gBuffer_Normals.Sample(ss, uv).xyz * 2.0f - 1.0f);
}

float2 getRandom(in float2 uv)
{
	return normalize(gBuffer_Random.Sample(ss, float2(800,600) * uv / float2(64,64)).xy * 2.0f - 1.0f);
}

float doAmbientOcclusion(in float2 tcoord,in float2 uv, in float3 p, in float3 cnorm)
{
	float3 diff = getPosition(tcoord + uv) - p;
	const float3 v = normalize(diff);
	const float d = length(diff)*2; //scale
	return max(0.0,dot(cnorm,v)-5)*(1.0/(1.0+d))*1; // Intensity
}

float4 PShader(VOut input) : SV_TARGET
{
	// If it's wireframe, skip everything else
	if (_wireframe == 1)
	{
		return float4(1,1,1,1); // we may have to do something with this, not sure yet...
	}

	float4 color = input.color;

	float4 spec = float4(0,0,0, 1);
	float4 tex = float4(0,0,0, 1);
	float4 bump = float4(0,0,0, 1);

	input.texcoord.xy *= texture_repeat;
	float2 texCoord = input.texcoord;

	if (_texture == 1)
	{
		if (_parallaxMapping == 1)
		{
			float height = parallaxmap.Sample(ss, texCoord);

			float3 toeyetangent = normalize(input.toeyetangent);
			float2 offset = toeyetangent.xy*height*0.04f;

			texCoord += offset;
		}

		if (_pixelDisorter == 1)
		{
			// Distortion factor
			float NoiseX = _disorterAmount * (time/1000) * sin(input.texcoord.x * input.texcoord.y+time/1000);
			NoiseX=fmod(NoiseX,8) * fmod(NoiseX,4); 

			// Use our distortion factor to compute how much it will affect each
			// texture coordinate
			float DistortX = fmod(NoiseX,5);
			float DistortY = fmod(NoiseX,5+0.002);
 
			// Create our new texture coordinate based on our distortion factor
			texCoord = float2(DistortX,DistortY);
		}

		if (!_bumpmap)
		{
			float4 txtColor = txt.Sample(ss, texCoord);
			color *= txtColor;
		}
		else if (_bumpmap == 1)
		{
			float4 Color = txt.Sample(ss, texCoord);
			float3 N = (2.0 * (txt2.Sample(ss, texCoord))) - 1.0;
			// diffuse
			float D = saturate(dot(N, lightvec));
			// reflection
		    float3 R = normalize(2 * D * N - lightvec);
			// specular
			float S = pow(saturate(dot(R, texCoord*input.tangent)), 2);
			const float4 Ambient = float4(0.3, 0.3, 0.3, 1.0);

			color *= Color*Ambient + Color * D + Color*S; 
		}

		if (_doClip == 1)
		{
			if (_invDoClip == 1)
			{
				color.a = 1.0f - saturate(txt.Sample(ss, texCoord));
			}
			else 
			{
				color.a = saturate(txt.Sample(ss, texCoord));
			}
		}
	}

	if (_specular == 1)
	{
		float4 normal = float4(input.Specnormal, 1.0);
		float4 diffuse = saturate(dot(-lightvec,normal));
		float4 reflect = normalize(2*diffuse*normal-lightvec);
		float4 specular = pow(saturate(dot(reflect,input.View)),15);
 
		color += float4(1,1,1,1)*specular;
	}

	if (_opacityEnable == 1)
	{
		float4 opacity = saturate(txt3.Sample(ss, texCoord));

		color.a *= opacity;
	}

	if (_terrain == 1)
	{
		float4 grassColor;
		float4 slopeColor;
		float4 rockColor;
		float slope;
		float blendAmount;
		float4 textureColor;

		grassColor = terrChannel1.Sample(ss, input.texcoord);

		slopeColor = terrChannel2.Sample(ss, input.texcoord);

		rockColor  = terrChannel3.Sample(ss, input.texcoord);

		// Calculate the slope of this point.
		slope = 1.0f - input.normal.y;

		// Determine which texture to use based on height.
		if(slope < 0.2)
		{
			blendAmount = slope / 0.2;
			textureColor = lerp(grassColor, slopeColor, blendAmount);
		}
	
		if((slope < 0.7) && (slope >= 0.2))
		{
			blendAmount = (slope - 0.2) * (1.0f / (0.7 - 0.2));
			textureColor = lerp(slopeColor, rockColor, blendAmount);
		}

		if(slope >= 0.7) 
		{
			textureColor = rockColor;
		}

		color *= textureColor;
	}

	if (_particle == 1)
	{
		float range = particle_lifeTime-particle_fallOff;

		if (particle_pastTime > range)
		{
			color.a *= saturate(1.0f - (1.0f/( (particle_lifeTime-(particle_lifeTime - particle_fallOff)) / (particle_pastTime-(particle_lifeTime - particle_fallOff)) )));
			
			color.a -= 1.0f/(distance(eyepos.xyz, input.Depth)) / 50.0f;
		}
	}

	if (_shadows == 1)
	{
		float bias;
		float2 projectTexCoord;
		float depthValue;
		float lightDepthValue;
		float lightIntensity;
		float4 textureColor;

		// Set the bias value for fixing the floating point precision issues.
		bias = 0.0001f;

		// Calculate the projected texture coordinates.
		projectTexCoord.x =  input.lightViewPosition.x / input.lightViewPosition.w / 2.0f + 0.5f;
		projectTexCoord.y = -input.lightViewPosition.y / input.lightViewPosition.w / 2.0f + 0.5f;

		// Determine if the projected coordinates are in the 0 to 1 range.  If so then this pixel is in the view of the light.
		if((saturate(projectTexCoord.x) == projectTexCoord.x) && (saturate(projectTexCoord.y) == projectTexCoord.y))
		{
			// Sample the shadow map depth value from the depth texture using the sampler at the projected texture coordinate location.
			depthValue = gBuffer_Shadows.Sample(ss, projectTexCoord).r;

			// Calculate the depth of the light.
			lightDepthValue = input.lightViewPosition.z / input.lightViewPosition.w;

			// Subtract the bias from the lightDepthValue.
			lightDepthValue = lightDepthValue - bias;

			// Compare the depth of the shadow map value and the depth of the light to determine whether to shadow or to light this pixel.
			// If the light is in front of the object then light the pixel, if not then shadow this pixel since an object (occluder) is casting a shadow on it.
			if(lightDepthValue < depthValue)
			{
				// Calculate the amount of light on this pixel.
				lightIntensity = saturate(dot(input.normal, -lightvec));

				if(lightIntensity > 0.0f)
				{
					// Determine the final diffuse color based on the diffuse color and the amount of light intensity.
					color += (ambientcol * lightIntensity) * color.a;

					// Saturate the final light color.
					color = saturate(color);
				}
			}
			else
			    color.rgb *= 0.3f;
		}
	}

	if (_fog == 1)
	{
		float l = saturate((input.Depth - FogStart) / (FogEnd - FogStart));
		color = float4(lerp(color,FogColor, l), color.a);
	}

	if (_selected == 1)
	{
		color += float4(0, 0, 0.2, 0);
	}

	color.a = saturate(color.a);

    return color;
}

Thanks! biggrin.png

FastCall22: "I want to make the distinction that my laptop is a whore-box that connects to different network"

Blog about... stuff (GDNet, WordPress): www.gamedev.net/blog/1882-the-cuboid-zone/, cuboidzone.wordpress.com/

Advertisement

Can anybody tell me if the parallax mapping is right? huh.png

I'm not asking for a fix, I'm just asking for a check, and if you have the time and you want to, you can give me an advice if you want to. happy.png

FastCall22: "I want to make the distinction that my laptop is a whore-box that connects to different network"

Blog about... stuff (GDNet, WordPress): www.gamedev.net/blog/1882-the-cuboid-zone/, cuboidzone.wordpress.com/

Nobody? huh.png

FastCall22: "I want to make the distinction that my laptop is a whore-box that connects to different network"

Blog about... stuff (GDNet, WordPress): www.gamedev.net/blog/1882-the-cuboid-zone/, cuboidzone.wordpress.com/

Looks like a bug I had a long while ago when first playing around with parallax mapping. The blurry strifes aren't supposed to be there, really. Just run the DX9 sdk-parallax mapping sample, and compare yours to this. I can't tell you what the exact problem was for me back then and how I solved it, but just study the directx sdk examples (there is actually also one for DX11, I believe)...

I believe that it's working now! biggrin.png

PS: I know that a sphere isn't the best choice...

Pic, please confirm:

2zy8vn4.png

FastCall22: "I want to make the distinction that my laptop is a whore-box that connects to different network"

Blog about... stuff (GDNet, WordPress): www.gamedev.net/blog/1882-the-cuboid-zone/, cuboidzone.wordpress.com/

Pic, please confirm:

Nope, still wrong. Unless you want a nightmarish game where everything is blurred and shapes are washed up, thats far, far from looking as it should. Its probably just a small space-convertion issue of some kind. Here is how it is supposed to look like.

Are you sure that this isn't how it's supposed to look?

2zswgmp.png

FastCall22: "I want to make the distinction that my laptop is a whore-box that connects to different network"

Blog about... stuff (GDNet, WordPress): www.gamedev.net/blog/1882-the-cuboid-zone/, cuboidzone.wordpress.com/

I followed this: http://www.d3dcoder.net/Data/Resources/ParallaxOcclusion.pdf

FastCall22: "I want to make the distinction that my laptop is a whore-box that connects to different network"

Blog about... stuff (GDNet, WordPress): www.gamedev.net/blog/1882-the-cuboid-zone/, cuboidzone.wordpress.com/

It looks definately better than on the sphere, but still, compared to this (see attachment) it looks washed up. Would need to see it in motion to see it more clearl, though.

Are you sure that this isn't how it's supposed to look?

Are you asking a question, or telling us that your implementation is correct? It isn't clear to me (or anyone else I think) what your motive is for writing this thread. If there is something about your results that seem wrong to you, then please ask about it. If this is a thread for you to demonstrate your implementation, then put that in the description.

So far, I haven't seen you really ask any substantive questions - please help us to understand what you want.

This topic is closed to new replies.

Advertisement