Jump to content

  • Log In with Google      Sign In   
  • Create Account


Dual Paraboloid Environment Mapping


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
2 replies to this topic

#1 dr4cula   Members   -  Reputation: 250

Like
0Likes
Like

Posted 22 March 2014 - 12:17 PM

Hello,

I've previously implemented cubemapping but due to the performance heavy nature of it I've decided to try out dual paraboloid mapping instead. However, I've run into a complete dead end and I can't seem to find where I've gone wrong. I'm having trouble generating the environment maps: http://postimg.org/image/nzfrv6z7h/

As you can see, on the left side (forward part) is really dodgy looking and on the right side (backwards part) is completely messed up.

Here are my shaders (based on J. Zink's solution in his D3D11 book):

Vertex shader:
paraboloidWorldMatrix = rendered object's matrix, I know I should calculate the concatenation on the CPU first but for the time being, it shouldn't matter
// input description
struct VSInput {
	float3 position : POSITION;
	float2 texCoord : TEXCOORD;
};

// output description
struct VSOutput {
	float4 position : SV_POSITION;
	float2 texCoord : TEXCOORD0;
	float zValue : ZVALUE;
};

cbuffer ParaboloidMatrices : register(b0) {
	matrix paraboloidWorldMatrix;
	matrix paraboloidViewMatrix;
};


/*
  =====================
  VSMain
  =====================
*/

VSOutput VSMain(VSInput input) {
	VSOutput output;
	output.position = float4(input.position, 1.0f);

	output.position = mul(output.position, paraboloidWorldMatrix);
	output.position = mul(output.position, paraboloidViewMatrix);

	// find the distance from the paraboloid's origin
	float dist = length(output.position.xyz);

	// normalize the position vector
	output.position /= dist;

	// save the normalized z-value 
	output.zValue = output.position.z;

	// scale the z-coordinate for the depth buffer
	output.position.z = dist / 1000;

	// set the w component to 1, ie no perspective projection done
	output.position.w = 1.0f;

	output.texCoord = input.texCoord;

	return output;
}
Geometry shader:
// input description
struct GSInput {
	float4 position : SV_POSITION;
	float2 texCoord : TEXCOORD0;
	float zValue : ZVALUE;
};

// output description
struct GSOutput {
	float4 position : SV_POSITION;
	float2 texCoord : TEXCOORD0;
	uint rtArrayIndex : SV_RenderTargetArrayIndex;
	float zValue : ZVALUE;
};

/*
  =====================
  GSMain
  =====================
*/

// instance 0 - forward part of the paraboloid
// instance 1 - backwards part of the paraboloid
[instance(2)]
[maxvertexcount(3)]
void GSMain(triangle GSInput input[3], uint instanceID : SV_GSInstanceID, inout TriangleStream<GSOutput> outputStream) {
	GSOutput output;

	// default winding and direction
	uint3 winding = uint3(0, 1, 2);
	float direction = 1.0f;

	// reverse the winding and direction for backwards paraboloid instances
	if(instanceID == 1) {
		winding.xyz = winding.xzy;
		direction = -1.0f;
	}

	// find the 3 triangle vertices
	[unroll]
	for(int i = 0; i < 3; ++i) {
		// create the projection factor into the paraboloid space
		float projectionFactor = input[winding[i]].zValue * direction + 1.0f;
		
		// find the vertices in paraboloid space
		output.position.x = input[winding[i]].position.x / projectionFactor;
		output.position.y = input[winding[i]].position.y / projectionFactor;
		output.position.z = input[winding[i]].position.z;
		output.position.w = 1.0f;

		// pass the texture coordinates along
		output.texCoord = input[winding[i]].texCoord;

		// let the render target array index be the same as the instance ID, ie 0/1 for forward/backwards paraboloid parts
		output.rtArrayIndex = instanceID;

		// pass the z value along in the current direction for easy clipping in the pixel shader
		output.zValue = input[winding[i]].zValue * direction;

		outputStream.Append(output);
	}

	outputStream.RestartStrip();
}
Pixel shader:
// input description
struct PSInput {
	float4 position : SV_POSITION;
	float2 texCoord : TEXCOORD0;
	uint rtArrayIndex : SV_RenderTargetArrayIndex;
	float zValue : ZVALUE;
};

// use the sampler bound to slot 0
SamplerState texSampler_;

// texture bound for rendering
Texture2D texture_ : register(t0);

/*
  =====================
  PSMain
  =====================
*/

float4 PSMain(PSInput input) : SV_TARGET {
	clip(input.zValue + 0.05f);
	
	float4 color = texture_.Sample(texSampler_, input.texCoord);

	return color;
}
I've tried comparing my code with the one presented in the book (as well as a couple of samples I've found online) but I can't find where I've gone wrong... Hope someone can help me out!

