PDA

View Full Version : normal arrays crashes



blender
05-12-2002, 01:09 AM
I use compiled vertext arrays for rendering my models, but when I use normal arrays, program crashes.

Sample 1 that works:



glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);

glVertexPointer(3, GL_FLOAT, 0, VertPosArray);
glTexCoordPointer(2, GL_FLOAT, 0, VertTexCoordArray);

glLockArraysEXT(0, lNumVerts);

//render models using glDrawArrays()

glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);

glUnlockArraysEXT();



Sample 2 that crashed my program:



glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);

glVertexPointer(3, GL_FLOAT, 0, VertPosArray);
glTexCoordPointer(2, GL_FLOAT, 0, VertTexCoordArray);
glNormalPointer(3, GL_FLOAT, VertNormalArray);

glLockArraysEXT(0, lNumVerts);

//render models using glDrawArrays()

glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);

glUnlockArraysEXT();



My arrays looks like this:
t_Vec3f *VertPosArray;
t_Vec2f *VertTexCoordArray;
t_Vec3f *VertNormalArray;

and I allocate the memory for each when I load the model. All the arrays are same sized.

Bob
05-12-2002, 01:30 AM
Your call to glNormalPointer is wrong. The first parameter is the data type, the second is the stride, and third is the pointer.

blender
05-12-2002, 05:22 AM
Oh yes, thanks. I really should see those prototypes before I use them http://www.opengl.org/discussion_boards/ubb/smile.gif

blender
05-12-2002, 06:48 AM
Something else come up:
The normals are somehow interpreted wrong, lighting is not looking right.

What does the parameter 'stride' do?
When I use glNormalPointer(GL_FLOAT, 0, VertNormalArray);, it crashes, I use the same stride value for other arrays and for them it works fine.
When I use glNormalPointer(GL_FLOAT, 1, VertNormalArray);, it doesn't crash, but lighting is NOT ok.

I'm sure that the normal values are ok.

[This message has been edited by blender (edited 05-12-2002).]

Bob
05-12-2002, 07:09 AM
The stride is the distance in bytes from the start of one entry (normal/vertex/color, dependeing on what the array contains) to the start of the next entry.

Say you have a vertex array, containing three components, stored as float, like this.



GLfloat myArray[] = {x0, y0, z0, x1, y1, z1, x2, y2, z2, ...};

The distance in byte between the start of two consecutive vertices is 3*sizeof(float), which is usually 12 bytesm and the stride is therefore 12.

Now, say you want to, for some reason, pad each vertex with an extra float. You then get this vertex array,



GLfloat myArray[] = {x0, y0, z0, pad0, x1, y1, z1, pad1, x2, y2, z2, pad2...};

The stride is now 4*sizeof(float), or usually 16 bytes.

A stride of zero, as in your code, is a special case, and means the entries are tightly packed together, i.e. there is no "empty" space between two vertices. In my first example, you can set stride to either 12 (the actual stride), or zero (the special case), since there's no space between two vertices. In the second example, you must set stirde to 16, cause they are no longer tightly packed together.

Most certainly your problem has to do with you not allocating enough memory for your normal array, and OpenGL tries to poke outside the allocated buffer. Why stride=1 works, but not stride=0, well, I leave that one as an excercise to you.

blender
05-13-2002, 02:53 AM
Most certainly your problem has to do with you not allocating enough memory for your normal array, and OpenGL tries to poke outside the allocated buffer.


Certainly not. Here's a piece of code:




VertPosArray = new t_Vec3f[lNumVerts];
VertTexCoordArray = new t_Vec2f[lNumVerts];
VertNormalArray = new t_Vec3f[lNumVerts];

// Check for errors

fread(VertPosArray, sizeof(t_Vec3f), lNumVerts, f);
fread(VertTexCoordArray, sizeof(t_Vec2f), lNumVerts, f);
fread(VertNormalArray, sizeof(t_Vec3f), lNumVerts, f);



So, I'm pretty sure there are enough memory allocated.

Robbo
05-13-2002, 03:09 AM
Often if you are performing transforms that require scale, your normals will be scaled also, leaving them incorrect. This is nothing to do with vertex buffers. You should either ensure your normals aren't scaled manually, or use lEnable ( GL_RESCALE_NORMAL ). This will slow down your T&L though, so try and remove the scaling if you can.

