Curious why no hybrid MSAA/SSAA?

arjan de lumens said:
Does alpha-to-coverage work correctly when there are multiple layers of alpha-blended/tested polygons drawn on top of each other?
Not quite, but that situation doesn't happen very often in those cases where alpha test is used currently. However, alpha to coverage has the same problem as alpha blending with magnification. If you get close to the edges, they will blur (and with a2c, you'll have banding, as you only have a small number of different coverage levels).
 
By keeping the test and the write in the same place we can enforce read-write coherency with relatively simple control and some tweaks to the required Z cache logic.

This was the vital part of information about hardware implementations that I was missing :)
I wasn't aware of the fact that the rasterizer could start on the next polygon before shading was complete. So I didn't know a problem could even exist there.

Anyway, if you would have some kind of 'dirty regions', where z was not updated yet, you could still draw (parts of) polygons that do not cover dirty regions... Perhaps the hierarchical zbuffers will incorporate this one day?
And why do I have the feeling that we'd be moving more and more towards tile-based (deferred) rendering :)
 
Couldn't you mystically generate a formula which will apply SS to all pixels while they are compressed?

This way they get bigger but not as big as if you were to uncompress everything. :D
 
Xmas said:
OpenGL guy said:
But if your compressed value depends on sample location...
I don't get it. If you adjust the sample positions, then you're trying to put sample No. x at exactly the same location where it is in multisampling operation.

And even if that's not possible, it's not too bad. Leave the sampling positions where they are. Ok, your texture and geometry sampling points are not in the same location then, but this is the case with multisampling, too. It may give slight overlap artifacts if polygons with alpha test are connected to polygons without alpha test, but considering how alpha test edges look like, I think it is a worthy tradeoff for many games.
The problem is far worse than you think. If you think it's trivial, write a program that does everything you've described, give me the source code and I'll make it fail catastrophically.
Rendering with multisample mask certainly isn't the best thing for performance because it makes compression almost useless for those tiles affected, but it's better than supersampling for the whole frame.
But, as I mentioned, you'd have to decompress the whole buffer, meaning very poor performance... worse than supersampling since supersampling would benefit from compression.
You don't have to decompress the Z buffer if you don't mess with the sample positions, but only use multisample mask, do you?
If you don't move the sample positions, then probably not, however you're going to get weird artifacts on the edges on some objects. These weird artifacts can be very ugly.
 
Dark Helmet said:
Not necessarily. Consider ALPHA_TO_COVERAGE.
More correctly, it's GL_SAMPLE_ALPHA_TO_COVERAGE_ARB, and the name shows probably the biggest problem with a2c...
 
OpenGL guy said:
The problem is far worse than you think. If you think it's trivial, write a program that does everything you've described, give me the source code and I'll make it fail catastrophically.
Is C#/MDX fine with you?
 
The problem is far worse than you think. If you think it's trivial, write a program that does everything you've described, give me the source code and I'll make it fail catastrophically.

Are you serious?

Why not make it a competition? See if anyone can come up with a way to make it work. :D
 
Xmas said:
OpenGL guy said:
The problem is far worse than you think. If you think it's trivial, write a program that does everything you've described, give me the source code and I'll make it fail catastrophically.
Is C#/MDX fine with you?
C or C++ please... I don't want to have to learn a new language just for this :p
 
Xmas said:
Dark Helmet said:
Not necessarily. Consider ALPHA_TO_COVERAGE.
More correctly, it's GL_SAMPLE_ALPHA_TO_COVERAGE_ARB, and the name shows probably the biggest problem with a2c...
How so? The thought running through my mind is it mandates the slow path (frag shader -> alpha value -> now we know which samples, so we can: stencil/alpha/depth test).
 
OpenGL guy said:
C or C++ please... I don't want to have to learn a new language just for this :p
Well, then maybe you tell me what you need and I will write it. After learning MDX, I really don't want to go back to those clumsy COM interfaces. ;)


Dark Helmet said:
How so? The thought running through my mind is it mandates the slow path (frag shader -> alpha value -> now we know which samples, so we can: stencil/alpha/depth test).
I meant the "GL_" part. There is no a2c in DirectX.
 
Xmas said:
OpenGL guy said:
C or C++ please... I don't want to have to learn a new language just for this :p
Well, then maybe you tell me what you need and I will write it. After learning MDX, I really don't want to go back to those clumsy COM interfaces. ;)
You should be able to just grab one of the MS DX9 SDK samples, rip out the rendering path and add in everything you've described above for alpha tested textures. Then put the source someplace and I'll show you how to break it :)
 
OpenGL guy said:
You should be able to just grab one of the MS DX9 SDK samples, rip out the rendering path and add in everything you've described above for alpha tested textures. Then put the source someplace and I'll show you how to break it :)
Ok, just a very quick hack:
Take the "Billboard" sample and replace CMyD3DApplication::DrawTrees with this one:

