Problems with my gloss mapping...

Started by
4 comments, last by Moe 22 years, 3 months ago
A while ago I asked a question about gloss mapping (combining a grayscale image with an environment map, then with a base texture), and how it is done. I figured that I might as well try doing it, just to see if I could get it working. Instead of whipping a full program up, I decided to modify the Sphere Environment mapping example in the SDK. My rage fury pro only supports 2 simultaneous textures, so I have to do it in 2 stages unless I run in REF, but thats just horrible. Here is the section of code that I am using for my gloss mapping:
  
		// Adds in the spheremap texture

        m_pd3dDevice->SetTexture( 0, detail );
		m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
        m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP,   D3DTOP_SELECTARG1 );

		m_pd3dDevice->SetTexture( 1, m_pSphereMapTexture );
		m_pd3dDevice->SetTextureStageState( 1, D3DTSS_COLORARG1, D3DTA_CURRENT );
        m_pd3dDevice->SetTextureStageState( 1, D3DTSS_COLORARG2, D3DTA_TEXTURE );
        m_pd3dDevice->SetTextureStageState( 1, D3DTSS_COLOROP,   D3DTOP_MODULATE );

        // Generate spheremap texture coords, and shift them over

        D3DXMATRIX mat;
        mat._11 = 0.5f; mat._12 = 0.0f; mat._13 = 0.0f; mat._14 = 0.0f; 
        mat._21 = 0.0f; mat._22 =-0.5f; mat._23 = 0.0f; mat._24 = 0.0f; 
        mat._31 = 0.0f; mat._32 = 0.0f; mat._33 = 1.0f; mat._34 = 0.0f; 
        mat._41 = 0.5f; mat._42 = 0.5f; mat._43 = 0.0f; mat._44 = 1.0f; 
        m_pd3dDevice->SetTransform( D3DTS_TEXTURE1, &mat );
        m_pd3dDevice->SetTextureStageState( 1, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2 );
        m_pd3dDevice->SetTextureStageState( 1, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACENORMAL );

		// Finally, draw the teapot

        m_pTeapot->UseMeshMaterials( FALSE );
        m_pTeapot->Render( m_pd3dDevice );

		// Adds in the spheremap texture

        m_pd3dDevice->SetTexture( 0, base );
        m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_CURRENT );
        m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_TEXTURE );
        m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP,   D3DTOP_MODULATE );

		 // Finally, draw the teapot

        m_pTeapot->UseMeshMaterials( FALSE );
        m_pTeapot->Render( m_pd3dDevice );
  
Now for some reason, it doesn''t look quite right. The whole teapot is shiny, and it should only be shiny in certain areas. Can anyone spot the error here? Moe''s site
Advertisement
Anyone?

Moe''s site
Your code does the following:

1) Render teapot with DetailMap * SphereMap
2) Render teapot with BaseMap * SphereMap


Problems:

a) because you don''t DISABLE stage 1 for the second pass you get BaseMap*SphereMap (stage 1 is set up for the first pass) - when you probably just want the base map.

b) SetTextureStageState() affects how pixels are coloured BEFORE they''re written to the frame buffer - it has no effect on HOW they''re written to the frame buffer, so your second pass totally overdraws what was rendered in the first pass!!

c) You need to make sure that the first pass doesn''t write to the Z buffer OR that the second pass gets past the Z compare. Otherwise the pixels from the second pass won''t get written to the frame buffer.

A combination of a and b is why the whole the whole teapot is shiny.

Solutions:

- You can actually do gloss mapping in ONE pass. The gloss map only contains scalar values so can actually be stored in the ALPHA channel of either the base map or the environment map. You can do this using the D3DTA_ALPHAREPLICATE modifier flag to copy the alpha channel into the colour channel. (The limitation is on the number of unique textures, usually not how many times you use those textures).

- Use alpha blending to determine how the second pass gets blended with the first pass. ONE:ONE is the same as an ADD, and SRCCOLOR:DESTCOLOR is the same as a MULTIPLY. Its probably best to draw the base pass first then the detail pass on top.