Bob
05-13-2002, 03:18 AM
So, I'm pretty sure there are enough memory allocated.

I can only see that you are allocating lNumVerts number of normals, but I don't see any proof that you aren't telling OpenGL to draw more than lNumVerts vertices. So you may still be poking outide allocated memory, becuse you either try to draw too many vertices, or your index array has a few indices that are too large (larger than lNumVerts - 1 that is).

Currupt lighting can also be caused by incorrect normals. In other words, your code to calculate normals is incorrect, assuming you don't load them from file, or anything like that.

blender
05-13-2002, 08:51 AM
Firstly, I'm not using index arrays and when I simply tried:

glDrawArrays(GL_TRIANGLES, 0, lNumVerts);

the results were same.

Secondly, I'm sure about the normals, they are loaded from a model file.

Thirdly, when I rendered in the 'old fashion'
way with exactly the same arrays the lighting was ok.

Bob
05-14-2002, 12:00 AM
OK, I think we got to the stage where we need to see some real code. If the code isn't too long, post it here. If it is, you can mail it to me, and I have a look at it. You find my address in my profile.

I can see you are not poking outside the arrays, and the normals seems to be correct since it works in the 'old fashion' way. I take that to be glVertex/glNormal by the way http://www.opengl.org/discussion_boards/ubb/biggrin.gif .

blender
05-14-2002, 02:35 AM
Here is the primary part of my code:

Header:



typedef struct Texture_t
{
char Filename[64];
char Name[64];
};

typedef struct Reference_t
{
char Filename[64];
char Name[64];
long lStart; // Faces
long lNum;
long lStartVert;
long lNumVert;
long Id;
long Sid;
t_PolygonMode Type;
bool bShow;
};

class t_MdlHeader
{
public:
unsigned int Version;
char Modelname[64];

long lNumTextures;
long lNumVerts;
long lNumFaces;
long lNumReferences;
long lNumNodes;
long lNumFixedNodes;
long lNumFrames;
long lNumSequences;
long lNumBControllers;

// Vertex array data
long *VertNodeIdArray;
float *VertLengthArray;

t_Vec3f *VertPosArray;
t_Vec3f *VertOrigPosArray;
t_Vec2f *VertTexCoordArray;
t_Vec3f *VertNormalArray;

// Model data
Texture_t *Textures;
Reference_t *References;

t_GlTexture *TextureData;

bool bLoaded;

bool Load(const char *Filename);
void Destroy();
void Render();
void Update();
t_MdlHeader();
};


Loading



