Jump to content

  • Log In with Google      Sign In   
  • Create Account

Banner advertising on our site currently available from just $5!


1. Learn about the promo. 2. Sign up for GDNet+. 3. Set up your advert!


Drawing terrain starting from the top left


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
16 replies to this topic

#1 Naruto-kun   Members   -  Reputation: 373

Like
0Likes
Like

Posted 15 June 2014 - 09:57 AM

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


Edited by Naruto-kun, 15 June 2014 - 10:04 AM.


Sponsor:

#2 Buckeye   GDNet+   -  Reputation: 10419

Like
0Likes
Like

Posted 15 June 2014 - 02:26 PM


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.


#3 Naruto-kun   Members   -  Reputation: 373

Like
0Likes
Like

Posted 16 June 2014 - 01:23 AM

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.


Edited by Naruto-kun, 16 June 2014 - 01:23 AM.


#4 Krohm   Crossbones+   -  Reputation: 3940

Like
0Likes
Like

Posted 16 June 2014 - 02:16 AM


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.


#5 Naruto-kun   Members   -  Reputation: 373

Like
0Likes
Like

Posted 16 June 2014 - 02:37 AM

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?


Edited by Naruto-kun, 16 June 2014 - 03:01 AM.


#6 Naruto-kun   Members   -  Reputation: 373

Like
0Likes
Like

Posted 16 June 2014 - 03:05 PM

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.


Edited by Naruto-kun, 17 June 2014 - 07:44 AM.


#7 Naruto-kun   Members   -  Reputation: 373

Like
0Likes
Like

Posted 17 June 2014 - 07:02 AM

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

 

grid_wireframe_zps5636180d.png


Edited by Naruto-kun, 17 June 2014 - 07:44 AM.


#8 kauna   Crossbones+   -  Reputation: 2894

Like
0Likes
Like

Posted 17 June 2014 - 09:45 AM

- 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!



#9 Naruto-kun   Members   -  Reputation: 373

Like
0Likes
Like

Posted 17 June 2014 - 11:32 AM

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.


Edited by Naruto-kun, 17 June 2014 - 11:34 AM.


#10 kauna   Crossbones+   -  Reputation: 2894

Like
0Likes
Like

Posted 17 June 2014 - 02:59 PM

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)


Edited by kauna, 17 June 2014 - 03:14 PM.


#11 Naruto-kun   Members   -  Reputation: 373

Like
0Likes
Like

Posted 17 June 2014 - 10:57 PM

The SetVertex and Index buffers part:

CreateBuffers(mvg->dev, &mvg->pVB, &mvg->pIB);
UINT stride = sizeof(VERTS);
UINT offset = 0;
mvg->devcon->IASetVertexBuffers(0, 1, &mvg->pVB, &stride, &offset);
mvg->devcon->IASetIndexBuffer(mvg->pIB, DXGI_FORMAT_R32_UINT, 0);

The input layout:

pFXT = pFX->GetTechniqueByName("RENDER");
if(pFXT)
{
	pFXT->GetDesc(&techDesc);

	D3D11_INPUT_ELEMENT_DESC ied[] = 
	{
		{ "ANCHOR", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
	};
	D3DX11_PASS_DESC PassDesc;
	pFXT->GetPassByIndex(0)->GetDesc( &PassDesc );
	dev->CreateInputLayout( ied, 1,	PassDesc.pIAInputSignature,	PassDesc.IAInputSignatureSize, &pLayout);
}

the draw call:

mvg->devcon->ClearRenderTargetView( mvg->rtv, D3DXCOLOR(0.0f,0.0f,0.0f,1) );
mvg->devcon->ClearDepthStencilView( mvg->dsv, D3D11_CLEAR_DEPTH, 1.0f, 0 );

mvg->devcon->IASetInputLayout( mvg->pLayout );
mvg->devcon->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

mvg->view->SetMatrix(&vMat.m[0][0]);
mvg->prj->SetMatrix(&pMat.m[0][0]);

for( UINT p = 0; p < mvg->techDesc.Passes; p++ )
{
	//apply technique
	mvg->pFXT->GetPassByIndex( p )->Apply(0, mvg->devcon);	

	//draw billboard
	mvg->devcon->DrawIndexed(38400, 0, 0);
}


#12 kauna   Crossbones+   -  Reputation: 2894

Like
0Likes
Like

Posted 18 June 2014 - 07:26 AM

3 (mostly unrelated) things concerning your code but essential when using C++:

 

- you create your temporary vertex and index arrays using new[] so they must be deleted with delete[]. 

- the loop creating indices goes out of bounds, when z=79 and x=79 : 79 * 80 + 79 + 81 > 6399. In this case the maximum loop count should be 79. 

 

bd.ByteWidth = sizeof(ind)*38400; I don't know your target system but this line creates different output on x64 and x86, since the pointer size on each platform is different. You should use sizeof(unsigned long) instead.

 

Cheers!


Edited by kauna, 18 June 2014 - 07:40 AM.


#13 Naruto-kun   Members   -  Reputation: 373

Like
0Likes
Like

Posted 18 June 2014 - 12:10 PM

3 (mostly unrelated) things concerning your code but essential when using C++:

 

- you create your temporary vertex and index arrays using new[] so they must be deleted with delete[]. 

- the loop creating indices goes out of bounds, when z=79 and x=79 : 79 * 80 + 79 + 81 > 6399. In this case the maximum loop count should be 79. 

 

bd.ByteWidth = sizeof(ind)*38400; I don't know your target system but this line creates different output on x64 and x86, since the pointer size on each platform is different. You should use sizeof(unsigned long) instead.

 

Cheers!

 

Thanks. Any other ideas regarding the vertex order/positioning?



#14 Naruto-kun   Members   -  Reputation: 373

Like
0Likes
Like

Posted 19 June 2014 - 06:41 AM

Any ideas?



#15 kauna   Crossbones+   -  Reputation: 2894

Like
0Likes
Like

Posted 22 June 2014 - 06:56 AM

Have you tried to simplify your grid? ie. just draw 1x1 size grid and then 2x2 ....

 

Cheers!



#16 Naruto-kun   Members   -  Reputation: 373

Like
0Likes
Like

Posted 23 June 2014 - 03:45 AM

Good point ill try that.



#17 Naruto-kun   Members   -  Reputation: 373

Like
0Likes
Like

Posted 07 July 2014 - 12:03 AM

found the cause of the problem. Got assbitten by an extra 32 bytes at the end of the row during the image transfer from GPU to system mem. Everything working now.






Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS