Speeding up Map Rendering

Started by
-1 comments, last by Hippokrates 21 years, 7 months ago
I have thought about a way to speed up rendering my map. My map is made up of tiles which are represented by Rectangles. I am using D3D8 for an API and render these Rectangles as unlit and untransformed vertices in triangle lists. What I thought of to speed up is to divide the map into Regions which contain an Index Buffer to store the indices into the map VB and a Rectangle to detect if they are visible. To set up the index buffers I have to know how many tiles are contained within a region. How can this be done? I tried a triangle-point collision test making the tile a rect and checking it thus against the bounding rect of the region but this didn`t seem to work. So let me show you what I did, perhaps you can find out what`s wrong or what can be done better. First of all the required structures:

//A Map Region:
struct MapRegion {
	int iContainedTiles[Map_Layers];
	int iTextureIndex;
	LPDIRECT3DINDEXBUFFER8 IndexBuffer[Map_Layers];
	RECT3D BoundingRect;
};
//A Rect
struct Rect3D {
	D3DVECTOR UpperLeft;
	D3DVECTOR UpperRight;
	D3DVECTOR LowerLeft;
	D3DVECTOR LowerRight;
};
 
So I made a rect out of the tile (this code is a bit confusing because I have to watch out if the Map is a tile or an isometric map)

bool CMap::TileInRect(DWORD dwMapX, DWORD dwMapY, LPRECT3D pRect) {
	RECT3D TileRect;
	if(MAP_TILE == m_Header.byMode) {
		TileRect.UpperLeft.x = dwMapX * m_Header.fGeometryWidth;
		TileRect.UpperLeft.y = dwMapY * -(m_Header.fGeometryHeight);
		TileRect.UpperLeft.z = m_Header.fZoom;
		TileRect.LowerLeft.x = dwMapX * m_Header.fGeometryWidth;
		TileRect.LowerLeft.y = dwMapY * -(m_Header.fGeometryHeight) - m_Header.fGeometryHeight;
		TileRect.LowerLeft.z = m_Header.fZoom;
		TileRect.UpperRight.x = dwMapX * m_Header.fGeometryWidth + m_Header.fGeometryWidth;
		TileRect.UpperRight.y = dwMapY * -(m_Header.fGeometryHeight);
		TileRect.UpperRight.z = m_Header.fZoom;
		TileRect.LowerRight.x = dwMapX * m_Header.fGeometryWidth + m_Header.fGeometryWidth;
		TileRect.LowerRight.y = dwMapY * -(m_Header.fGeometryHeight) - m_Header.fGeometryHeight;
		TileRect.LowerRight.z = m_Header.fZoom;
	}else {
		TileRect.LowerLeft.x = (m_Header.fGeometryWidth / 2.0f) * (dwMapX - dwMapY) - (m_Header.fGeometryWidth / 2.0f);	
		TileRect.LowerLeft.y = (m_Header.fGeometryHeight / 2.0f) * (dwMapX + dwMapY) - m_Header.fGeometryHeight;
		TileRect.LowerLeft.z = m_Header.fZoom;
		TileRect.UpperLeft.x = (m_Header.fGeometryWidth / 2.0f) * (dwMapX - dwMapY) - (m_Header.fGeometryWidth / 2.0f);
		TileRect.UpperLeft.y = (m_Header.fGeometryHeight / 2.0f) * (dwMapX + dwMapY);
		TileRect.UpperLeft.z = m_Header.fZoom;
		TileRect.LowerRight.x = (m_Header.fGeometryWidth / 2.0f) * (dwMapX - dwMapY) + (m_Header.fGeometryWidth / 2.0f);
		TileRect.LowerRight.y = (m_Header.fGeometryHeight / 2.0f) * (dwMapX + dwMapY) - m_Header.fGeometryHeight;
		TileRect.LowerRight.z = m_Header.fZoom;
		TileRect.UpperRight.x = (m_Header.fGeometryWidth / 2.0f) * (dwMapX - dwMapY) + (m_Header.fGeometryWidth / 2.0f);
		TileRect.UpperRight.y = (m_Header.fGeometryHeight / 2.0f) * (dwMapX + dwMapY);
		TileRect.UpperRight.z = m_Header.fZoom;
	}
	//Prüfen ob sich die Rechtecke überschneiden
	//Das Rechteck wird in 2 Dreiecke zerlegt und das gegen das Tile geprüft
	TRIANGLE Triangle;

	Triangle.LowerLeft = pRect->LowerLeft;
	Triangle.LowerRight = pRect->LowerRight;
	Triangle.UpperCenter = pRect->UpperLeft;
	if(TrianglePointCollision(&(TileRect.LowerLeft), &Triangle)) {
		return true;
	}
	if(TrianglePointCollision(&(TileRect.LowerRight), &Triangle)) {
		return true;
	}
	if(TrianglePointCollision(&(TileRect.UpperLeft), &Triangle)) {
		return true;
	}
	if(TrianglePointCollision(&(TileRect.UpperRight), &Triangle)) {
		return true;
	}

	Triangle.LowerLeft = pRect->UpperLeft;
	Triangle.LowerRight = pRect->LowerRight;
	Triangle.UpperCenter = pRect->UpperRight;
	if(TrianglePointCollision(&(TileRect.LowerLeft), &Triangle)) {
		return true;
	}
	if(TrianglePointCollision(&(TileRect.LowerRight), &Triangle)) {
		return true;
	}
	if(TrianglePointCollision(&(TileRect.UpperLeft), &Triangle)) {
		return true;
	}
	if(TrianglePointCollision(&(TileRect.UpperRight), &Triangle)) {
		return true;
	}
	return false;
}
 
