0

I've been writing my own renderer for a while now and I just about got the system running decently, but I am running into some speed issues.

At about 1000 scene objects, the fps drops really fast and by 2000 objects, the max my laptop can get is 25 fps. I made the exact same scene with THREE and i get a constant 60fps which is really annoying and I'm not sure what to do.

After creating a debug timer for myself, I disscovered that most of the lag is coming from assigning my attributes, the uniforms and also the draw call itself.

In my pipeline i have a map of shaders and for each object using that shader, I get the required attributes and uniforms and then send the data over to the gpu.

I have a feeling that it is the func.call(this.gl, args...) is what is slowing it down but I am really not sure.

the code is below.

for (let [shader, mesh] of this.shaders) {

            shader.use(gl);

            let attributes = shader.attr;
            let uniforms   = shader.uni;

          

            for (let i = 0; i < mesh.length; i++) {


                const mesh_attr = mesh[i].attributes;

                for (let key in attributes) {

                    if (!attributes.hasOwnProperty(key)) continue;

                    if (mesh_attr[key] === undefined || mesh_attr[key] === null) {
                        console.warn(`mesh ${mesh[i].uuid} does not have the attribute ${key}\nwill not render this object`);
                        continue;
                    }


                    const numComponents = mesh_attr[key].size;
                    const type          = FLOAT;
                    const normalize     = false;
                    const stride        = 0;
                    const offset        = 0;

                    gl.bindBuffer(ARRAY_BUFFER, mesh_attr[key].buffer);

                    gl.vertexAttribPointer(
                        attributes[key],
                        numComponents,
                        type,
                        normalize,
                        stride,
                        offset);

                    gl.enableVertexAttribArray(attributes[key]);

                }

                if (mesh[i].geometry.indexed === true) {

                    {
                        gl.bindBuffer(ELEMENT_ARRAY_BUFFER, mesh_attr.indices.buffer);
                    }

                }


                const mesh_uni = mesh[i].uniforms;

                for (let key in uniforms) {

                    if (!uniforms.hasOwnProperty(key)) continue;

                    switch (key) {

                        case 'uModel':
                            uniforms[key].func.call(this.gl, uniforms[key].location, false, mesh[i].modelMatrix);

                            break;
                        case 'uProjection':
                            uniforms[key].func.call(this.gl, uniforms[key].location, false, projectionMatrix);

                            break;
                        case 'uView':
                            uniforms[key].func.call(this.gl, uniforms[key].location, false, viewMatrix);
                            break;
                        default:
                            if (uniforms[key].matrix) {
                                uniforms[key].func.call(this.gl, uniforms[key].location, false, mesh_uni[key].data);
                            }
                            else {
                                uniforms[key].func.call(this.gl, uniforms[key].location, mesh_uni[key].data);
                            }
                            break;


                    }


                }

                let vertexCount;

                if (mesh[i].geometry.indexed === true) {

                    vertexCount = mesh[i].attributes.indices.data.length;


                    const type   = gl.UNSIGNED_SHORT;
                    const offset = 0;
                    gl.drawElements(mesh[i].material.drawMode, vertexCount, type, offset);

                }

                else {


                    vertexCount = mesh[i].attributes.aPosition.data.length / mesh[i].attributes.aPosition.size;
                    const type  = gl.UNSIGNED_SHORT;

                    gl.drawArrays(mesh[i].material.drawMode, vertexCount, type);

                }


            }


        }

Does anyone know why im experiencing all this lag? I'm really not sure wht and I've been playing around with it for 2 days with no success. I'm not sure if its just my bad code :) or a weird bug in my code?

Any help would be greatly appreciated.

Also I am really sorry I couldn't think of an appropriate title so I put whatever and I dont think its very good.

  • `call`ing a function is certainly not the issue here, in short you want to avoid using buffers like you do, look at [this answer](https://stackoverflow.com/questions/27905214/why-is-my-simple-webgl-demo-so-slow/27912649#27912649) and the therein linked ones. For learning how to profile the CPU side of your application look at [this guide](https://developer.chrome.com/docs/devtools/evaluate-performance/). – LJᛃ Jul 18 '21 at 16:48
  • Yeh ur right. After a little rewrite, I realised that buffer binding is hella expensive and I have moved that to each geometry now. Also thank you a lot for state-cache idea, I will have to use an interleaved vertexarraybuffer (with my normals, uvs, indices ofc) but that shouldn't be too hard to setup. thanks again :)) – Samuel Cobb Jul 19 '21 at 12:30

0 Answers0