Jump to content


Fastest way to display a static model


33 replies to this topic

#1 Alienizer

    Member

  • Members
  • PipPipPipPip
  • 440 posts

Posted 05 August 2012 - 04:48 AM

What is the best way to display a static model in OpenGL, which is compatible with NVidia and ATI? and be the most compatible, v1.15 maybe? I have an older ATI card and it has the latest driver GL v6.xxx but Load_GL_version_3_3 fails. So I need something that can work with v1.15 maybe? or v2? donno!

I want to make an obj viewer, but some of them are big (600k triangles) that when I rotate the scene, it takes more than a few seconds to update! Especialy when there are transparencies because I sort them by z.

I don't know if I should use shaders or not, glDrawArrays or not etc. I don't need textures, only vertex, normals and colors.

What I do right now is so slow, I cull the back and draw the front, then cull the front and draw the back, then draw the front transparencies, then the back transparencies (after sorting them!).

Thanks!

#2 Stainless

    Member

  • Members
  • PipPipPipPip
  • 610 posts
  • LocationSouthampton

Posted 06 August 2012 - 09:18 AM

If you need transparency, it's going to be slow. Sorry you need to reduce the number of tri's you are displaying somehow.

Is the camera close enough to the object to allow you to do some quad tree or something?

#3 Reedbeta

    DevMaster Staff

  • Administrators
  • 5344 posts
  • LocationSanta Clara, CA

Posted 06 August 2012 - 05:10 PM

600K triangles isn't that much, even for an older card. Why do you draw the opaque stuff twice? Surely you have the depth buffer turned on, so you should be able to just draw it once (without culling, if you want to see backfaces) and let the depth buffer sort it all out.

IIRC, in OpenGL for static geometry you should create a vertex buffer object and copy the vertices into it once at load time, then re-use the same VBO for rendering each frame. This should be quite fast. If you don't have access to VBOs, at least use glDrawArrays.
reedbeta.com - developer blog, OpenGL demos, and other projects

#4 Alienizer

    Member

  • Members
  • PipPipPipPip
  • 440 posts

Posted 06 August 2012 - 08:17 PM

I draw the front then the back because that's the only way I know how to do it with textures! and then I draw the front then back transparencies as you told me before I had to sort them by eye-dist to get it rigjht.

From what I understand, glDrawArrays can not be used to draw front and back textures all at once, is that right?

Why can't OpenGL provide array pair for all this? I mean, a struct of vertex and front/back colors and textures...

 struct gl_Vertex_Data {
 vert1,vert2,vert3: vec4;
 frontTexUV, backTexUV: vec2;
 frontColor, backColor: vec4;
 frontTexID, backTexID: uint
}

Bind all our texture to one unit and just use the texture ID. The way I understabd it now is only the active texture is used, and if you want 50 of them, you need to combine them all in a single giant texture! makes no sense, not with the technology we have now!

Then all we have to worry about is rotate, panning and stuff, and, if we pass the data as a pointer instead of uploading it to the card, it can become dynamic instead of static. Why are they making it so hard and complicated? c++ is easier to understand~!

#5 Reedbeta

    DevMaster Staff

  • Administrators
  • 5344 posts
  • LocationSanta Clara, CA

Posted 06 August 2012 - 08:33 PM

So - you want to put two different textures on the front and back sides? In that case, it does make sense to draw front and back in separate draw calls. Anyway, you could use a shader approach for this as well but that may be beside the point.
reedbeta.com - developer blog, OpenGL demos, and other projects

#6 Stainless

    Member

  • Members
  • PipPipPipPip
  • 610 posts
  • LocationSouthampton

Posted 06 August 2012 - 09:56 PM

I'm not sure why you want to have different textures on each side of a polygon, but that is whats causing you problems.

If I were you I would look at the models and decide which triangles absolutely need to have different textures each side, and in your 3d editor duplicate those polygons.

Also extract all the transparent polygons and put them in a separate object.

Then render all the solid polygons with culling enabled,

Sort your transparent polygons

Draw them with culling off with a painters algorithm

It depends on the number of polygons that need to be duped, and the number of transparent ones, but it should be a lot quicker

#7 Alienizer

    Member

  • Members
  • PipPipPipPip
  • 440 posts

Posted 07 August 2012 - 12:57 AM

Thank you guys. but I'm not understanding your question! A poly has 2 face, and that means each face can have a color or a texture. Why would I be forced to have the back identical to the front?

Reedbeta, how am I suppose to draw both sides on a single call? Say, one poly with a carpet texture on the front and a brick texture on the back. How can I do that with a single call without a shader? Or am I suppose to draw only onr face since only one face can be visible at any one time, and if so, how does this work without a shader?