bool t_MdlHeader::Load(const char *Filename)
{

if(!m_Render.bInstalled) return false;

FILE *f;
char Temp[64];
long l;

m_Console.Message("Model: Loading model: %s", Filename);

// Make the global filename and global foldername
sprintf(Temp, "models/%s/%s.mdl", Filename, Filename);

f = fopen(Temp, "rb");
if(!f)
{
m_Console.Error(false, "Couldn't open model file!");
return false;
}

// Basic info
fread(&Version, sizeof(unsigned int), 1, f);
fread(Modelname, sizeof(char), 64, f);

if(Version != 1)
{
m_Console.Error(false, "Invalid model version!");
return false;
}

// Elements number info
fread(&lNumTextures, sizeof(long), 1, f);
fread(&lNumVerts, sizeof(long), 1, f);
fread(&lNumFaces, sizeof(long), 1, f);
fread(&lNumReferences, sizeof(long), 1, f);
fread(&lNumNodes, sizeof(long), 1, f);
fread(&lNumFixedNodes, sizeof(long), 1, f);
fread(&lNumFrames, sizeof(long), 1, f);
fread(&lNumSequences, sizeof(long), 1, f);
fread(&lNumBControllers, sizeof(long), 1, f);

// Allocate memory for vertexs
VertNodeIdArray = new long[lNumVerts];
VertLengthArray = new float[lNumVerts];
VertPosArray = new t_Vec3f[lNumVerts];
VertOrigPosArray = new t_Vec3f[lNumVerts];
VertTexCoordArray = new t_Vec2f[lNumVerts];
VertNormalArray = new t_Vec3f[lNumVerts];

if(VertNodeIdArray==NULL | | VertLengthArray==NULL | | VertPosArray==NULL | |
VertOrigPosArray==NULL | | VertTexCoordArray==NULL | | VertNormalArray==NULL)
{
m_Console.Error(false, "Not enough memory for storing vertices.");
return false;
}

// Allocate memory for elements
Textures = new Texture_t[lNumTextures];
Faces = new Face_t[lNumFaces];
References = new Reference_t[lNumReferences];
Nodes = new Node_t[lNumNodes];
FixedNodes = new FixedNode_t[lNumFixedNodes];
Frames = new Frame_t[lNumFrames];
Sequences = new Sequence_t[lNumSequences];

TextureData = new t_GlTexture[lNumTextures];

if(Textures==NULL | | Faces==NULL | | References==NULL | | Nodes==NULL | |
FixedNodes==NULL | | Frames==NULL | | Sequences==NULL | | TextureData==NULL)
{
m_Console.Error(false, "Not enough memory for storing elements.");
return false;
}

// Load data
fread(Textures, sizeof(Texture_t), lNumTextures, f);

fread(VertNodeIdArray, sizeof(long), lNumVerts, f);
fread(VertPosArray, sizeof(t_Vec3f), lNumVerts, f);
fread(VertTexCoordArray, sizeof(t_Vec2f), lNumVerts, f);
fread(VertNormalArray, sizeof(t_Vec3f), lNumVerts, f);

fread(Faces, sizeof(Face_t), lNumFaces, f);
fread(References, sizeof(Reference_t), lNumReferences, f);
fread(Nodes, sizeof(Node_t), lNumNodes, f);
fread(FixedNodes, sizeof(FixedNode_t), lNumFixedNodes, f);

fread(Frames, sizeof(Frame_t), lNumFrames, f);
fread(Sequences, sizeof(Sequence_t), lNumSequences, f);
fread(BControllers, sizeof(BController_t), lNumBControllers, f);

fclose(f);

// Load textures
for(l=0; l<lNumTextures; l++)
{
sprintf(Temp, "models/%s/%s", Filename, Textures[l].Filename);
TextureData[l].LoadTGA(Temp, true);
}

// Loaded http://www.opengl.org/discussion_boards/ubb/smile.gif
bLoaded = true;

return true;
}


Rendering



void t_MdlHeader::Render()
{

if(bLoaded==false) return;
if(m_Render.bInstalled==false) return;

// Lighting
glLightfv(GL_LIGHT0, GL_AMBIENT, Light0Amb);
glLightfv(GL_LIGHT0, GL_DIFFUSE, Light0Dif);
glLightfv(GL_LIGHT0, GL_POSITION, Light0Pos);
glEnable(GL_LIGHT0);
glLightfv(GL_LIGHT1, GL_AMBIENT, Light1Amb);
glLightfv(GL_LIGHT1, GL_DIFFUSE, Light1Dif);
glLightfv(GL_LIGHT1, GL_POSITION, Light1Pos);
glEnable(GL_LIGHT1);
glEnable(GL_LIGHTING);

if(mouse_b & 1)
{
glRotatef(90.0f, 0.0f, 0.0f, 1.0f);
glRotatef(fModelRotate, 0.0f, 0.0f, 1.0f);
}
else
{
glLoadIdentity();
glTranslatef(5.0f, -10.0f, -3.5f);
glRotatef(-90.0f, 1.0f, 0.0f, 0.0f);
glRotatef(180.0f, 0.0f, 0.0f, 1.0f);
}

static long n, m, k;
Reference_t *pRef;
t_GlTexture *pTextr;
t_GlTexture *pShine;

glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);

glVertexPointer(3, GL_FLOAT, 0, VertPosArray);
glTexCoordPointer(2, GL_FLOAT, 0, VertTexCoordArray);
glNormalPointer(GL_FLOAT, 3, VertNormalArray);

glLockArraysEXT(0, lNumVerts);

for(n=0; n<lNumReferences; n++)
{
if(References[n].bShow==false) n++;

switch( References[n].Type )
{
case SOLID:
pRef = &amp;References[n];
pTextr = &amp;TextureData[pRef->Id];

glBindTexture(GL_TEXTURE_2D, *pTextr->iData);
glDrawArrays(GL_TRIANGLES, pRef->lStartVert, pRef->lStartVert+pRef->lNumVert);
break;

case SHINE:
pRef = &amp;References[n];
pTextr = &amp;TextureData[pRef->Id];
pShine = &amp;TextureData[pRef->Sid];

glBindTexture(GL_TEXTURE_2D, *pTextr->iData);
glDrawArrays(GL_TRIANGLES, pRef->lStartVert, pRef->lStartVert+pRef->lNumVert);

glEnable(GL_TEXTURE_GEN_S);
glEnable(GL_TEXTURE_GEN_T);
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
glEnable(GL_BLEND);
glEnable(GL_ALPHA_TEST);
glDisable(GL_LIGHTING);

glBindTexture(GL_TEXTURE_2D, *pShine->iData);
glDrawArrays(GL_TRIANGLES, pRef->lStartVert, pRef->lStartVert+pRef->lNumVert);

glDisable(GL_BLEND);
glDisable(GL_ALPHA_TEST);
glEnable(GL_LIGHTING);
glDisable(GL_TEXTURE_GEN_S);
glDisable(GL_TEXTURE_GEN_T);
break;

case BLENDED:
glEnable(GL_BLEND);
glEnable(GL_ALPHA_TEST);
glDisable(GL_LIGHTING);

pRef = &amp;References[n];
pTextr = &amp;TextureData[pRef->Id];

glBindTexture(GL_TEXTURE_2D, *pTextr->iData);
glDrawArrays(GL_TRIANGLES, pRef->lStartVert, pRef->lStartVert+pRef->lNumVert);

glDisable(GL_BLEND);
glDisable(GL_ALPHA_TEST);
glEnable(GL_LIGHTING);
break;
}
}

glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);

glUnlockArraysEXT();

glDisable(GL_LIGHTING);
}

blender
05-15-2002, 02:19 AM
so, can you see anything that could cause this kind behaviour?

Robbo
05-15-2002, 02:47 AM
Try this:

glNormalPointer(GL_FLOAT, 0, VertNormalArray);

instead of:

glNormalPointer(GL_FLOAT, 3, VertNormalArray);

The second parameter is the stride, per component, rather than the width of the normal. Your normals are tightly packed, so there is no byte stride between them.

Bob
05-15-2002, 03:28 AM
Your normals are tightly packed, so there is no byte stride between them.

The stride is not the space between two entries, but the distance from the start of one entry to the start of the next entry. The stride in blenders normal array should be 12 (3 * sizeof(float)), since there's 12 bytes from the start of one normal to the start of the nex normal. Since they are tighly packed, as you say, the stride can be set to zero, but that's just a special case, and should not be confused with the number of bytes between two entries.

Robbo
05-15-2002, 03:47 AM
Either way, a value of 3 is incorrect. It should be zero or 12? MSDN gives a rather stupid prototype for this function (with 4 parameters):

void glNormalPointer(
GLenum type,
GLsizei stride,
GLsizei count,
const GLvoid *pointer
);

Stride is stride in bytes, count is the number of normals (static normals, whatever that means).

In the gl online documentation, it states stride as the stride in bytes between the start of each normal, which as you say is 12.

So, his code 'aint right!!!!! http://www.opengl.org/discussion_boards/ubb/wink.gif

Bob
05-15-2002, 04:05 AM
The OpenGL documentation in MSDN is not the best. The vertex array functions described there is the old version I believe, the version from the OpenGL 1.0 VA extension.

Deiussum
05-15-2002, 05:12 AM
Newer versions of MSDN correctly show the prototype as

void glNormalPointer(
GLenum type,
GLsizei stride,
const GLvoid *pointer
);

blender
05-16-2002, 04:39 AM
Damn!!

I should have guessd this.
See this following line I used to use:
glDrawArrays(GL_TRIANGLES, pRef->lStartVert, pRef->lStartVert+pRef->lNumVert);

Heh. Before I changed to vertex arrays, I used loop like this:
for(i=pRef->lStartVert; i<pRef->lStartVert+pRef->lNumVert; i++)

So, I took a look to glDrawArrays more carefully and figured out that the last parameter is actually a number of polygons after the start point, not the end point in the array.

That's why it did crash before, when I used stride as (3*sizeof(float)) or sizeof(t_Vec3f),
but now it finally works.

Thanks to eveyone for your support.