1

So I made a mesh in Maya, wrote some code to import it into the vertex buffer and so far so good but the mesh has multiple components that have different textures assigned and I figured thats easy ill put a key in the vertbuffer and run a switch statement (and from what i can gather from this post thats not such a bad thing) and send the required textures for the whole mesh through uniforms and have them selected through the key but as i was implementing it i noticed it would require multiple sampler2D's and was wondering if this would entail loading multiple mostly unused textures every pixel and would this be a waste?

GLchar* MeshFragmentShader =    //also known as pixel shader
    "#version 330 core\n"   //version 3, not 440 >> 450
    "\n"                    //GLSL 3, core = non-depricated
    "layout(location = 0) out vec4 color;\n"
    "\n"
    "in vec2 v_TexCoord;\n"
    "in vec4 v_color;\n"
    "in float v_lightval;\n"
    "\n"
    "uniform sampler2D u_Texture;\n"//<<multiple samplers?
    "\n"
    "void main()\n"
    "{\n"
    "   int i = 0;\n"//<<texture/color key (location = 4) Vertbuffer
    "   vec4 texColor;  \n"
    "   switch (i) {\n"
    "       case 0:\n"
    "           texColor = texture(u_Texture, v_TexCoord);\n"
    "           break;\n"
    "       case 20:\n"
    "           texColor = v_color;\n"//<<override
    "           break;\n"
    "   }   \n"
    //" texColor = texture(u_Texture, v_TexCoord);  \n"
    "   \n"//simple code certainly somthing i would like to improve
    "   vec3 Kolor = texColor.rgb * (v_lightval + 0.4f);\n"//change 0.4f to gamma
    "   color = vec4(Kolor, 1.0f);\n"
    //WORKING
    //" vec4 texColor = texture(u_Texture, v_TexCoord);\n"
    //"   texColor.rgb *= v_lightval;\n"
    //" color = texColor;\n"
    "}\n";

UPDATE:
For anyone who comes across this and maybe to elaborate a bit more i went from the above shader to this and I added the vertex shader (and an image) for reference;

GLchar* MeshVertexShader =
        "#version 400 core\n"   //version 3, not 440 >> 450 
        "\n"                    //GLSL 3, core = non-depricated
        "layout(location = 0) in vec4 position;\n"
        "layout(location = 1) in vec2 texCoord;\n"
        "layout(location = 2) in vec3 normal;\n"
        "layout(location = 3) in vec4 color;\n"
        "layout(location = 4) in float matid;\n"
        "\n"
        "out vec2 v_TexCoord;\n"
        "out vec4 v_color;\n"
        "out float v_matid;\n"
        "out vec3 norm;\n"
        "\n"
        "uniform mat4 u_MVP;\n"//model matrix projection matrix
        "uniform mat3 u_normalmatrix;\n"
        //"uniform bool u_LightingFlag;\n"  //had problems passing this

        "void main()\n"
        "{\n"
        "   vec4 postposition = u_MVP * position;\n"//3 line down
        "   norm = normalize( u_normalmatrix * normalize(normal) );\n"
        "   \n"
        "   gl_Position = postposition;\n"                  
        "   v_TexCoord = texCoord;\n"
        "   v_color = color;\n"
        "   \n"
        "   v_matid = matid;\n"
        "}\n";
    GLchar* MeshFragmentShader =    //also known as pixel shader
            "#version 400 core\n"   //version 4.0, not 440 >> 450
            "\n"                    //GLSL 4, core = non-depricated
            "layout(location = 0) out vec4 color;\n"
            "\n"
            "in vec2 v_TexCoord;\n"
            "in vec4 v_color;\n"
            //"in float v_lightval;\n"  
            "in float v_matid;\n"
            "in vec3 norm;\n"
            "\n"
            "uniform sampler2D u_Texture0;\n"   
            "uniform sampler2D u_Texture1;\n"   
            "uniform sampler2D u_Texture2;\n"   
            "uniform sampler2D u_Texture3;\n"   
            "uniform bool u_LightingFlag;\n"    
            "\n"
            "void main()\n"
            "{\n"
            "   float lightval;\n"
            "   if (u_LightingFlag == true){\n"
            "   vec3 light1 = normalize( vec3(-10.0f, 9.0f, -11.0f) );\n"
            "   lightval = max(dot(norm,light1),0.0f);\n"//Lambert Lighting
            "   } else {\n"
            "   lightval = 0.6f;\n"
            "   }\n"
            "   vec4 texColor;\n"
            "   for (int i = 0; i < 1; i++) {\n"        //not a loop, a goto
            "       if (v_matid < 0.1f) { texColor = texture(u_Texture0, v_TexCoord);