#8 Reedbeta

    DevMaster Staff

  • Administrators
  • 5344 posts
  • LocationSanta Clara, CA

Posted 07 August 2012 - 01:10 AM

Well, first realize that drawing both front and back sides of a polygon, especially with different textures, is not a "normal" way to render things. You can do it if you want to. But maybe you should consider modeling your art with two separate polygons for the front and back sides (with opposite winding), like Stainless said. Then in your modeling program you can put separate UVs, textures, etc. on them, no problem. You'd render it with backface culling turned on, and without doing separate passes for front and back (just one pass over the model - separate draw calls for each material, as usual). That would be the usual way to do this sort of things. The renderer doesn't have to know anything about front/back sides, since it's all baked into the art.

I was just saying that it's possible to write a shader that takes two textures, and based on whether you're looking at the front or back of a particular pixel, samples one texture or the other. That's not necessarily the best way to do this though. I'm just saying it's possible.

Anyway, all this yadda yadda about front/back and different textures etc. may be a red herring. Have you been able to narrow down your performance problem at all? For instance, if you turn off transparencies, or if you only render front faces, does it improve the speed? By how much? If it's still really slow when just drawing the opaque front faces, you have some other problem that may be totally unrelated to the whole front/back business.
reedbeta.com - developer blog, OpenGL demos, and other projects

#9 Alienizer

    Member

  • Members
  • PipPipPipPip
  • 440 posts

Posted 07 August 2012 - 01:51 AM

I see what you mean Reedbeta and I model the way you suggest, but when I want to see obj models, many of them are dual face. Not all models are made with only front faces.

I use the glBegin(GL_TRIANGLES); glEnd; to set the texture, UV, normal and vertex for each poly. And it's not bad at all, not that slow on 600k poly doing the front and back, without transparencies. But the more transparencies I have, the bigger the list to sort, and again with the front then the back, so it get's very slow.

I wrote a shader that I pass everything to and use glDrawArrays, and the shader uses gl_FrontFacing to know which side, but it only works fine with colors since from what I can tell, you can't pass textures as well.

So I'm back to glBegin(GL_TRIANGLES); glEnd; and I can pass one texture using glBindTexture(GL_TEXTURE_2D...); but how do I pass a 2nd one, and not just that, how do I also pass the 2nd color, and the 2nd UV???

#10 Reedbeta

    DevMaster Staff

  • Administrators
  • 5344 posts
  • LocationSanta Clara, CA

Posted 07 August 2012 - 02:00 AM

First of all, using glDrawArrays is definitely FAR faster than using glBegin/glEnd and passing each vertex separately. Especially for large models, it's no surprise you are getting terrible performance using glBegin/glEnd! Using glDrawArrays should be independent of what kind of shader you use, the front-facing/back-facing stuff, etc. And of course you can use textures with glDrawArrays and other batching methods, I'm not sure what the trouble is? You'll use glTexcoordPointer to set up the UVs and glBindTexture to set the texture, just as normal.

For multiple textures, use glActiveTexture to switch which texture unit is the "current" one, then glBindTexture to assign a texture to the current texture unit. Like wise use glClientActiveTexture and glTexcoordPointer to set up multiple sets of UVs. So you'd set up all your vertices, UVs, textures, etc. and then do glDrawArrays to send everything off.
reedbeta.com - developer blog, OpenGL demos, and other projects

#11 Alienizer

    Member

  • Members
  • PipPipPipPip
  • 440 posts

Posted 07 August 2012 - 02:57 AM

I was under the impression that glDrawArrays only work on one texture at a time, and I had to call it for as many textures I have!

ok Reedbeta, you really got me puzled here because I seached and search the net for days and nowhere have I found a way to do what you've explained.

Can you please enlighten more Reedbeta?

Here's what I do to setup the vertex...

glGenBuffers(1, &vboVertex);
glBindBuffer(GL_ARRAY_BUFFER, vboVertex);
glBufferData(GL_ARRAY_BUFFER, SizeOfTheArrayInByte, PointerTotheArray, GL_STATIC_DRAW);
vboAtribVertex = glGetAttribLocation(ProgramID, "inVertex"); // in the vertex shader I have layout(location =  0) in vec4 inVertex;
glEnableVertexAttribArray(vboAtribVertex);
glBindBuffer(GL_ARRAY_BUFFER, vboVertex);
glVertexAttribPointer(vboAtribVertex, 4, GL_FLOAT, GL_FALSE, 0, 0);

