Skip to main content
GameDev.net gamedev.net
🔒 Locked

Texture Blending

Started by Swatter555 Nov 7, 2004 at 2:49 PM 8 replies 1.7k views
Original Post
Swatter555
Swatter555
I am getting some strange results trying to blend two textures together. Im am trying to blend one texture that is being loaded from a file and one that is created procedurally. Basically, that one loaded from the file is the base texture and the one created proc. is a light map. I am confused by many things,actually. For the light map, I set the base color to white and the shadows are obviously shades of gray. When I render just the light map, the results are correct. Combining this with the base texture should give me the base texture blended with the elevation shades, but it isnt working correctly. I may be fundementally misunderstanding this. I was going by the example in the DX SDK, but it is blending really funky. The result shows the shades of elevation, but only one color from the base texture is actually being shown. I am no doubt abusing the render state values, but here is code snip:


//Alpha determines transparency
		_device->SetRenderState(D3DRS_SRCBLEND,D3DBLEND_SRCALPHA);
		_device->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA);

        //Set the light map texture
		_device->SetTexture(0,_light_map);

		//Set the base texture operation and args
        _device->SetTextureStageState(0,D3DTSS_COLOROP,D3DTOP_MODULATE);
        _device->SetTextureStageState(0,D3DTSS_COLORARG1, D3DTA_TEXTURE);
        _device->SetTextureStageState(0,D3DTSS_COLORARG2, D3DTA_DIFFUSE);

        //Set the base texture
        _device->SetTexture(1,_tex);
		
        //Set the blend stage
        _device->SetTextureStageState(1,D3DTSS_COLOROP, D3DTOP_MODULATE);
        _device->SetTextureStageState(1,D3DTSS_COLORARG1, D3DTA_TEXTURE);
        _device->SetTextureStageState(1,D3DTSS_COLORARG2, D3DTA_CURRENT);
		

		//Enable blending
		_device->SetRenderState(D3DRS_ALPHABLENDENABLE,true);
		
		hr =_device->DrawIndexedPrimitive(
			D3DPT_TRIANGLELIST,
			0,
			0,
			_numVertices,
			0,
			_numTriangles);

		//Disable blending
		_device->SetRenderState(D3DRS_ALPHABLENDENABLE,false);



Any help or advice would be appreciated.
Pipo DeClown
Pipo DeClown
I'm not really sure, but the code seems okay. Can you perhaps show the bad result as an image?
Swatter555
Swatter555
Each texture renders on the mesh fine, seperately. So, Im thinking that it must be the blending. I dont really understand this stuff too well, so any suggestions would be helpful :)
hplus0603
hplus0603
Did you validate the render state after setting up the device? Some devices have problems with things like where "DIFFUSE" should go.

Also, it's hard to tell what's wrong, because you're not showing us what it looks like when you're only rendering the light map.

Another thing to be aware of is that you're not setting up the alpha ops for your texture stages, but you're turning on alpha blend. It's not clear that you need alpha blend at all, and if you do, you clearly should set all the alpha ops for the stages you're using!

Last, you're not showing us how you set up texture coordinates -- note that the second texture unit needs a second set of texture coordinates, unless you're using Dx9 magic to map a single stream of texture coordinates to two texture units.
enum Bool { True, False, FileNotFound };
Swatter555
Swatter555
Ok, I updated the webpage with the light map. I dont know what you mean by validating the render state :(

Ok, Ill post the source code for the vertex generation method, and the light map generation methods. I hope this helps,let me know if you need more.

I am on very shaky footing with this stuff, so keep your explanations pretty simple :)

