PolygonOffsetFactor doesn't seem to work with DirectX

You discovered a bug in the engine, and you are sure that it is not a problem of your code? Just post it in here. Please read the bug posting guidelines first.
Post Reply
dan27
Posts: 2
Joined: Tue Sep 23, 2014 1:06 am

PolygonOffsetFactor doesn't seem to work with DirectX

Post by dan27 »

I'm seeing the same problem described in this bug report: http://sourceforge.net/p/irrlicht/bugs/414/#7c89

Looking at the source, notice that SMaterial::PolygonOffsetFactor is a 3-bit value with values of 0 to 7. It is used in the CD3D9Driver::setBasicRenderStates() method like so:

Code: Select all

pID3DDevice->SetRenderState(D3DRS_DEPTHBIAS, F2DW((FLOAT)material.PolygonOffsetFactor));
The values passed to DirectX for D3DRS_DEPTHBIAS are going to be 0 through 7. 0 disables polygon offset, so the minimum value we can specify is 1. But isn't that the entire range of the values in the Z buffer? In other words, don't the DirectX Z buffer values range from -1.0 to +1.0? This is essentially moving the faces entirely outside the range of the z buffer if I understand this correctly. It seems to be appropriate for OpenGL which probably uses integers for the Z buffer, but not DirectX.

If you reference the MS docs here: http://msdn.microsoft.com/en-us/library ... s.85).aspx note that they say suitable values range from -1.0 to +1.0 which also seems to imply that these should be very small floating point values.
dan27
Posts: 2
Joined: Tue Sep 23, 2014 1:06 am

Re: PolygonOffsetFactor doesn't seem to work with DirectX

Post by dan27 »

To fix this I modified CD3D9Driver::setBasicRenderStates() to convert the integer offset to a floating point value in the range 0.0000001 to 0.01 increasing by a factor of 10. This isn't very elegant, but I don't know how else to do it without changing the public API. Hope this helps someone:

Code: Select all

 
    // Polygon offset
    if (queryFeature(EVDF_POLYGON_OFFSET) && (resetAllRenderstates ||
        lastmaterial.PolygonOffsetDirection != material.PolygonOffsetDirection ||
        lastmaterial.PolygonOffsetFactor != material.PolygonOffsetFactor))
    {
        if (material.PolygonOffsetFactor)
        {
         // --ds 9/23/14: material.PolygonOffsetFactor is a 3-bit bitfield with values of 
         // 0 to 7, but DirectX expects floating point values in the range of -1.0 to 1.0.
         // Map the integers to something more appropriate.  See the bug report filed here: 
         // PolygonOffsetFactor doesn't seem to work with DirectX
         // http://irrlicht.sourceforge.net/forum/viewtopic.php?f=7&t=50262&sid=d12a31df99610dc35741ba34355ecbea
         //
         // Powers of 10 for integer values 0 through 7: each value is 10 times larger than the last
         static float s_toD3d[8] = { 0.0f, 0.0000001f, 0.000001f, 0.00001f, 0.0001f, 0.001f, 0.01f, 0.1f };
 
            if (material.PolygonOffsetDirection==EPO_BACK)
            {
                pID3DDevice->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, F2DW(1.f));
                pID3DDevice->SetRenderState(D3DRS_DEPTHBIAS, F2DW((FLOAT)s_toD3d[material.PolygonOffsetFactor]));
            }
            else
            {
                pID3DDevice->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, F2DW(-1.f));
                pID3DDevice->SetRenderState(D3DRS_DEPTHBIAS, F2DW((FLOAT)-s_toD3d[material.PolygonOffsetFactor]));
            }
        }
        else
        {
            pID3DDevice->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, 0);
            pID3DDevice->SetRenderState(D3DRS_DEPTHBIAS, 0);
        }
    }
 
Post Reply