Drawing terrain starting from the top left

Started by
15 comments, last by JB3DG 9 years, 9 months ago

Hi guys

Im in a bit of a quandary here. Most of the tutorials I can find on drawing terrain tend to start at the bottom left of the height map.

In my situation, the source elevation data I get starts at the top left. Trying to calculate the pointer offset for the bottom left and looping through it is going to make things an absolute nightmare... Any suggestions on how the vertex order should be set up so as to avoid running into the problem of backface culling? I know I can set the rasterizer to draw the triangles clockwise instead of the default counter clockwise but I am unsure as to what the vertex order in the triangle strip would look like then.

I would like to set things up so that I load only the height map into the shader along with the position of the top left corner, and then adjust the x and z values of the vertex based on a fix resolution using the vertex id number.

Thanks
JB

Advertisement


it is going to make things an absolute nightmare...

Unless you have an overriding reason, you should write code in the most straight-forward manner possible - i.e., that which makes your understanding of it the most logical. Chances are, you will be debugging it or adding to it at some point. In that case, you want to avoid having to go over (and possibly go over again) what your thought process was so you can find errors or add to the code without creating even more of a nightmare. Code for the future, not the present.

If that means changing your input data format, or leaving tutorials behind, I'd suggest you do so. The bitter taste of any bad code will continue long after the satisfaction of "successfully" following a tutorial or using an incompatible addressing scheme has disappeared.

Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly.

You don't forget how to play when you grow old; you grow old when you forget how to play.

Changing the input data format isn't an option since it is generated by another program...That said, I would like to see at least what the vertex order would look like when drawn using clockwise ordering. So far I have only been able to find examples that cover the first 4 verts counterclockwise. Nothing beyond them and nothing in the least giving me an idea of how even a 2D grid would be drawn clockwise.


In my situation, the source elevation data I get starts at the top left. Trying to calculate the pointer offset for the bottom left and looping through it is going to make things an absolute nightmare
If everything fails, just flip it just after loading.

What problem are you having exactly? Would a transform function like ...


uint xrev(uint toRight, uint xMax) {
    return xMax - 1 - toRight;
}

uint *heightmap = load();
uint originHeight = heightmap[xrev(0)];
uint oneSampleRightHeight = heightmap[xrev(1)];
... be sufficient? What is the problem exactly? I cannot understand.

Previously "Krohm"

I wouldn't quite call it a problem. More a uncertainty due to past experiences with other projects.

My idea is to load my source elevation data into a 2DTexture. Then I would simply make the draw call with the number of vertices I wish to use for my terrain grid. In the vertex shader, I would then position the vertices according to their vertex ID and give them their UV coordinates with which I will sample the 2D texture in the vertex shader to give them their Y elevation values. However, if I understand correctly, the order in which I place the vertices based on their ID will determine the direction of the face depending on whether I am using clockwise winding or counter clockwise winding in the rasterizer state. So I would like an idea on how the vertices are placed in a 2D grid starting from the top left and going clockwise.

Ideally for me the vertex ID would start at 0 and increment for each column until the top right vertex, then move down one row and increment again. But im guessing triangle strips don't work that way...Unless there is a way to handle the indexing on shader?

Decided to try drawing just a grid for now based on what I could find on rastertek. In short...not getting anywhere.

Here is my shader:


//blend state
BlendState SrcAlphaBlendingAdd 
{ 
	BlendEnable[0] = TRUE; 
	SrcBlend = SRC_ALPHA; 
	DestBlend = INV_SRC_ALPHA; 
	BlendOp = ADD; 
	SrcBlendAlpha = ZERO; 
	DestBlendAlpha = ZERO; 
	BlendOpAlpha = ADD; 
	RenderTargetWriteMask[0] = 0x0F; 
};

RasterizerState CLR
{
	FillMode = SOLID;
	CullMode = NONE;
	FrontCounterClockwise = false;
	DepthBias = false;
	DepthBiasClamp = 0;
	SlopeScaledDepthBias = 0;
	DepthClipEnable = TRUE;
	ScissorEnable = false;
	MultisampleEnable = false;
	AntialiasedLineEnable = TRUE;
};

//VERTEX AND PIXEL SHADER INPUTS
//--------------------------------------------------------------------------------------
struct SPRITE_INPUT
{
	float2 pos : ANCHOR;
};

//pixel shader inputs
struct PS_INPUT
{
	float4 p : SV_POSITION; 
	float2 t : TEXCOORD;
};

float4x4 view;
float4x4 prj;
float dist = 92.77443083f;

//--------------------------------------------------------------------------------------
// VERTEX SHADER
//--------------------------------------------------------------------------------------
PS_INPUT VS( SPRITE_INPUT input )
{
	PS_INPUT vert;
	float offset = dist*-40.0f;
	if((uint)input.pos.x % 2 == 0)
		vert.t.x = 0;
	else
		vert.t.x = 1;
	if((uint)input.pos.y % 2 == 0)
		vert.t.y = 0;
	else
		vert.t.y = 1;
	vert.p = float4(offset+(input.pos.x*dist), 0, offset+(input.pos.y*dist), 1);

	vert.p = mul(vert.p, view);
	vert.p = mul(vert.p, prj);
	return vert;  
}

