I'm trying to render a map, but unfortunately, only the underside is rendered.
I guess I'm doing something wrong while setting up the vertex and index buffers.
This is the part I initialize the vertex and index buffers:
// Initialize vertices and indices
SimpleVertex* vertices = new SimpleVertex[(dimension + 1) * (dimension + 1)];
WORD* indices = new WORD[dimension * dimension * 6];
for (WORD i = 0; i < dimension + 1; ++i)
{
for (WORD j = 0; j < dimension + 1; ++j)
{
vertices[i * (dimension + 1) + j].Pos = XMFLOAT3(i, rand() % 2, j);
vertices[i * (dimension + 1) + j].Color = XMFLOAT4(rand() % 2, rand() % 2, rand() % 2, 1.0f);
}
}
for (WORD i = 0; i < dimension; i++)
{
for (WORD j = 0; j < dimension; j++)
{
indices[(i * dimension + j) * 6] = (WORD)(i * (dimension + 1) + j);
indices[(i * dimension + j) * 6 + 2] = (WORD)(i * (dimension + 1) + j + 1);
indices[(i * dimension + j) * 6 + 1] = (WORD)((i + 1) * (dimension + 1) + j + 1);
indices[(i * dimension + j) * 6 + 3] = (WORD)(i * (dimension + 1) + j);
indices[(i * dimension + j) * 6 + 5] = (WORD)((i + 1) * (dimension + 1) + j + 1);
indices[(i * dimension + j) * 6 + 4] = (WORD)((i + 1) * (dimension + 1) + j);
}
}
// Create vertex buffer
D3D11_BUFFER_DESC bd;
ZeroMemory(&bd, sizeof(bd));
bd.Usage = D3D11_USAGE_DEFAULT;
bd.ByteWidth = sizeof(SimpleVertex)* (dimension + 1) * (dimension + 1);
bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bd.CPUAccessFlags = 0;
D3D11_SUBRESOURCE_DATA InitData;
ZeroMemory(&InitData, sizeof(InitData));
InitData.pSysMem = vertices;
hr = g_pd3dDevice->CreateBuffer(&bd, &InitData, &g_pVertexBuffer);
delete vertices;
if (FAILED(hr))
return hr;
// Set vertex buffer
UINT stride = sizeof(SimpleVertex);
UINT offset = 0;
g_pImmediateContext->IASetVertexBuffers(0, 1, &g_pVertexBuffer, &stride, &offset);
// Create indices buffer
bd.Usage = D3D11_USAGE_DEFAULT;
bd.ByteWidth = sizeof(WORD)* dimension * dimension * 6;
bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
bd.CPUAccessFlags = 0;
InitData.pSysMem = indices;
hr = g_pd3dDevice->CreateBuffer(&bd, &InitData, &g_pIndexBuffer);
delete indices;
if (FAILED(hr))
return hr;
Excuses for my bad English :(. Thank you for reading!
The first thing that occurred to me is you may be declaring your vertices in the wrong order. If your Direct3D context is expecting vertices to be counterclockwise, and yours are defined in clockwise order, "backface culling" will cause your polygons to be invisible unless viewed from the other side.
Specifically, D3D11_RASTERIZER_DESC::FrontCounterClockwise sets the direction. (see http://msdn.microsoft.com/en-us/library/windows/desktop/ff476198%28v=vs.85%29.aspx)
In the code where you set up your rasterizer description, try setting CullMode=D3D11_CULL_NONE and if the terrain appears, then this was your problem.
Most likely, the face culling wasn't set up properly.
In theory (thanks Google for providing links ;) ):
Face culling
Winding order
In practice:
You decide in which order to put your vertices within triangles (in reality, you manipulating with indices, as your buffers are indexed) - clockwise or counterclockwise.
Having decision #1 you now decide which faces must be considered as "front":
D3D11_RASTERIZER_DESC rd = {};
rd.FrontCounterClockwise = true; // counterclockwise are front
and you decide which faces rasterizer must cull: back ones, front ones, or none:
rd.CullMode = D3D11_CULL_BACK; // back faced primitives will be stripped out
// during rasterization
// (clockwise ones in our example)
So, you can either change your geometry winding and/or DirectX winding option and/or DirectX culling option.
Note: By-default, DirectX 11 uses false and D3D11_CULL_BACK for parameters above. So it considers clockwise primitives as front faced, and culls counterclockwise ones, considered back faced.
Note: To better understand culling, draw a triangle on both sides of piece of paper as if it would be same triangle viewed from different sides. Put indices near each vertex (same on both sides of paper). Draw an circular arrow showing winding order. Compare it with your mesh. Then it will be obvious which winding order and culling you must use.
Sources:
MSDN DirectX Reference pages:
D3D11_RASTERIZER_DESC
D3D11_CULL_MODE
ID3D11Device::CreateRasterizerState()
ID3D11DeviceContext::RSSetState()
Related
I tried the code below, but I have incorrect indices. I'm trying to render lines using CGAL and 3D Delaunay, but I get correct indices. It was hard to get the indices of the 3D Delaunay. I don't know which part is wrong, I try with 4 vertices, it looks correct, but with more than 5 indices I get wrong triangles...
std::vector<int> triangles;
std::map<Delaunay3::Vertex_handle, int> index_of_vertex;
int j = 0;
for (Delaunay3::Finite_vertices_iterator it = dt.finite_vertices_begin();
it != dt.finite_vertices_end(); ++it, ++j) {
index_of_vertex[it.base()] = j;
}
for (Delaunay3::Finite_facets_iterator itFacet = dt.finite_facets_begin();
itFacet != dt.finite_facets_end(); itFacet++) {
triangles.push_back(index_of_vertex[itFacet->first->vertex(0)]);
triangles.push_back(index_of_vertex[itFacet->first->vertex(1)]);
triangles.push_back(index_of_vertex[itFacet->first->vertex(2)]);
triangles.push_back(index_of_vertex[itFacet->first->vertex(0)]);
triangles.push_back(index_of_vertex[itFacet->first->vertex(2)]);
triangles.push_back(index_of_vertex[itFacet->first->vertex(3)]);
triangles.push_back(index_of_vertex[itFacet->first->vertex(1)]);
triangles.push_back(index_of_vertex[itFacet->first->vertex(2)]);
triangles.push_back(index_of_vertex[itFacet->first->vertex(3)]);
}
std::vector<WORD> lineIndex;
lineIndex.resize(triangles.size() * sizeof(int) * 4);
int l, t;
for (l = 0, t = 0; t < triangles.size(); t += 4) {
// Each triangle has 3 lines, so D3D_PRIMITIVE_TOPOLOGY_LINELIST needs 6 vertices
// Each vertex has to be listed twice
lineIndex[l] = triangles[t];
l++;
lineIndex[l] = triangles[t + 1];
l++;
lineIndex[l] = triangles[t + 1];
l++;
lineIndex[l] = triangles[t + 2];
l++;
lineIndex[l] = triangles[t + 2];
l++;
lineIndex[l] = triangles[t];
l++;
}
// Fill in a buffer description for drawing only the triangle outlines
ZeroMemory(&bd, sizeof(bd));
bd.Usage = D3D11_USAGE_DEFAULT;
bd.ByteWidth = numTriangleVertices * 3 * sizeof(int); // <---- from the function
bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
bd.CPUAccessFlags = 0;
ZeroMemory(&InitData, sizeof(InitData));
InitData.pSysMem = static_cast<void*>(lineIndex.data());
pd3dDevice->CreateBuffer(&bd, &InitData, &g_pTriOutlineIndexBuffer);
Let me explain it with a triangulation with only 4 non-coplanar vertices.
You then have 4 finite facets. Each of them is represented as a std::pair<Delaunay3::Cell_handle, int> pair;, where pair. first is the cell incident to the facet and pair.second is the index of the vertex opposite to the facet in the cell.
If pair.second == 0, the indices of the vertices of the facet are 1,2,3;
If pair.second == 1, the indices of the vertices of the facet are 2,3,0; etc.
That is in general, f pair.second == i, the indices of the vertices of the facet are (i+1)%4, (i+2)%4, (i+3)%4
There is also a helper class, which is the base class of the triangulations
https://doc.cgal.org/latest/TDS_3/classCGAL_1_1Triangulation__utils__3.html
It allows you to write Delaunay_3::vertex_triple_index(i,j).
I agree that this is not well documented at all, and we are going to improve that.
I've implemented the Marching Cube algorithm in a DirectX environment (To test and have fun). Upon completion, I noticed that the resulting model looks heavily distorted, as if the indices were off.
I've attempted to extract the indices, but I think the vertices are ordered correctly already, using the lookup tables, examples at http://paulbourke.net/geometry/polygonise/ . The current build uses a 15^3 volume.
Marching cubes iterates over the array as normal:
for (float iX = 0; iX < CellFieldSize.x; iX++){
for (float iY = 0; iY < CellFieldSize.y; iY++){
for (float iZ = 0; iZ < CellFieldSize.z; iZ++){
MarchCubes(XMFLOAT3(iX*StepSize, iY*StepSize, iZ*StepSize), StepSize);
}
}
}
The MarchCube function is called:
void MC::MarchCubes(){
...
int Corner, Vertex, VertexTest, Edge, Triangle, FlagIndex, EdgeFlags;
float Offset;
XMFLOAT3 Color;
float CubeValue[8];
XMFLOAT3 EdgeVertex[12];
XMFLOAT3 EdgeNorm[12];
//Local copy
for (Vertex = 0; Vertex < 8; Vertex++) {
CubeValue[Vertex] = (this->*fSample)(
in_Position.x + VertexOffset[Vertex][0] * Scale,
in_Position.y + VertexOffset[Vertex][1] * Scale,
in_Position.z + VertexOffset[Vertex][2] * Scale
);
}
FlagIndex = 0;
Intersection calculations:
...
//Test vertices for intersection.
for (VertexTest = 0; VertexTest < 8; VertexTest++){
if (CubeValue[VertexTest] <= TargetValue)
FlagIndex |= 1 << VertexTest;
}
//Find which edges are intersected by the surface.
EdgeFlags = CubeEdgeFlags[FlagIndex];
if (EdgeFlags == 0){
return;
}
for (Edge = 0; Edge < 12; Edge++){
if (EdgeFlags & (1 << Edge)) {
Offset = GetOffset(CubeValue[EdgeConnection[Edge][0]], CubeValue[EdgeConnection[Edge][1]], TargetValue); // Get offset function definition. Needed!
EdgeVertex[Edge].x = in_Position.x + VertexOffset[EdgeConnection[Edge][0]][0] + Offset * EdgeDirection[Edge][0] * Scale;
EdgeVertex[Edge].y = in_Position.y + VertexOffset[EdgeConnection[Edge][0]][1] + Offset * EdgeDirection[Edge][1] * Scale;
EdgeVertex[Edge].z = in_Position.z + VertexOffset[EdgeConnection[Edge][0]][2] + Offset * EdgeDirection[Edge][2] * Scale;
GetNormal(EdgeNorm[Edge], EdgeVertex[Edge].x, EdgeVertex[Edge].y, EdgeVertex[Edge].z); //Need normal values
}
}
And the original implementation gets pushed into a holding struct for DirectX.
for (Triangle = 0; Triangle < 5; Triangle++) {
if (TriangleConnectionTable[FlagIndex][3 * Triangle] < 0) break;
for (Corner = 0; Corner < 3; Corner++) {
Vertex = TriangleConnectionTable[FlagIndex][3 * Triangle + Corner];3 * Triangle + Corner]);
GetColor(Color, EdgeVertex[Vertex], EdgeNorm[Vertex]);
Data.VertexData.push_back(XMFLOAT3(EdgeVertex[Vertex].x, EdgeVertex[Vertex].y, EdgeVertex[Vertex].z));
Data.NormalData.push_back(XMFLOAT3(EdgeNorm[Vertex].x, EdgeNorm[Vertex].y, EdgeNorm[Vertex].z));
Data.ColorData.push_back(XMFLOAT4(Color.x, Color.y, Color.z, 1.0f));
}
}
(This is the same ordering as the original GL implementation)
Turns out, I missed a parenthesis showing operator precedence.
EdgeVertex[Edge].x = in_Position.x + (VertexOffset[EdgeConnection[Edge][0]][0] + Offset * EdgeDirection[Edge][0]) * Scale;
EdgeVertex[Edge].y = in_Position.y + (VertexOffset[EdgeConnection[Edge][0]][1] + Offset * EdgeDirection[Edge][1]) * Scale;
EdgeVertex[Edge].z = in_Position.z + (VertexOffset[EdgeConnection[Edge][0]][2] + Offset * EdgeDirection[Edge][2]) * Scale;
Corrected, obtained Visine; resumed fun.
I'm working on just making uniformly colors spheres for a project and I'm running into an issue. The spheres run fine but when I try to color them with glColorPointer they stop appearing. OpenGL isn't showing any errors when I call glGetError so I'm at a loss for why this would happen.
The code to generate the vertices, colors etc:
void SphereObject::setupVertices()
{
//determine the array sizes
//vertices per row (+1 for the repeated one at the end) * three for each coordinate
//times the number of rows
int arraySize = myNumVertices * 3;
myNumIndices = (myVerticesPerRow + 1) * myRows * 2;
myVertices = new GLdouble[arraySize];
myIndices = new GLuint[myNumIndices];
myNormals = new GLdouble[arraySize];
myColors = new GLint[myNumVertices * 4];
//use spherical coordinates to calculate the vertices
double phiIncrement = 360 / myVerticesPerRow;
double thetaIncrement = 180 / (double)myRows;
int arrayIndex = 0;
int colorArrayIndex = 0;
int indicesIndex = 0;
double x, y, z = 0;
for(double theta = 0; theta <= 180; theta += thetaIncrement)
{
//loop including the repeat for the last vertex
for(double phi = 0; phi <= 360; phi += phiIncrement)
{
//make sure that the last vertex is repeated
if(360 - phi < phiIncrement)
{
x = myRadius * sin(radians(theta)) * cos(radians(0));
y = myRadius * sin(radians(theta)) * sin(radians(0));
z = myRadius * cos(radians(theta));
}
else
{
x = myRadius * sin(radians(theta)) * cos(radians(phi));
y = myRadius * sin(radians(theta)) * sin(radians(phi));
z = myRadius * cos(radians(theta));
}
myColors[colorArrayIndex] = myColor.getX();
myColors[colorArrayIndex + 1] = myColor.getY();
myColors[colorArrayIndex + 2] = myColor.getZ();
myColors[colorArrayIndex + 3] = 1;
myVertices[arrayIndex] = x;
myVertices[arrayIndex + 1] = y;
myVertices[arrayIndex + 2] = z;
if(theta <= 180 - thetaIncrement)
{
myIndices[indicesIndex] = arrayIndex / 3;
myIndices[indicesIndex + 1] = (arrayIndex / 3) + myVerticesPerRow + 1;
indicesIndex += 2;
}
arrayIndex += 3;
colorArrayIndex += 4;
}
}
}
And the code to actually render the thing
void SphereObject::render()
{
glPushMatrix();
glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT);
glEnableClientState(GL_COLOR_ARRAY);
glColorPointer(4, GL_INT, 0, myColors);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_DOUBLE, 0, myVertices);
glDrawElements(GL_QUAD_STRIP, myNumIndices, GL_UNSIGNED_INT, myIndices);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glPopClientAttrib();
glPopMatrix();
}
Any and all help would be appreciated. I'm really having a hard time for some reason.
When you use GL_INT (or any integer type) for color pointer, it linearly maps the largest possible integer value to 1.0f (maximum color), and 0 to 0.0f (minimum color).
Therefore unless your values of RGB and A are in the billions, they will likely appear completely black (or transparent if that's enabled). I see that you've got alpha = 1, which will essentially be zero after conversion to float.
I am currently making a method to load in a noisy heightmap, but lack the triangles to do so. I want to make an algorithm that will take an image, its width and height and construct a terrain node out of it.
Here's what I have so far, in somewhat pseudo
Vertex* vertices = new Vertices[image.width * image.height];
Index* indices; // How do I judge how many indices I will have?
float scaleX = 1 / image.width;
float scaleY = 1 / image.height;
float currentYScale = 0;
for(int y = 0; y < image.height; ++y) {
float currentXScale = 0;
for (int x = 0; x < image.width; ++x) {
Vertex* v = vertices[x * y];
v.x = currentXScale;
v.y = currentYScale;
v.z = image[x,y];
currentXScale += scaleX;
}
currentYScale += scaleY;
}
This works well enough to my needs, my only problem is this: How would I calculate the # of indices and their positions for drawing the triangles? I have somewhat familiarity with indices, but not how to programmatically calculate them, I can only do that statically.
As far as your code above goes, using vertices[x * y] isn't right - if you use that, then e.g. vert(2,3) == vert(3,2). What you want is something like vertices[y * image.width + x], but you can do it more efficiently by incrementing a counter (see below).
Here's the equivalent code I use. It's in C# unfortunately, but hopefully it should illustrate the point:
/// <summary>
/// Constructs the vertex and index buffers for the terrain (for use when rendering the terrain).
/// </summary>
private void ConstructBuffers()
{
int heightmapHeight = Heightmap.GetLength(0);
int heightmapWidth = Heightmap.GetLength(1);
int gridHeight = heightmapHeight - 1;
int gridWidth = heightmapWidth - 1;
// Construct the individual vertices for the terrain.
var vertices = new VertexPositionTexture[heightmapHeight * heightmapWidth];
int vertIndex = 0;
for(int y = 0; y < heightmapHeight; ++y)
{
for(int x = 0; x < heightmapWidth; ++x)
{
var position = new Vector3(x, y, Heightmap[y,x]);
var texCoords = new Vector2(x * 2f / heightmapWidth, y * 2f / heightmapHeight);
vertices[vertIndex++] = new VertexPositionTexture(position, texCoords);
}
}
// Create the vertex buffer and fill it with the constructed vertices.
this.VertexBuffer = new VertexBuffer(Renderer.GraphicsDevice, typeof(VertexPositionTexture), vertices.Length, BufferUsage.WriteOnly);
this.VertexBuffer.SetData(vertices);
// Construct the index array.
var indices = new short[gridHeight * gridWidth * 6]; // 2 triangles per grid square x 3 vertices per triangle
int indicesIndex = 0;
for(int y = 0; y < gridHeight; ++y)
{
for(int x = 0; x < gridWidth; ++x)
{
int start = y * heightmapWidth + x;
indices[indicesIndex++] = (short)start;
indices[indicesIndex++] = (short)(start + 1);
indices[indicesIndex++] = (short)(start + heightmapWidth);
indices[indicesIndex++] = (short)(start + 1);
indices[indicesIndex++] = (short)(start + 1 + heightmapWidth);
indices[indicesIndex++] = (short)(start + heightmapWidth);
}
}
// Create the index buffer.
this.IndexBuffer = new IndexBuffer(Renderer.GraphicsDevice, typeof(short), indices.Length, BufferUsage.WriteOnly);
this.IndexBuffer.SetData(indices);
}
I guess the key point is that given a heightmap of size heightmapHeight * heightmapWidth, you need (heightmapHeight - 1) * (heightmapWidth - 1) * 6 indices, since you're drawing:
2 triangles per grid square
3 vertices per triangle
(heightmapHeight - 1) * (heightmapWidth - 1) grid squares in your terrain.
well I think I know what the problem is. I am just having a hard time debugging it. I am working with the directx api and I am trying to generate a plane along the x and z axis according to a book I have. The problem is when I am creating my indices. I think I am setting values out of the bounds of the indices array. I am just having a hard time figuring out what I did wrong. I am unfamiliar with the this method of generating a plane. so its a little difficult for me. below is my code. Take emphasis on the indices loop.
[edit]
Ive been reviewing it. This is how the indices works
int curVertex = x + (z * NUM_VERTSX);
This always gets the beginning vertices. so say we have 17 vertices on the x axis and 17 vertices on the z axis and we are on the first loop of the x and z axis
curVertx = 0 + (0 * 17)
curVertx = 0 + 0 = 0
say we are on the first loop of the z axis and second loop of the x axis
curVertx = 1 + (0 * 17)
curVertx = 1+ 0 = 1
indices[curIndex] = curVertex;
indices[curIndex + 1] = curVertex + NUM_VERTSX;
indices[curIndex + 2] = curVertex + 1;
indices[curIndex + 3] = curVertex + 1;
indices[curIndex + 4] = curVertex + NUM_VERTSX;
indices[curIndex + 5] = curVertex + NUM_VERTSX + 1;
if we are on the first
loop indices[curIndex] = curVertex;
this equals the first vertex = 0.
indices[curIndex + 1] = curVertex + NUM_VERTSX;
this equals the second row vertices (its always the vertices below the starting vertices
x x x x
[x] x x x
#include "MyGame.h"
//#include "CubeVector.h"
/* This code sets a projection and shows a turning cube. What has been added is the project, rotation and
a rasterizer to change the rasterization of the cube. The issue that was going on was something with the effect file
which was causing the vertices not to be rendered correctly.*/
typedef struct
{
ID3D10Effect* pEffect;
ID3D10EffectTechnique* pTechnique;
//vertex information
ID3D10Buffer* pVertexBuffer;
ID3D10Buffer* pIndicesBuffer;
ID3D10InputLayout* pVertexLayout;
UINT numVertices;
UINT numIndices;
}ModelObject;
ModelObject modelObject;
// World Matrix
D3DXMATRIX WorldMatrix;
// View Matrix
D3DXMATRIX ViewMatrix;
// Projection Matrix
D3DXMATRIX ProjectionMatrix;
ID3D10EffectMatrixVariable* pProjectionMatrixVariable = NULL;
//grid information
#define NUM_COLS 16
#define NUM_ROWS 16
#define CELL_WIDTH 32
#define CELL_HEIGHT 32
#define NUM_VERTSX (NUM_COLS + 1)
#define NUM_VERTSY (NUM_ROWS + 1)
bool MyGame::InitDirect3D()
{
if(!DX3dApp::InitDirect3D())
{
return false;
}
D3D10_RASTERIZER_DESC rastDesc;
rastDesc.FillMode = D3D10_FILL_WIREFRAME;
rastDesc.CullMode = D3D10_CULL_FRONT;
rastDesc.FrontCounterClockwise = true;
rastDesc.DepthBias = false;
rastDesc.DepthBiasClamp = 0;
rastDesc.SlopeScaledDepthBias = 0;
rastDesc.DepthClipEnable = false;
rastDesc.ScissorEnable = false;
rastDesc.MultisampleEnable = false;
rastDesc.AntialiasedLineEnable = false;
ID3D10RasterizerState *g_pRasterizerState;
mpD3DDevice->CreateRasterizerState(&rastDesc, &g_pRasterizerState);
mpD3DDevice->RSSetState(g_pRasterizerState);
// Set up the World Matrix
D3DXMatrixIdentity(&WorldMatrix);
D3DXMatrixLookAtLH(&ViewMatrix, new D3DXVECTOR3(0.0f, 10.0f, -20.0f), new D3DXVECTOR3(0.0f, 0.0f, 0.0f), new D3DXVECTOR3(0.0f, 1.0f, 0.0f));
// Set up the projection matrix
D3DXMatrixPerspectiveFovLH(&ProjectionMatrix, (float)D3DX_PI * 0.5f, (float)mWidth/(float)mHeight, 0.1f, 100.0f);
if(!CreateObject())
{
return false;
}
return true;
}
//These are actions that take place after the clearing of the buffer and before the present
void MyGame::GameDraw()
{
static float rotationAngle = 0.0f;
// create the rotation matrix using the rotation angle
D3DXMatrixRotationY(&WorldMatrix, rotationAngle);
rotationAngle += (float)D3DX_PI * 0.0f;
// Set the input layout
mpD3DDevice->IASetInputLayout(modelObject.pVertexLayout);
// Set vertex buffer
UINT stride = sizeof(VertexPos);
UINT offset = 0;
mpD3DDevice->IASetVertexBuffers(0, 1, &modelObject.pVertexBuffer, &stride, &offset);
mpD3DDevice->IASetIndexBuffer(modelObject.pIndicesBuffer, DXGI_FORMAT_R32_UINT, 0);
// Set primitive topology
mpD3DDevice->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
// Combine and send the final matrix to the shader
D3DXMATRIX finalMatrix = (WorldMatrix * ViewMatrix * ProjectionMatrix);
pProjectionMatrixVariable->SetMatrix((float*)&finalMatrix);
// make sure modelObject is valid
// Render a model object
D3D10_TECHNIQUE_DESC techniqueDescription;
modelObject.pTechnique->GetDesc(&techniqueDescription);
// Loop through the technique passes
for(UINT p=0; p < techniqueDescription.Passes; ++p)
{
modelObject.pTechnique->GetPassByIndex(p)->Apply(0);
// draw the cube using all 36 vertices and 12 triangles
mpD3DDevice->DrawIndexed(modelObject.numIndices,0,0);
}
}
//Render actually incapsulates Gamedraw, so you can call data before you actually clear the buffer or after you
//present data
void MyGame::Render()
{
DX3dApp::Render();
}
bool MyGame::CreateObject()
{
VertexPos vertices[NUM_VERTSX * NUM_VERTSY];
for(int z=0; z < NUM_VERTSY; ++z)
{
for(int x = 0; x < NUM_VERTSX; ++x)
{
vertices[x + z * NUM_VERTSX].pos.x = (float)x * CELL_WIDTH;
vertices[x + z * NUM_VERTSX].pos.z = (float)z * CELL_HEIGHT;
vertices[x + z * NUM_VERTSX].pos.y = 0.0f;
vertices[x + z * NUM_VERTSX].color = D3DXVECTOR4(1.0, 0.0f, 0.0f, 0.0f);
}
}
DWORD indices[NUM_VERTSX * NUM_VERTSY];
int curIndex = 0;
for(int z=0; z < NUM_ROWS; ++z)
{
for(int x = 0; x < NUM_COLS; ++x)
{
int curVertex = x + (z * NUM_VERTSX);
indices[curIndex] = curVertex;
indices[curIndex + 1] = curVertex + NUM_VERTSX;
indices[curIndex + 2] = curVertex + 1;
indices[curIndex + 3] = curVertex + 1;
indices[curIndex + 4] = curVertex + NUM_VERTSX;
indices[curIndex + 5] = curVertex + NUM_VERTSX + 1;
curIndex += 6;
}
}
//Create Layout
D3D10_INPUT_ELEMENT_DESC layout[] = {
{"POSITION",0,DXGI_FORMAT_R32G32B32_FLOAT, 0 , 0, D3D10_INPUT_PER_VERTEX_DATA, 0},
{"COLOR",0,DXGI_FORMAT_R32G32B32A32_FLOAT, 0 , 12, D3D10_INPUT_PER_VERTEX_DATA, 0}
};
UINT numElements = (sizeof(layout)/sizeof(layout[0]));
modelObject.numVertices = sizeof(vertices)/sizeof(VertexPos);
//Create buffer desc
D3D10_BUFFER_DESC bufferDesc;
bufferDesc.Usage = D3D10_USAGE_DEFAULT;
bufferDesc.ByteWidth = sizeof(VertexPos) * modelObject.numVertices;
bufferDesc.BindFlags = D3D10_BIND_VERTEX_BUFFER;
bufferDesc.CPUAccessFlags = 0;
bufferDesc.MiscFlags = 0;
D3D10_SUBRESOURCE_DATA initData;
initData.pSysMem = vertices;
//Create the buffer
HRESULT hr = mpD3DDevice->CreateBuffer(&bufferDesc, &initData, &modelObject.pVertexBuffer);
if(FAILED(hr))
return false;
modelObject.numIndices = sizeof(indices)/sizeof(DWORD);
bufferDesc.ByteWidth = sizeof(DWORD) * modelObject.numIndices;
bufferDesc.BindFlags = D3D10_BIND_INDEX_BUFFER;
initData.pSysMem = indices;
hr = mpD3DDevice->CreateBuffer(&bufferDesc, &initData, &modelObject.pIndicesBuffer);
if(FAILED(hr))
return false;
/////////////////////////////////////////////////////////////////////////////
//Set up fx files
LPCWSTR effectFilename = L"effect.fx";
modelObject.pEffect = NULL;
hr = D3DX10CreateEffectFromFile(effectFilename,
NULL,
NULL,
"fx_4_0",
D3D10_SHADER_ENABLE_STRICTNESS,
0,
mpD3DDevice,
NULL,
NULL,
&modelObject.pEffect,
NULL,
NULL);
if(FAILED(hr))
return false;
pProjectionMatrixVariable = modelObject.pEffect->GetVariableByName("Projection")->AsMatrix();
//Dont sweat the technique. Get it!
LPCSTR effectTechniqueName = "Render";
modelObject.pTechnique = modelObject.pEffect->GetTechniqueByName(effectTechniqueName);
if(modelObject.pTechnique == NULL)
return false;
//Create Vertex layout
D3D10_PASS_DESC passDesc;
modelObject.pTechnique->GetPassByIndex(0)->GetDesc(&passDesc);
hr = mpD3DDevice->CreateInputLayout(layout, numElements,
passDesc.pIAInputSignature,
passDesc.IAInputSignatureSize,
&modelObject.pVertexLayout);
if(FAILED(hr))
return false;
return true;
}
Your indices array contains 6 entries per 'cell' (since you're drawing two triangles for each), therefore it should be declared as
DWORD indices[NUM_ROWS * NUM_COLS * 6]
The error you get tells you, that you write outside the boundaries of indices, this is usually either a hint towards a wrong declaration (or a wrong index calculation).
Now let us take the code snippet in question (probable root cause)
Code
DWORD indices[NUM_VERTSX * NUM_VERTSY];
int curIndex = 0;
for(int z=0; z < NUM_ROWS; ++z)
{
for(int x = 0; x < NUM_COLS; ++x)
{
int curVertex = x + (z * NUM_VERTSX);
indices[curIndex] = curVertex;
indices[curIndex + 1] = curVertex + NUM_VERTSX;
indices[curIndex + 2] = curVertex + 1;
indices[curIndex + 3] = curVertex + 1;
indices[curIndex + 4] = curVertex + NUM_VERTSX;
indices[curIndex + 5] = curVertex + NUM_VERTSX + 1;
curIndex += 6;
}
}
Analysis
Here indices have max number of 'cells' = NUM_VERTX * NUM_VERTSY = (16 + 1) * (16+1) = 289. So there are 0...288 'cells'. During the boundary condition - there value of z = 15, x = 15. So curIndex would be 15 * 15 * 6 = 1350. This far exceeds allocated cells.
Suggestion
Since three values determine the size of the target array, all three must be part of the allocation of the array. so if you use DWORD indices[NUM_VERTSX * NUM_VERTSY * UNIT_BLOCK], where UNIT_BLOCK = 6, it should work fine.
Also instead of embedding magic number inside the code, you can use a const variable - it would help a great deal later (if you want to change the value of the index).
HTH