Code:
HRESULT CMyD3DApplication::DrawTrees()
{
	bool bUseSuperSampling = true;
	D3DXMATRIX pMatrix, tMatrix, pnMatrix[4];
	float samplepos[4][2] = /*{ { -0.375f, -0.125 }, { 0.125f, -0.375f }, 
							  { -0.125f, 0.375f }, { 0.375f, 0.125f } };*/ // RG
	{ { 0, 0 }, { 0, 0.5f }, { 0.5f, 0 }, { 0.5f, 0.5f } } ;	// OG
	D3DVIEWPORT9 viewport;

	if(bUseSuperSampling)
	{
		m_pd3dDevice->SetRenderState(D3DRS_MULTISAMPLEANTIALIAS, TRUE);
		m_pd3dDevice->GetTransform(D3DTS_PROJECTION, &pMatrix);
		m_pd3dDevice->GetViewport(&viewport);
		// prepare shifted projection matrices for sample positions
		for(int j = 0; j < 4; ++j)
		{
			D3DXMatrixTranslation(&tMatrix,  2 * samplepos[j][0] / viewport.Width, 
				2 * samplepos[j][1] / viewport.Height, 0);
			D3DXMatrixMultiply(&pnMatrix[j], &pMatrix, &tMatrix);			
		}
	}

    // Enable alpha testing (skips pixels with less than a certain alpha.)
    if( m_d3dCaps.AlphaCmpCaps & D3DPCMPCAPS_GREATEREQUAL )
    {
        m_pd3dDevice->SetRenderState( D3DRS_ALPHATESTENABLE, TRUE );
        m_pd3dDevice->SetRenderState( D3DRS_ALPHAREF,        0x7f );//*** 
        m_pd3dDevice->SetRenderState( D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL );
    }

    // Loop through and render all trees
    m_pd3dDevice->SetStreamSource( 0, m_pTreeVB, 0, sizeof(TREEVERTEX) );
    m_pd3dDevice->SetFVF( TREEVERTEX::FVF );
    for( DWORD i=0; i<NUM_TREES; i++ )
    {
        // Quick culling for trees behind the camera
        // This calculates the tree position relative to the camera, and
        // projects that vector against the camera's direction vector. A
        // negative dot product indicates a non-visible tree.
        if( 0 > ( m_Trees[i].vPos.x - m_vEyePt.x ) * g_vDir.x + 
                ( m_Trees[i].vPos.z - m_vEyePt.z ) * g_vDir.z )
        {
            break;
        }
        
        // Set the tree texture
        m_pd3dDevice->SetTexture( 0, m_pTreeTextures[m_Trees[i].dwTreeTexture] );

        // Translate the billboard into place
        m_matBillboardMatrix._41 = m_Trees[i].vPos.x;
        m_matBillboardMatrix._42 = m_Trees[i].vPos.y;
        m_matBillboardMatrix._43 = m_Trees[i].vPos.z;
        m_pd3dDevice->SetTransform( D3DTS_WORLD, &m_matBillboardMatrix );

		//***
		
		if(bUseSuperSampling)
		{
			for(int j = 0; j < 4; ++j)
			{
				m_pd3dDevice->SetRenderState(D3DRS_MULTISAMPLEMASK, 1 << j);

				m_pd3dDevice->SetTransform(D3DTS_PROJECTION, &pnMatrix[j]);

				// Render the billboard
				m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, m_Trees[i].dwOffset, 2 );
			}
		}
		else
		{
			// Render the billboard
			m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, m_Trees[i].dwOffset, 2 );
		}
		//***
    }

    // Restore state
    D3DXMATRIXA16  matWorld;
    D3DXMatrixIdentity( &matWorld );
    m_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );
    m_pd3dDevice->SetRenderState( D3DRS_ALPHATESTENABLE,    FALSE );

	//***
	if(bUseSuperSampling)
	{
		m_pd3dDevice->SetRenderState(D3DRS_MULTISAMPLEMASK, 0xffff);
		m_pd3dDevice->SetRenderState(D3DRS_MULTISAMPLEANTIALIAS, TRUE);
		m_pd3dDevice->SetTransform(D3DTS_PROJECTION, &pMatrix);
	}
	//***

    return S_OK;
}

You have to set multisample type to 4 samples for this to work.
 
Xmas said:
And even if that's not possible, it's not too bad. Leave the sampling positions where they are. Ok, your texture and geometry sampling points are not in the same location then, but this is the case with multisampling, too. It may give slight overlap artifacts if polygons with alpha test are connected to polygons without alpha test, but considering how alpha test edges look like, I think it is a worthy tradeoff for many games.
This seems like a very serious source of artifacts to me. I think the best case scenario would be setting it up so that all samples in a pixel have the same Z value (i.e. the translation matrix offsets match the subsample offsets). Then you get just plain aliased intersections between alpha-tested and non alpha-tested polys. Better than no alpha-test AA, but it may not be good enough considering the perf hit of your solution, Xmas. Still, we all love having IQ options, right? :D

OpenGL guy, how does centroid sampling work when the multisample mask is set? Is the texture sampling location equal to the centroid of the enabled samples or all samples in the poly for this pixel?
 
Back
Top