The code converts a tile into a rectangle and checks its edge points against the rectangle which is split into 2 triangles to perform the test. Now the code for the collision test. I have got 2 methods. A fast method which seems to return true every time and a slow method wich selects exactly the wrong tiles...

//Slow version:
bool TrianglePointCollision(D3DVECTOR * pPoint, LPTRIANGLE pTriangle) {
	D3DVECTOR V1, V2, V3;
	float fAngle;

	V1 = NormalizeVector(VectorSubtract(*pPoint, pTriangle->LowerLeft));
	V2 = NormalizeVector(VectorSubtract(*pPoint, pTriangle->LowerRight));
	V3 = NormalizeVector(VectorSubtract(*pPoint, pTriangle->UpperCenter));

	fAngle = acos(DotProduct(V1, V2)) + acos(DotProduct(V2, V3)) + acos(DotProduct(V3, V1));

	if(fabs(fAngle - 2.0f * D3DX_PI) < 0.0001f) {
		return true;
	}
	return false;
}
//Fast version:
bool TrianglePointCollision(D3DVECTOR & rPoint, TRIANGLE & rTriangle) {
	D3DVECTOR V1, V2;

	V1 = CrossProduct(VectorSubtract(rTriangle.UpperCenter, rTriangle.LowerRight), VectorSubtract(rPoint, rTriangle.LowerRight));
	V2 = CrossProduct(VectorSubtract(rTriangle.UpperCenter, rTriangle.LowerRight), VectorSubtract(rTriangle.LowerLeft, rTriangle.LowerRight));

	if(DotProduct(V1, V2) < 0.0f) {
		return false;
	}

	V1 = CrossProduct(VectorSubtract(rTriangle.UpperCenter, rTriangle.LowerLeft), VectorSubtract(rPoint, rTriangle.LowerLeft));
	V2 = CrossProduct(VectorSubtract(rTriangle.UpperCenter, rTriangle.LowerLeft), VectorSubtract(rTriangle.LowerRight, rTriangle.LowerLeft));

	if(DotProduct(V1, V2) < 0.0f) {
		return false;
	}

	V1 = CrossProduct(VectorSubtract(rTriangle.LowerRight, rTriangle.LowerLeft), VectorSubtract(rPoint, rTriangle.LowerLeft));
	V2 = CrossProduct(VectorSubtract(rTriangle.LowerRight, rTriangle.LowerLeft), VectorSubtract(rTriangle.UpperCenter, rTriangle.LowerLeft));

	if(DotProduct(V1, V2) < 0.0f) {
		return false;
	}

	return true;
}
 
Perhaps some of you can help me. So this is the goal: I have got a tile which is represented by 4 untransformed vertices. All tiles have the same Z value. Every bounding rect should have this z-value, too. I need to know if a tile is contained within such a rectangle.
Im Anfang war die Tat...Faust

This topic is closed to new replies.

Advertisement