2
\$\begingroup\$

I'm trying to implement a radiosity processor. I'm aware of many places online to find information about radiosity. I found a great source on NVidia's website is GPU Gems - Chapter 39 . On this page they talk about Hemispherical projection. I've implemented a projector that will place mesh 'vertices' on a unit hemisphere...the problem is that the rasterizer only linearly interpolates between vertices along an edge...

...is there a way to adjust the method of interpolation?

Here is shader code for hemispherical projection...it does place the objects correctly, however, the edges between the vertices are straight...when true hemispherical projection would create rounded edges...

float4x4 mW;
float4x4 mV;
float4x4 mP;
float4x4 mOrtho;
float2 vNearFar;
static const float PI = 3.14159265f;


texture g_TextureDiffuse;
sampler g_SamplerDiffuse = sampler_state
{
    Texture = <g_TextureDiffuse>;
    MinFilter = Point;
    MagFilter = Linear;
    MipFilter = Linear;
    AddressU = Clamp;
    AddressV = Clamp;  
};


struct VS_IN
{
    float4 Position : POSITION0;
    float3 Normal : NORMAL0;
    float2 UV : TEXCOORD0;
};

struct PS_IN
{
        float4 Position : POSITION0;
    float3 Normal : TEXCOORD0;
    float2 UV : TEXCOORD1;
    float4 Pos2 : TEXCOORD2;
};

PS_IN VS( VS_IN input )
{
    PS_IN output = ( PS_IN )0;

    float4x4 mWV = mul( mW, mV );
    float4x4 mWVP = mul( mWV, mP );
        half4 vPos = mul( input.Position, mWV );

    half3 vHemi = normalize( vPos.xyz );

    half3 fNearFar = vNearFar.y - vNearFar.x;

    output.Position.xy = vHemi.xy * fNearFar;
    output.Position.z = ( vPos.z / ( vNearFar.y - vNearFar.x ) );
    output.Position.w = fNearFar;
    output.Pos2 = output.Position;
    output.Normal = mul( input.Normal, mWV );
    output.UV = input.UV;
    return output;
}

float4 PS( PS_IN input ) : COLOR0
{
    //float2 uv = input.UV - 0.5;
    //float z = sqrt( 1.0 - input.Pos2.x * input.Pos2.x - input.Pos2.y * input.Pos2.y );
        //float a = ( z * tan( ( PI / 2 ) * 0.5 ) );
        //return tex2D( g_SamplerDiffuse, ( uv * a ) + 0.5 );

    float4 diffuse = tex2D( g_SamplerDiffuse, input.UV );
    return diffuse;
}

technique Render
{
    pass Pass0
    {
        VertexShader = compile vs_2_0 VS();
            PixelShader = compile ps_2_0 PS();
    }
}

Here is screenshot: enter image description here

It may be difficult to tell, but the cube has two faces( triangles ) per side( 6 sides, 12 faces ). From the picture you may be able to see the problem with flat edges...this problem is well documented...I'm trying to avaoid having to render 5 different images( hemicube ) to approximate a hemisphere...I'm mostly interested in hearing about methods of implementing a hemisphere...I also tried( to no avail ) to write a pixel shader that would warp the final( post scene render ) image. I didn't get great results...

...it also just came to me that I don't necessarily need a render result for computing the form factor...just the area that the projected object consumes within the area of the hemisphere base...

...any thoughts are appreciated!

... here is a screenshot of the cube subdivided...much better...still not accurate enter image description here

\$\endgroup\$

1 Answer 1

3
\$\begingroup\$

Hardware rasterizers are only designed to support perspective projection, and they assume that positions and other attributes can be interpolated "linearly" (actually, they use perspective-correct interpolation, where quantities vary along a linear path but not necessarily at a linear rate). They cannot rasterize hemispherical/fisheye/parabolic projections natively.

You can of course calculate these projections in the vertex shader, but unless all your geometry is quite highly tessellated, you'll run into problems that way: geometry too close to the camera will be rasterized inaccurately (so the radiosity result will be inaccurate as well), and it's possible for objects behind a wall to penetrate the wall and become visible when they shouldn't be.

Ignacio Castaño tried various nonlinear projections when working on the lighting capture system for The Witness, and didn't get anywhere with them. He eventually went with hemicubes. (Ignacio's other articles on that blog are also worth reading if you're building a radiosity solver.)

\$\endgroup\$
1
  • \$\begingroup\$ thanks...high tesselation is the answer for approximation of a hemisphere...that's what i've just finished trying...I wrote a subdivision algorithm that divides each mesh face by 2 until it reaches a threshold...too many faces...invalid artifacts due to their proximity to the camera( or near any plane ) and the like...I thought that because NVidia suggests a hemispherical projection approach that there must be some way of doing it accurately...I've played around with it enough now to move on...thanks again...above is the same cube, subdivided...it was an improvement \$\endgroup\$
    – P. Avery
    Aug 22, 2013 at 4:53

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .