View more

View more

View more

### Image of the Day Submit

IOTD | Top Screenshots

### The latest, straight to your Inbox.

Subscribe to GameDev.net Direct to receive the latest updates and exclusive content.

# 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.

2 replies to this topic

### #1dr4cula  Members

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):

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;
}

// 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();
}

// 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!

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.

### #3dr4cula  Members

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.

-- 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;
}