Geomipped interpolation

Started by
3 comments, last by GameDev.net 18 years, 9 months ago
So anyway, and I did a quick search to see if this particular issue had arisen and it seems not. I've implemented the whole geomipmapping thing with splatting over the past couple of weeks, and for the most part it works great, and I get lovely framerates, but I still have quite a lot of popping between different mip levels. I've isolated the problem to the fact that on some chunks the value for D is the same for concurrent mip levels, so although I have nice interpolation code in my shader to interpolate between say, mipLevel n and mipLevel n+1, its no good when the terrain instantly skips from n to say, n+3. Its a royal pain in the buttcheeks, and although normally I hate posting on forums to get help, I feel for once I need to, I want to get off this damned terrain which should be the SIMPLE bit of my project and get onto something thats actually interesting. Code? Sure. This is the code for calculating D for each mip level ( C A and T are simple enough and don't need pasting here )

			for(int mip = 1 ; mip < MIPMAPLEVELS ; mip++)
			{
				//the step that this mip takes
				int Step = (int)pow(2.0f, mip);
				float Delta = 0.0f;
				//for each skipped vertice
				for(int subY = StartY + Step ; subY <= StartY + CHUNKSIZE ; subY += Step*2)
				{
					for(int subX = StartX + Step; subX <= StartX + CHUNKSIZE ; subX += Step*2)
					{
						//skipped center vertices height
						float height = m_pHeightMap[subX + subY*m_iRealMapWidth];

						//check diagonal
						//top left to bottom right
						Delta = max( Delta, abs( height - ( m_pHeightMap[(subX-Step) + (subY-Step)*m_iRealMapWidth] + m_pHeightMap[(subX+Step) + (subY+Step)*m_iRealMapWidth])/2.0f));
						//top right to bottom left
						Delta = max( Delta, abs( height - ( m_pHeightMap[(subX+Step) + (subY-Step)*m_iRealMapWidth] + m_pHeightMap[(subX-Step) + (subY+Step)*m_iRealMapWidth])/2.0f));

						//check left node ( Top and bottom )
						height = m_pHeightMap[(subX-Step) + subY*m_iRealMapWidth];
						Delta = max(Delta, abs(height - (m_pHeightMap[(subX - Step) + (subY - Step)*m_iRealMapWidth] + m_pHeightMap[(subX - Step) + (subY + Step)*m_iRealMapWidth])/2.0f));


						//check right node ( Top and Bottom )
						height = m_pHeightMap[(subX + Step) + (subY)*m_iRealMapWidth];
						Delta = max(Delta, abs( height - (m_pHeightMap[(subX + Step) + (subY - Step)*m_iRealMapWidth] + m_pHeightMap[(subX + Step) + (subY + Step)*m_iRealMapWidth])/2.0f));


						//check top node ( Left and Right )
						height = m_pHeightMap[subX + (subY - Step)*m_iRealMapWidth];
						Delta = max(Delta, abs( height - (m_pHeightMap[(subX-Step) + (subY-Step)*m_iRealMapWidth] + m_pHeightMap[(subX+Step) + (subY-Step)*m_iRealMapWidth])/2.0f));

						//check bottom node ( Left and Right)
						height = m_pHeightMap[subX + (subY - Step)*m_iRealMapWidth];
						Delta = max(Delta, abs( height - (m_pHeightMap[(subX-Step) + (subY+Step)*m_iRealMapWidth] + m_pHeightMap[(subX+Step) + (subY+Step)*m_iRealMapWidth])/2.0f));
					}
				}				
				//Dn^2 ( So the distance doesn't need to be square rooted every frame
				m_pBlocks[x + y*m_iChunksWidth].minDis[mip] = (Delta*Delta) * ( C * C );
			}


And this is the code for calculating which mip to use:

			for(int mip = 0 ; mip < MIPMAPLEVELS ; mip++)
				{
					if(dist > m_pBlocks[chunkID].minDis[mip])
						m_pBlocks[chunkID].currentLevel = mip;
					else
						break;					
				}
				if(m_pBlocks[chunkID].currentLevel == MIPMAPLEVELS-1)
				{
					m_pBlocks[chunkID].interpolationValue = 0.0f;
				}
				else
				{
					m_pBlocks[chunkID].interpolationValue = (dist - m_pBlocks[chunkID].minDis[m_pBlocks[chunkID].currentLevel])/(m_pBlocks[chunkID].minDis[m_pBlocks[chunkID].currentLevel+1] - m_pBlocks[chunkID].minDis[m_pBlocks[chunkID].currentLevel]);
				}


Now, I've had some ideas for smooth interpolation for when it jumps between multiple levels in one go - for instance doing interpolation from mip 0 to mip nMax instead of per mip ( based on weighting per mip ). Failing that, just using magic numbers for the D values. Neither of these is truely satisfactory though, at least not in the any way i managed to implement it. Anyone come across this problem before? How did you solve it? (Yes, the terrain is quite bumpy, hence the skipping of multiple mips ), but it will be scaled out and nothing like as bad as it is now, I'd just prefer to have it work as it is now so when I scale it, it will look even more beautiful ). And apologies for asking 'yet another question about geomipmapping' :)
http://www.codeofrob.com
Advertisement
Well, there is maybe a couple bugs.

The first is really minor:
//check bottom node ( Left and Right)height = m_pHeightMap[subX + (subY - Step)*m_iRealMapWidth];

I feel like that should be (subY + Step) instead.

Second might be on purpose, I can't tell without more code:
you assign to minDis the Distance squared, but then you linearly interpolate it like it's not squared. This wouldn't probably cause bugs, just irregularities in the interpolation. I only bring it up because you say:
if(dist > m_pBlocks[chunkID].minDis[mip])

and if you do that, then certainly dist is really the dist-squared value.

and Third is mostly asthetic:
int Step = (int)pow(2.0f, mip);

You cast mip to double, then 2.0f to double, then pow and recast back to int... I mean you are right on the cusp of some bad stuff, though probably in your data range it will be fine.

So in the end, that probably wasn't much help :)
Minor bug fixes are always good :)

dist is indeed squared - I just have bad local variable naming conventions.

And yeaugh, how did I miss that bottom node check? Not that it changes anything except being more accurate - but oops :p

I didn't think interpolating with the squared values would really matter, as they're all squared I'd still get a value between 0 and 1, but I guess I should tidy that up anyway.

As for the good old pow call, I'll fix that somewhen, it is untidy.

(I've now changed all my diagonals to only sample between top right and bottom left to reflect my vertice order - it makes for really smooth interpolation with magic dist values ).
http://www.codeofrob.com
Apologies for the double post, but I may as well leave a solution here should anyone come looking.

Its a bit of a hack fix, but basically, whatever distance I get for a mip level, I add it on to the distance needed for the previous mip level.

This is a far better approach than simply using 'magic numbers', and it means that you still get a good drop in detail as distance increases so the face number remains low.

I can't see any popping at all, and thats on my bumpy terrain, so there you go.

I'll keep watching this thread, any better solutions are welcome.
http://www.codeofrob.com

int Step = (int)pow(2.0f, mip);


int Step = 1 <

This topic is closed to new replies.

Advertisement