//--------------------------------------------------------------------------------------
// PIXEL SHADER
//--------------------------------------------------------------------------------------
float4 PS( PS_INPUT input ) : SV_Target
{ 
	float4 color = float4(1, 1, 1, 1);
	if(input.t.x == 0 && input.t.y == 0)
		color.gb = 0;
	if(input.t.x == 1 && input.t.y == 0)
		color.rb = 0;
	if(input.t.x == 0 && input.t.y == 1)
		color.rg = 0;
	return color;      
}
//--------------------------------------------------------------------------------------
// Techniques
//--------------------------------------------------------------------------------------
technique10 RENDER
{
    pass P0
    {
        SetVertexShader( CompileShader( vs_5_0, VS() ) );
        SetPixelShader( CompileShader( ps_5_0, PS() ) );
        SetBlendState( SrcAlphaBlendingAdd, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF );
	SetRasterizerState(CLR);
    }    
}

Here is the code that loads the vertex and index buffer. Its probably the worst way to set things up but I unfortunately cant seem to find anything that helps.


	VERTS *vert = new VERTS[38400];
	unsigned long *ind = new DWORD[38400];
	int index = 0;
	for(int j = 0; j < 79; j ++)
	{
		for(int i = 0; i < 79; i ++)
		{
			vert[index].x = (float)i;//Upper Left
			vert[index].y = (float)j;
			ind[index] = index;
			index ++;

			vert[index].x = (float)i+1;//Upper Right
			vert[index].y = (float)j;
			ind[index] = index;
			index ++;

			vert[index].x = (float)i+1;//Lower Right
			vert[index].y = (float)j+1;
			ind[index] = index;
			index ++;

			vert[index].x = (float)i+1;//Lower Right
			vert[index].y = (float)j+1;
			ind[index] = index;
			index ++;

			vert[index].x = (float)i;//Lower Left
			vert[index].y = (float)j+1;
			ind[index] = index;
			index ++;

			vert[index].x = (float)i;//Upper Left
			vert[index].y = (float)j;
			ind[index] = index;
			index ++;
		}
	}

	D3D11_BUFFER_DESC bd;
	ZeroMemory(&bd, sizeof(bd));

	bd.Usage = D3D11_USAGE_DEFAULT;
	bd.ByteWidth = sizeof(vert)*38400;
	bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;

	D3D11_SUBRESOURCE_DATA sv;
	ZeroMemory(&sv, sizeof(sv));
	sv.pSysMem = &vert[0];

	dev->CreateBuffer(&bd, &sv, pvb);
	bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
	bd.ByteWidth = sizeof(ind)*38400;
	sv.pSysMem = &ind[0];
	dev->CreateBuffer(&bd, &sv, pib);
	delete vert;
	delete ind;

And here is the result.

grid_zps1064610c.png

If I move or rotate the view matrix position around I get the expected results so it that part is behaving itself. Its pattern that is going bad.

The desired image is a bunch of quads in an orderly 80x80 grid with each corner being a different color.

no ideas? Here is a wireframe of the above shot.

grid_wireframe_zps5636180d.png

- Few points, you want 80x80 grid, but your loop does actually 79x79 grid. The loops should both have <80 instead of <79.

- You create indexes for your trianglemesh, but since each index indexes unique vertex, indexing isn't necessary. You can draw the mesh with draw, no need for drawindexed.

- can you show your program side vertex structure and vertex declaration?

Cheers!

Small change to the order based on another terrain example I found but still the same results.


struct VERTS
{
	float x;
	float y;
};

void CreateBuffers(ID3D11Device* dev, ID3D11Buffer** pvb, ID3D11Buffer** pib)
{
	VERTS *vert = new VERTS[6400];
	unsigned long *ind = new DWORD[38400];
	
	for(int z = 0; z < 80; z ++)
	{
		for(int x = 0; x < 80; x ++)
		{
			vert[x+z*80].x = (float)x;//Upper Left
			vert[x+z*80].y = (float)z;
		}
	}

	int index = 0;
	for(int z = 0; z < 80; z ++)
	{
		for(int x = 0; x < 80; x ++)
		{
			int v = x + (z*80);
			
			ind[index] = v;
			ind[index+1] = v+80;
			ind[index+2] = v+1;

			ind[index+3] = v+1;
			ind[index+4] = v+80;
			ind[index+5] = v+81;
			index += 6;
		}
	}

	D3D11_BUFFER_DESC bd;
	ZeroMemory(&bd, sizeof(bd));

	bd.Usage = D3D11_USAGE_DEFAULT;
	bd.ByteWidth = sizeof(vert)*6400;
	bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;

	D3D11_SUBRESOURCE_DATA sv;
	ZeroMemory(&sv, sizeof(sv));
	sv.pSysMem = &vert[0];

	dev->CreateBuffer(&bd, &sv, pvb);
	bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
	bd.ByteWidth = sizeof(ind)*38400;
	sv.pSysMem = &ind[0];
	dev->CreateBuffer(&bd, &sv, pib);
	delete vert;
	delete ind;
}

I am still only looking to generate a simple grid hence the only values being a XY (or rather on the shader side, XZ). I plan to handle the elevation part by sampling a texture in the vertex shader based on the vertex position in the grid before I multiply it by the scale and add the offset to it.

I position the view matrix at the center of the grid and shift its position around until I update the elevation values again at which point I reset it to the center of the grid.

Can I see your vertex declaration, draw call you make, the code where you set your vertex buffer and index buffer?

Cheers!

ps. with tesselation hardware you could skip almost all the code you have written (although max tesselation per patch is 64x64)

This topic is closed to new replies.

Advertisement