bool TERRAIN::computeVertices(){	HRESULT hr = 0;	hr = _device->CreateVertexBuffer(		_numVertices * sizeof(TerrainVertex),		D3DUSAGE_WRITEONLY,		TerrainVertex::FVF,		D3DPOOL_MANAGED,		&_vb,		0);	if(FAILED(hr))		return false;	// coordinates to start generating vertices at	int startX = -_width / 2;	int startZ =  _depth / 2;	// coordinates to end generating vertices at	int endX =  _width / 2;	int endZ = -_depth / 2;	// compute the increment size of the texture coordinates	// from one vertex to the next.	float uCoordIncrementSize = 1.0f / (float)_numCellsPerRow;	float vCoordIncrementSize = 1.0f / (float)_numCellsPerCol;	TerrainVertex* v = 0;	_vb->Lock(0, 0, (void**)&v, 0);	int i = 0;	for(int z = startZ; z >= endZ; z -= _cellSpacing)	{		int j = 0;		for(int x = startX; x <= endX; x += _cellSpacing)		{			// compute the correct index into the vertex buffer and heightmap			// based on where we are in the nested loop.			int index = i * _numVertsPerRow + j;			v[index] = TerrainVertex((float)x,				                     (float)_heightmap[index],				                     (float)z,				                     (float)j * uCoordIncrementSize,				                     (float)i * vCoordIncrementSize);			j++; // next column		}		i++; // next row	}	_vb->Unlock();	return true;}bool TERRAIN::genLightMap(D3DXVECTOR3 *directionToLight){		//Method fills the top surface of a texture procedurally.  Then	//lights the top surface.  Finally, it fills the other mipmap	//surfaces based on the top surface data using D3DXFilterTexture.	HRESULT hr = 0;	// texel for each quad cell	int texWidth  = _numCellsPerRow;	int texHeight = _numCellsPerCol;	// create an empty texture	hr = D3DXCreateTexture(		_device,		texWidth, 		texHeight,		0,              // create a complete mipmap chain		0,              // usage		D3DFMT_X8R8G8B8,// 32 bit XRGB format		D3DPOOL_MANAGED, &_light_map);	if(FAILED(hr))	{		//If failure, Show MB	    MessageBox(_hwnd,		"Error:Unable create height texture.",		"October War Editor Error",		 MB_OK);        //Send a quit message if failure		PostMessage(_hwnd,WM_CLOSE,0,0);		return false;	}//end if	D3DSURFACE_DESC textureDesc; 	_light_map->GetLevelDesc(0 /*level*/, &textureDesc);	// make sure we got the requested format because our code 	// that fills the texture is hard coded to a 32 bit pixel depth.	if(textureDesc.Format != D3DFMT_X8R8G8B8)	   return false;			D3DLOCKED_RECT lockedRect;	_light_map->LockRect(0/*lock top surface*/, &lockedRect, 		0 /* lock entire tex*/, 0/*flags*/);         	DWORD* imageData = (DWORD*)lockedRect.pBits;	for(int i = 0; i < texHeight; i++)	{		for(int j = 0; j < texWidth; j++)		{			D3DXCOLOR c = owb->trans;			// fill locked data, note we divide the pitch by four because the			// pitch is given in bytes and there are 4 bytes per DWORD.			imageData[i * lockedRect.Pitch / 4 + j] = (D3DCOLOR)c;		}	}	_light_map->UnlockRect(0);	if(!lightTerrain(directionToLight))	{		::MessageBox(0, "lightTerrain() - FAILED", 0, 0);		return false;	}		hr = D3DXFilterTexture(		_light_map,		0, // default palette		0, // use top level as source level		D3DX_DEFAULT); // default filter	if(FAILED(hr))	{		::MessageBox(0, "D3DXFilterTexture() - FAILED", 0, 0);		return false;	}	return true;}bool TERRAIN::lightTerrain(D3DXVECTOR3 *directionToLight){	HRESULT hr = 0;	D3DSURFACE_DESC textureDesc; 	_light_map->GetLevelDesc(0 /*level*/, &textureDesc);	// make sure we got the requested format because our code that fills the	// texture is hard coded to a 32 bit pixel depth.	if( textureDesc.Format != D3DFMT_X8R8G8B8 )		return false;			D3DLOCKED_RECT lockedRect;	_light_map->LockRect(		0,          // lock top surface level in mipmap chain		&lockedRect,// pointer to receive locked data		0,          // lock entire texture image		0);         // no lock flags specified	DWORD* imageData = (DWORD*)lockedRect.pBits;	for(int i = 0; i < textureDesc.Height; i++)	{		for(int j = 0; j < textureDesc.Width; j++)		{			// index into texture, note we use the pitch and divide by 			// four since the pitch is given in bytes and there are 			// 4 bytes per DWORD.			int index = i * lockedRect.Pitch / 4 + j;			// get current color of quad			D3DXCOLOR c( imageData[index] );			// shade current quad			c *= computeShade(i, j, directionToLight);			// save shaded color			imageData[index] = (D3DCOLOR)c;		}	}	_light_map->UnlockRect(0);	return true;}float TERRAIN::computeShade(int cellRow,int cellCol,D3DXVECTOR3 *directionToLight){	// get heights of three vertices on the quad	float heightA = getHeightmapEntry(cellRow,   cellCol);	float heightB = getHeightmapEntry(cellRow,   cellCol+1);	float heightC = getHeightmapEntry(cellRow+1, cellCol);	// build two vectors on the quad	D3DXVECTOR3 u(_cellSpacing, heightB - heightA, 0.0f);	D3DXVECTOR3 v(0.0f,         heightC - heightA, -_cellSpacing);	// find the normal by taking the cross product of two	// vectors on the quad.	D3DXVECTOR3 n;	D3DXVec3Cross(&n, &u, &v);	D3DXVec3Normalize(&n, &n);	float cosine = D3DXVec3Dot(&n, directionToLight);	if(cosine < 0.0f)	   cosine = 0.0f;	return cosine;}
hplus0603
hplus0603
You didn't pay attention to my suggestion. I asked you whether there were two texture coordinate channels, and you post code without showing what TerrainVertex looks like, but you post a lot of code that you've already claimed is proven correct (by rendering each texture singly). Besides, I don't want to see your code; I want you to figure out the problem.

As for validating the device, try MSDN.
Especially good is the ValidateDevice() function -- which you would have found if you just did a search on "validate" and "device" rather than asking what I meant.
enum Bool { True, False, FileNotFound };
Swatter555
Swatter555
Sorry, I dont mean to do lazy or anything and I should have read you post more closely.

Im coding in validate device as I write this.

struct TerrainVertex	{		TerrainVertex(){}		TerrainVertex(float x, float y, float z,float u, float v)		{			_x = x; _y = y; _z = z;			_u = u; _v = v;		}		float _x, _y, _z;		float _u, _v;		static const DWORD FVF;	};
EverIce
EverIce
I'm absolutelly sure you forget that :
_device->setTextureStageState(1, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_PASSTHRU);

Swatter555
Swatter555
Quote:
Original post by EverIce
I'm absolutelly sure you forget that :
_device->setTextureStageState(1, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_PASSTHRU);



I love you! I also thank everyone who has contributed to this thread and my greater understanding.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.