- Remember to always DISABLE the stage after the one you''re using for a pass. In fact on older hardware it can be wise to disable all those you aren''t using once at program startup. Also on older hardware you sometimes get higher success rates by ensuring that the DISABLE is done in the same stage for alpha and colour channels, even if the alpha isn''t being used.

--
Simon O''''Connor
Creative Asylum Ltd
www.creative-asylum.com

Simon O'Connor | Technical Director (Newcastle) Lockwood Publishing | LinkedIn | Personal site

I am afraid I am still a bit confused.

What I thought I was doing was blending the detail texture with the sphere map, then blending the base texture with that. How exactly to I disable stage 1? So it is possible to do it in 1 pass, if I convert the grayscale picture with the spheremap''s alpha component, then blend that with the base texture?

Moe''s site
PASSES, STAGES & STATES
=======================

D3D uses a state model, so when you set a state, it remains set until you explicitly set it to something else again.

So at the top of your code you have:
SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );SetTextureStageState( 0, D3DTSS_COLOROP,   D3DTOP_SELECTARG1 );SetTextureStageState( 1, D3DTSS_COLORARG1, D3DTA_CURRENT );SetTextureStageState( 1, D3DTSS_COLORARG2, D3DTA_TEXTURE );SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_MODULATE ); 


Which sets blend stage 0 to SELECT TEXTURE 0, and sets blend stage 1 to MODULATE (*) the result of stage 0 (CURRENT) with TEXTURE from stage 1.

That is the current "state" D3D is set to, i.e. TEXTURE0 * TEXTURE1.

Further down your code, after you''ve set up the texture transform, the next time you touch the colour op states is to do:

SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_CURRENT );SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_TEXTURE );SetTextureStageState( 0, D3DTSS_COLOROP,   D3DTOP_MODULATE ); 


Which tells D3D to MODULATE the CURRENT colour input for stage 0 with the TEXTURE for stage 0. Since this is the first *STAGE* in this *PASS*, the input for CURRENT will be the DIFFUSE colour (from lighting, from the vertex colour or 0xFFFFFF if its disabled).

Stage 1 is still set to what you left it at for the second render of the model though, and is still active, because nothing has changed its state! This is why you need to DISABLE the stages you aren''t using ( Set COLOROP to D3DTOP_DISABLE ).


Actually I think you''ve become a tad mixed up over the distinction between STAGE and PASS:

"A Pass" is rendering the model with a current set of states. So your code uses 2 *passes* (each time you say m_pTeapot->Render( m_pd3dDevice ); it''s a new "pass").

"Stages" are the operations which take place to combine the textures and colour inputs for a single pass. The input of a stage is fed by the output of the previous stage. The input for stage 0 is fed with the pixels from the polygon being drawn in the CURRENT pass, it is *not* fed by the pixels drawn in the previous pass!


SINGLE PASS GLOSSMAPPING
========================

1. Usually an environment map doesn''t contain any alpha information, just R, G and B colour information. The alpha channel of that texture is often unused.

2. Your glossiness map is a greyscale texture, where R,G and B are set to the same value. Because of this, the glossiness map could fit into to unused alpha channel of the environment map!

3. There is a modifier flag for D3D texture stages (SetTextureStageState) which tells the graphics card to copy the current alpha channel into the R, G and B channels (R=A, G=A, B=A).

4. So what you can do is combine the glossiness map with the environment map (or with the base map if you''d prefer), and tell D3D to copy the alpha information into the colour channel at the relevent stage.


I seriously suggest you take another look at what''s in the docs under Using Direct3D->Textures->Texture Blending.


If I get time today I''ll modify the sample myself and post the code to show you what I''m talking about.


--
Simon O''''Connor
Creative Asylum Ltd
www.creative-asylum.com

Simon O'Connor | Technical Director (Newcastle) Lockwood Publishing | LinkedIn | Personal site

I think I see what you are getting at. I was blending the current stage 0 with the texture in stage 0, when I should have been blending the current stage 1 with the texture in stage 0.

I do know the difference between stages and passes. If my previous posts were a bit confusing, it was probably because I was up late. I probably should read over the docs when I get the chance, it can''t hurt me.

Thanks for the great in-depth help that you have given me!

Moe''s site

This topic is closed to new replies.

Advertisement