break; }\n"
            "       if (v_matid < 1.1f) { texColor = texture(u_Texture1, v_TexCoord);
break; }\n"
            "       if (v_matid < 2.1f) { texColor = texture(u_Texture2, v_TexCoord);
break; }\n"
            "       if (v_matid < 3.1f) { texColor = texture(u_Texture3, v_TexCoord);
break; }\n"
            "       texColor = v_color;\n"//override
            "   }\n"
            "   vec3 Kolor = texColor.rgb * (lightval + 0.4f);\n"   
            "   color = vec4(Kolor, 1.0f);\n"                       
            //" color = v_color;\n"                 
            "}\n"; 

I benchmarked it by comparing that to a version that used only one texture, by forcing VSYNC off in nvidia control panel and monitoring gpu usage and the effects and metrics were really minimal, so so far so good but if anyone knows if im doing anything wrong or could be doing anything better than please do tell the one loop for-loop could possibly use some work I tried using a switch but couldnt get it to work partly cause of type-casting and Im thinking of passing the cases as variables

enter image description here

enter image description here

  • If your textures have many unused pixels the textures themselves are at fault, why don't you merge them into fewer textures? Otherwise if it's the case that all mesh components aren't shown most of the time, your meshes don't seem to belong in the same model. –  Apr 21 '19 at 23:04
  • You should group your faces by texture/material and handle those as separate objects VAO/VBOs... Anyway way around it I think would be using bindless texturing but never used that and not sure its available in `#version 330 core` Another workaround is Texture atlas, but that one limits the wrappings functionality and quality of textures – Spektre Apr 25 '19 at 04:29
  • I could use groups and I could also use multiple image textures but using groups would mean a big revamp of the mesh loader and multiple draw calls which could be a negative in itself but its a university project and I only have a week to plug it into vr and add some other stuff – negativezforward Apr 25 '19 at 05:37
  • I updated the post with a lot more to it too – negativezforward Apr 25 '19 at 05:38
  • @negativezforward 1. to notify (respond to) user `nick` you have to add `@nick` to the comment. 2. having single VAO/draw call is also a bottleneck as when the VBOs grow too big GL will stagger ... Your scene screenshot suggest single texture per object anyway. You will needmatrix per object too so having single VAO is not a good idea 3. you should measure OpenGL time instead of GPU utilization you know using the `glQueryCounter(id,GL_TIMESTAMP);` for more info see [Benchmarking GLSL shaders to compare speed of alternative implementations](https://stackoverflow.com/a/37490211/2521214) – Spektre Apr 26 '19 at 05:20
  • @negativezforward And no using more texture samplers is not a performance hit (as the textures are/should be already loaded into GPU) but there is only limited number of texture units limiting the total number of textures used at once... – Spektre Apr 26 '19 at 05:25
  • @Spektre the way it works is I have a mesh loader so I can create something in Maya (with multiple textures but once per vertex) for example as I intend to do martial arts in the dojo Ive split the mesh into two the outside and the inside and being loaded as individual mesh's they are individual vbo's thats the way the loader works. I had a (purposely) quick dabble with timings but couldnt find a way to get milliseconds but (I mentioned it by saying I turned VSYNC off but didnt elaborate, sorry my bad) I did measure the fps also (and I added another pic). Yeah your guaranteed 16, and thanks. – negativezforward Apr 26 '19 at 08:15
  • @negativezforward You got whole scene as a mesh but that is not how 3D apps works. You need to have each object as separate mesh otherwise you can not do anything with them (like moving, collision testing, etc) but if you still want to use multiple samplers then do ... but that will lead to multiple `if/else` conditions inside fragment shaders lowering overal speed. That is why I suggest bindless texturing. Measuring `fps ` is not a good way to mesure your render as it includes too many stuff unrelated to your rendering. – Spektre Apr 26 '19 at 08:22
  • @Spektre the skybox is a mesh (unto itself), the dojo is split into three mesh's, dojo inner, dojo outer and dojo base and because currently Im using four textures per mesh the 12 planets you see are actually three mesh's of four planets each – negativezforward Apr 26 '19 at 08:37

0 Answers0