I am reading Introduction to 3d programming with DirectX10 by Frank Luna. At the end of chapter 5 he explains how to render a 3d plane on the xz axis. the following links are links to images of the pages.
http://i159.photobucket.com/albums/t150/numerical25/firstPage.jpg
http://i159.photobucket.com/albums/t150/numerical25/secondPage.jpg
I started off having this post as a question but turns out I am getting a better understanding of what he is doing. I will have particular questions about things I do not understand at the end.
What Frank is trying to do in the code is create a m X n plane laying on the x and z axis. Where n and m represent rows and columns.
Below is the code
//=======================================================================================
// PeaksAndValleys.cpp by Frank Luna (C) 2008 All Rights Reserved.
//=======================================================================================
#include "PeaksAndValleys.h"
#include "Vertex.h"
#include <vector>
PeaksAndValleys::PeaksAndValleys()
: mNumRows(0), mNumCols(0), mNumVertices(0), mNumFaces(0),
md3dDevice(0), mVB(0), mIB(0)
{
}
PeaksAndValleys::~PeaksAndValleys()
{
ReleaseCOM(mVB);
ReleaseCOM(mIB);
}
float PeaksAndValleys::getHeight(float x, float z)const
{
return 0.3f*( z*sinf(0.1f*x) + x*cosf(0.1f*z) );
}
void PeaksAndValleys::init(ID3D10Device* device, DWORD m, DWORD n, float dx)
{
md3dDevice = device;
mNumRows = m;
mNumCols = n;
mNumVertices = m*n;
mNumFaces = (m-1)*(n-1)*2;
// Create the geometry and fill the vertex buffer.
std::vector<Vertex> vertices(mNumVertices);
float halfWidth = (n-1)*dx*0.5f;
float halfDepth = (m-1)*dx*0.5f;
for(DWORD i = 0; i < m; ++i)
{
float z = halfDepth - i*dx;
for(DWORD j = 0; j < n; ++j)
{
float x = -halfWidth + j*dx;
// Graph of this function looks like a mountain range.
float y = getHeight(x,z);
vertices[i*n+j].pos = D3DXVECTOR3(x, y, z);
// Color the vertex based on its height.
if( y < -10.0f )
vertices[i*n+j].color = BEACH_SAND;
else if( y < 5.0f )
vertices[i*n+j].color = LIGHT_YELLOW_GREEN;
else if( y < 12.0f )
vertices[i*n+j].color = DARK_YELLOW_GREEN;
else if( y < 20.0f )
vertices[i*n+j].color = DARKBROWN;
else
vertices[i*n+j].color = WHITE;
}
}
D3D10_BUFFER_DESC vbd;
vbd.Usage = D3D10_USAGE_IMMUTABLE;
vbd.ByteWidth = sizeof(Vertex) * mNumVertices;
vbd.BindFlags = D3D10_BIND_VERTEX_BUFFER;
vbd.CPUAccessFlags = 0;
vbd.MiscFlags = 0;
D3D10_SUBRESOURCE_DATA vinitData;
vinitData.pSysMem = &vertices[0];
HR(md3dDevice->CreateBuffer(&vbd, &vinitData, &mVB));
// Create the index buffer. The index buffer is fixed, so we only
// need to create and set once.
std::vector<DWORD> indices(mNumFaces*3); // 3 indices per face
// Iterate over each quad and compute indices.
int k = 0;
for(DWORD i = 0; i < m-1; ++i)
{
for(DWORD j = 0; j < n-1; ++j)
{
indices[k] = i*n+j;
indices[k+1] = i*n+j+1;
indices[k+2] = (i+1)*n+j;
indices[k+3] = (i+1)*n+j;
indices[k+4] = i*n+j+1;
indices[k+5] = (i+1)*n+j+1;
k += 6; // next quad
}
}
D3D10_BUFFER_DESC ibd;
ibd.Usage = D3D10_USAGE_IMMUTABLE;
ibd.ByteWidth = sizeof(DWORD) * mNumFaces*3;
ibd.BindFlags = D3D10_BIND_INDEX_BUFFER;
ibd.CPUAccessFlags = 0;
ibd.MiscFlags = 0;
D3D10_SUBRESOURCE_DATA iinitData;
iinitData.pSysMem = &indices[0];
HR(md3dDevice->CreateBuffer(&ibd, &iinitData, &mIB));
}
void PeaksAndValleys::update(float dt)
{
}
void PeaksAndValleys::draw()
{
UINT stride = sizeof(Vertex);
UINT offset = 0;
md3dDevice->IASetVertexBuffers(0, 1, &mVB, &stride, &offset);
md3dDevice->IASetIndexBuffer(mIB, DXGI_FORMAT_R32_UINT, 0);
md3dDevice->DrawIndexed(mNumFaces*3, 0, 0);
}
Below I am going to try to break down what he is doing. from within init()
some of The parameters he passed through init() are m and n which hold values of 129 and 129
m and n = rows and columns on the plane.
n = 129
m = 129
dx = 1.0f (This represents the width of each square square. it is 1 unit long by 1 unit wide)
Since each square is equal and height and width, he uses dx to represent both height of width
float halfWidth = (n-1)*dx*0.5f;
float halfDepth = (m-1)*dx*0.5f;
given the information above, we do the following formular
float halfWidth = (129 - 1) = 128 * 1 = 128 * 0.5 = 64
float halfDept = (129 - 1) = 128 * 1 = 128 * 0.5 = 64
so...
float halfWidth = 64;
float halfDept = 64;
Since the plane's origin is at 0,0. to get the top left point he must first divide the plane in half.
float z = halfWidth - i*dx;
(64) = 64 - 0 * 1 = -64
z = 64
then he goes inside the another loop which represents each x column and does the samething
float x = -halfWidth + j*dx;
-1(64) = -64 + 0 * 1 = -64
x = -64
this time he negates 64 so we start off on the left side of the plane and not the right
(j * dx) and (i * dx) in above's code serves as a incrementer. each loop j increments by 1
-1(64) = -64 + 0 * 1 = -64
-1(64) = -64 + 1 * 1 = -63
-1(64) = -64 + 2 * 1 = -62
.....
and below is for the z axis (notice he subtracts (i * 1)
(64) = 64 - 0 * 1 = 64
(64) = 64 - 1 * 1 = 63
(64) = 64 - 2 * 1 = 62
.....
so each loop we move closer to the origin on both axes
each loop he works on all columns before moving on to the next row.
for each column he calls on the getHeight(x,z) function where he passes the current column and row
float PeaksAndValleys::getHeight(float x, float z)const
{
return 0.3f*( z*sinf(0.1f*x) + x*cosf(0.1f*z) );
}
assuming this is the first loop, it does the following
0.3f * (64 * sinf(0.1f*-64) + (-64)*cosf(0.1f*64));
I am not sure what the final answer is cause I am not sure how sinf() and cosf() works but I assume that the farther away from the origin, the bigger the value be on the negative or positive side.
It then returns a value for y and adds the x y and z value to that vertices. depending on how high your y value is, or how low, gives that vector a particular color. the higher it is , the more it turns white like a mountain peak, the lower it is , the more sandy it is like a beach.
after its done, it adds it to the buffer and then adds the indices. If someone could explain why you have to add indices along with the buffer that would be great. and possibly the understanding of sinf and cosf. can't find it on my calculator. But what ever it is, it gives a smooth mountain and valley affect.