Thanks in advance!

Sponsor:

#2 Adam_42   Crossbones+   -  Reputation: 2418

Like
2Likes
Like

Posted 22 March 2014 - 04:31 PM

From the image it looks like you're rendering a very small number of polygons.

 

For dual paraboloid mapping that won't work well - you need lots of polys if you want it to look correct as the spherical transform is done on the vertices, and not per pixel.



#3 dr4cula   Members   -  Reputation: 250

Like
0Likes
Like

Posted 23 March 2014 - 06:41 AM

From the image it looks like you're rendering a very small number of polygons.
 
For dual paraboloid mapping that won't work well - you need lots of polys if you want it to look correct as the spherical transform is done on the vertices, and not per pixel.


Thanks for your reply!

-- edited --

I had a massive typo in my shaders earlier, should be fixed now. I've created a completely new scene with a higher res poly model to use for reflection. However, there's still a problem with it: http://postimg.org/image/ehiu32s81/ (scene setup (sphere is the reflective object): http://postimg.org/image/gy01i39jb/)

Since the projection remains constant (http://postimg.org/image/v57uibnpb/), I'm assuming something is off in my sampling, so here's my pixel shader:
 
// input description
struct PSInput {
	float4 position : SV_POSITION;
	float2 texCoord : TEXCOORD0;
	float3 normal : NORMAL;
	float3 incidentVector : INCIDENT_VECTOR;
};

cbuffer ParaboloidMatrices : register(b0) {
	matrix paraboloidWorldMatrix;
	matrix paraboloidViewMatrix;
};

// use the sampler bound to slot 0
SamplerState texSampler_;

// texture bound for rendering
Texture2DArray texture_ : register(t0);

/*
  =====================
  PSMain
  =====================
*/

float4 PSMain(PSInput input) : SV_TARGET {
	// normalize the necessary input vectors
	float3 normal = normalize(input.normal);
	float3 incident = normalize(input.incidentVector);

	// find the reflection vector in paraboloid space
	float3 ref = reflect(incident, normal);
	ref = mul(ref, (float3x3)paraboloidViewMatrix);

	// find the forward facing paraboloid texture coordinates, z specifies which texture from the array to use
	float3 forward;
	forward.x = ref.x / (ref.z + 1.0f);
	forward.y = ref.y / (ref.z + 1.0f);
	// convert to the appropriate range from [-1,1] to [0,1]
	forward.x = (forward.x + 1.0f) / 2.0f;
	forward.y = 1.0f - (forward.y + 1.0f) / 2.0f;
	forward.z = 0.0f;

	// find the backward facing paraboloid texture coordinates, z specifies which texture from the array to use
	float3 backward;
	backward.x = ref.x / (1.0f - ref.z);
	backward.y = ref.y / (1.0f - ref.z);
	// convert to the appropriate range from [-1,1] to [0,1]
	backward.x = (backward.x + 1.0f) / 2.0f;
	backward.y = 1.0f - (backward.y + 1.0f) / 2.0f;
	backward.z = 1.0f;

	float4 color;
	if(ref.z > 0.0f) {
		color = texture_.Sample(texSampler_, forward);
	}
	else {
		color = texture_.Sample(texSampler_, backward);
	}

	return color;
}
Thanks in advance once more!

Edited by dr4cula, 23 March 2014 - 08:16 AM.





Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS