glDrawRangeElement issue.

Started by
12 comments, last by Drey 17 years, 9 months ago
i'm not coding in C++. Instead i'm using blitzmax. However, i doubt it's the source of the problem. Case Key_1 does as expected and renders the quad. Case Key_2 does as expected and renders the top corner. However case Key_3 only renders the left upper half. Instead it's suppost to render the bottom right corner of the quad. Can someone help me out here?

GLGraphics 800,600
glewInit()

	
Local	fltVertex#[] =[ -1.0 , 1.0 , 0.0 ,    1.0 , 1.0,  0.0 ,    -1.0, -1.0, 0.0 ,    1.0, -1.0, 0.0 ]
Local	fltColor#[] = [ 1.0 ,  0.0 , 0.0 ,    0.0 , 1.0,  0.0 ,     0.0,  0.0, 1.0 ,    1.0,  1.0, 0.0 ]
		'              Red                      Green              Blue                  Yellow
Local	shtElements:Short[] = [ 0:Short,  1:Short, 2:Short, 1:Short, 3:Short , 2:Short ]	



	glMatrixMode(GL_PROJECTION);				'		// Select The Projection Matrix
	glLoadIdentity();							'// Reset The Projection Matrix

	'// Calculate The Aspect Ratio Of The Window
	gluPerspective(45.0 ,Float(GraphicsWidth())/GraphicsHeight(),0.1 ,100.0 );

	glMatrixMode(GL_MODELVIEW);						'// Select The Modelview Matrix
	glLoadIdentity();	
	
	glShadeMOdel(GL_SMOOTH);
	glClearColor( 0.0, 0.0 , 0.0 , 0.0 )
	
		
	
	glEnable(GL_DEPTH_TEST);					'	// Enables Depth Testing	
	
	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);		
	
			
glEnableClientState(GL_VERTEX_ARRAY)
glEnableCLientState(GL_Color_Array)
glVertexPointer(3, GL_FLOAT , 0 , Varptr(fltVertex[0]) )
glColorPointer(3,  GL_FLOAT , 0 , Varptr(fltColor[0]) )

Local KeyInput = KEY_1
While Not KeyHit(KEY_A)

	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);			'// Clear The Screen And The Depth Buffer
	glLoadIdentity();							'// Reset The Current Modelview Matrix
	
	glTranslatef( 0.0 , 0.0, -5.0 )

	
	If KeyHit(KEY_1)
		Keyinput = KEY_1
	ElseIf KeyHit(Key_2)
		keyinput = KEY_2
	ElseIf KeyHit(Key_3)
		keyinput = KEY_3
	EndIf
	
	Select KeyInput
	
		Case KEY_1
			glDrawRangeElements(GL_TRIANGLES, 0,5,6, GL_UNSIGNED_SHORT , Varptr(shtElements[0]) )
		Case Key_2
			glDrawRangeElements(GL_TRIANGLES, 0,2,3, GL_UNSIGNED_SHORT , Varptr(shtElements[0]) ) 
		Case Key_3
			glDrawRangeElements(GL_TRIANGLES, 3,5,3, GL_UNSIGNED_SHORT , Varptr(shtElements[0]) )
					
	End Select
	
		
	Flip()
	
Wend 

gldisableClientState(GL_VERTEX_ARRAY)
gldisableCLientState(GL_Color_Array)


Advertisement
Quote:Original post by Drey
		Case KEY_1			glDrawRangeElements(GL_TRIANGLES, 0,5,6, GL_UNSIGNED_SHORT , Varptr(shtElements[0]) )		Case Key_2			glDrawRangeElements(GL_TRIANGLES, 0,2,3, GL_UNSIGNED_SHORT , Varptr(shtElements[0]) ) 		Case Key_3			glDrawRangeElements(GL_TRIANGLES, 3,5,3, GL_UNSIGNED_SHORT , Varptr(shtElements[0]) )

Well I don't know the language, but shouldn't the last parameter to glDrawRangeElements in case Key_3 be Varptr(shtElements[3])?

Remember, glDraw*Elements will start dereferncing from the pointer you provide irrespective of the range.
First, your call for case 3 is identical to that of case 2, except the range of index values. So if case 2 draws the top half then so should case 3.

Second, you start and end values are the maximum and minimum values in the index array. For case 3, you say that no indices are outside the range [3, 5]. But clearly every index except the second last index is outside this range. I assume the call for case 3 would looks something like this (adjust the syntax for your language).
glDrawRangeElements(GL_TRIANGLES,                               1,    // Smallest value in the range of interest (index 3 to 5, see below) is 1.                               3,    // Largest index in the range of interest is 3.                               3,    // Draw 3 indices, making one triangle.               GL_UNSIGNED_SHORT,               Varptr(shtElements[3])    // Start drawing at index 3, which means index 3 to 5 since the number of indices to draw is 3.);

For the same reason, case 1 and 2, while not wrong in the sense that you're lying to OpenGL about the smallest and largest index value, are not really correct. Case 1 should have smallest and largest index set to 0 and 3, respectively, and case 2, 0 and 2.

Now while writing mu reply it seems like you misunderstand the start and end values. Seems like you think these values are represent what part of the index array to use, but they are not. OpenGL is perfectly capable of calculating those values itself from the start pointer and the number of indices to draw. What it's not capable of is to determine what the values of those indices are, i.e. the content of the index array.
OK, but changing the pointers like that isn't an good idea for VBOs though or should i use gBufferSubData for every range change? Kinda kills the purpose though. How will i control regions with VBO?
Quote:Original post by Drey
OK, but changing the pointers like that isn't an good idea for VBOs though ...

Why do you thisnk that?

You are just providing an offset from the start of your index array basically. There is no additional cost in providing &indices[n] and &indices[0] ... the GPU just starts reading from a different memory address.
because my orginal design idea was to have prepare the VBO once ( with glbindbuffer ) and then call on regions of the array as needed. So the array loaded was going to be the WHOLE mesh, and i was giong to call on glDraw"Range"Elements to render different parts under different matrices. It would have only taken one command before for VBO..now it seems like i have to do a few..which defeats the purpose somewhat.
But you don't have to change any arrays, and what we're telling you to do is what you want to do. If you want OpenGL to draw 3 vertices, starting at the 3:rd index, then you pass a pointer (or offset, since you use VBO) to the 3:rd index, and set the size to 3.

Range in glDrawRangeElements does not refer to drawing a sub range of the index array. It tells OpenGL what the range of the index values, the values in the index array, is. For the purpose of only drawing certain parts of the object, then glDrawElements is just fine. glDrawRangeElements doesn't provide anything but the chance of a more optimized rendering. It doesn't provide anything that can't be done with glDrawElements.
Oh, i understand that. I'm just worried about my VBOs working correctly now.


glGenBuffers 1, Varptr(intVertexBuffer)
glBindBuffer(GL_ARRAY_BUFFER, intVertexBuffer)
glBufferData(GL_ARRAY_BUFFER, SizeOf(fltVertex), Varptr(fltVertex[0]), GL_STATIC_DRAW)
glBindBuffer(GL_ARRAY_BUFFER, 0 )


in bufferdata i'll have to change to Varptr(fltVertex[3]) for this example. I was trying to avoid calling bindbuffer again. The idea was to do something like this.
Mesh.BeginRender() //if in VBO mode, binds buffers.  If in VA mode, sets pointersLoops for Num Of RefMesh  Loops for RefMesh.SegementUpdateList       // Model Transform matrix       Segement.Position.toMatrixLoad()      //       Mesh.Render( Segement.ElementRange )  // Range object containing starting and ending in the arrayEnd LoopMesh.EndRender()


It's rough peusocode, but it conveys the idea mostly.
I know it's not a big deal in VA(change pointers) but it is in VBO. Is there a way to get the same effect without rebinding?
Unless what you're telling us is not whta you actually want, then the answer we have given you is the solution to your problem.

Create the VBO by uploading the mesh data once, and only once. No need to touch it any more. When drawing sub parts of the mesh, adjust the starting address passed to glDraw(Range)Elements.

That's all there is. Really.
I had a post typed up but now i really understand what's goin on now. I can bind everything like normal except the indices array. I was binding that as well. That's where all this confusion came from. I guess it isn't really too bad a bottleneck to have the indice array stream from the RAM and nothing else.

I was passing a null as a pointer once i had the indice array loaded

							glGenBuffers 1, Varptr(intVertexBuffer)				glBindBuffer(GL_ARRAY_BUFFER, intVertexBuffer)				glBufferData(GL_ARRAY_BUFFER, SizeOf(fltVertex), Varptr(fltVertex[0]), GL_STATIC_DRAW)				glBindBuffer(GL_ARRAY_BUFFER, 0 )								glGenBuffers(1,  Varptr(intElementBuffer) )				glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, intElementBuffer)				glBufferData(GL_ELEMENT_ARRAY_BUFFER, SizeOf(shtElements), Varptr(shtElements[0]), GL_STATIC_DRAW)				glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0 )			


Then i will have 3 modes. ALL VBO(including indices, non animated or non seperatable items), Partical VBO mode(likely excluding indice binding), and a VA mode. (if i'm understanding this correctly)

Thanks guys! :-D


This topic is closed to new replies.

Advertisement