Then i do the same for the normals, the colors and UVs, but I have no clue how to add textures to all this?

#12 Reedbeta

    DevMaster Staff

  • Administrators
  • 5344 posts
  • LocationSanta Clara, CA

Posted 07 August 2012 - 04:30 AM

Textures work exactly the same way whether you use vertex buffers or not. For one texture, you just do glBindTexture(GL_TEXTURE_2D, ...) sometime before the glDrawArrays call. For multiple textures, you'd do something like

glActiveTexture(0);
glBindTexture(GL_TEXTURE_2D, aTexture);

glActiveTexture(1);
glBindTexture(GL_TEXTURE_2D, anotherTexture);

glActiveTexture(2);
glBindTexture(GL_TEXTURE_2D, yetAnotherTexture);
// etc.

That's all there is to it. The numbers passed to glActiveTexture are the numbers of the texture units. They run from 0 up to however many simultaneous textures your card can support. You can probably get the texture unit numbers from glGetAttribLocation, too, to match up with specific textures declared in the shader.

To provide multiple UVs, just have the vertex shader declare multiple texcoord inputs and use glVertexAttribPointer multiple times, once for each set of UVs.
reedbeta.com - developer blog, OpenGL demos, and other projects

#13 Alienizer

    Member

  • Members
  • PipPipPipPip
  • 440 posts

Posted 07 August 2012 - 04:38 AM

ok, but then how do I access them in the shader? Do I have to declare uniform sampler2D tex; one for each texture?

#14 Reedbeta

    DevMaster Staff

  • Administrators
  • 5344 posts
  • LocationSanta Clara, CA

Posted 07 August 2012 - 05:15 AM

Yes, one for each texture.
reedbeta.com - developer blog, OpenGL demos, and other projects

#15 Alienizer

    Member

  • Members
  • PipPipPipPip
  • 440 posts

Posted 07 August 2012 - 04:22 PM

really? but how do I access the right one in the shader? I can't simply have a bunch of "if then" for each tex1, tex2, tex3 etc. ???

#16 TheNut

    Senior Member

  • Moderators
  • 1719 posts
  • LocationCyberspace

Posted 07 August 2012 - 06:05 PM

See this.
http://www.nutty.ca - Being a nut has its advantages.

#17 Alienizer

    Member

  • Members
  • PipPipPipPip
  • 440 posts

Posted 07 August 2012 - 06:18 PM

Great, thank you. But I can only load 32 textures! I was trying it on a model that had 52.

Any other work around that can work on more than 32 sampler?

Thanks guys, I appreciate the help.

#18 TheNut

    Senior Member

  • Moderators
  • 1719 posts
  • LocationCyberspace

Posted 07 August 2012 - 06:28 PM

I won't ask what you're doing that requires 52 textures, but if you are doing something crazy like that I would suggest you look into texture atlases to cut down on the number of textures you need to feed to the shader. If you need something more dynamic, you can look into the megatexturing algorithm, or possibly 3d textures and use each slice as a new texture (haven't really used these much). You really shouldn't be pushing more than 4 to 8 textures, since most hardware on average will cap at those ranges.
http://www.nutty.ca - Being a nut has its advantages.

#19 Reedbeta

    DevMaster Staff

  • Administrators
  • 5344 posts
  • LocationSanta Clara, CA

Posted 07 August 2012 - 06:38 PM

Well, usually when people use multiple textures it's because they have a color map, normal map, specular map, etc. So they want to sample all the textures, not choose one. Note that you'd still normally draw each material in its own draw call, drawing only the polygons that use that material, then looping over all the materials. A "material" here means one color map, one normal map, one specular map, etc. A typical model might have several different materials in it, applied to different polygons.

For using different textures on the front and back sides, you would indeed use an if-statement. There's a pixel shader semantic, I forget what it's called, that tells you whether you're on the front or back side (i.e. it has a value of 1 for front-facing pixels and -1 for back-facing pixels, or some such). You could use that in an if-statement to determine which texture to sample.

As I mentioned earlier in the thread, this isn't necessarily the best way to do it. I think it's totally reasonable to draw the front faces in one call, and then switch textures and culling modes and do another call to get the back faces. Then the shader would only look at one texture. All of the stuff I posted was by way of if you want multiple textures in one shader, here's how you'd do it.
reedbeta.com - developer blog, OpenGL demos, and other projects

#20 Alienizer

    Member

  • Members
  • PipPipPipPip
  • 440 posts

Posted 07 August 2012 - 06:41 PM

oh!!?? But most models have way more than that! Walls, chaires, desk, floor, magazines, vase, plants you name it!





1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users