javascript中的高效粒子系统? (WebGL的) [英] Efficient particle system in javascript? (WebGL)

查看:107
本文介绍了javascript中的高效粒子系统? (WebGL的)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试编写一个程序,对粒子进行一些基本的重力物理模拟。我最初使用标准Javascript图形(带有2d上下文)编写程序,我可以通过这种方式获得大约25 fps w / 10000粒子。我在WebGL中重写了这个工具,因为我假设我可以通过这种方式获得更好的结果。我也使用glMatrix库进行矢量数学运算。然而,通过这种实现,我只获得了大约15fps的10000粒子。

I'm trying to write a program that does some basic gravity physics simulations on particles. I initially wrote the program using the standard Javascript graphics (with a 2d context), and I could get around 25 fps w/10000 particles that way. I rewrote the tool in WebGL because I was under the assumption that I could get better results that way. I am also using the glMatrix library for vector math. However, with this implementation I'm getting only about 15fps with 10000 particles.

我目前是EECS本科生,我有一定的编程经验,但从来没有图形,我对如何优化Javascript代码几乎没有任何线索。
我对WebGL和Javascript的工作方式有很多不了解。使用这些技术时,哪些关键组件会影响性能?是否有更有效的数据结构来管理我的粒子(我只是使用一个简单的数组)?使用WebGL可以解决性能下降的问题? GPU和Javascript之间的延迟可能是什么?

I'm currently an EECS undergrad and I have had a reasonable amount of experience programming, but never with graphics, and I have little clue as to how to optimize Javascript code. There is a lot I don't understand about how WebGL and Javascript work. What key components affect performance when using these technologies? Is there a more efficient data structure to use to manage my particles (I'm just using a simple array)? What explanation could there be for the performance drop using WebGL? Delays between the GPU and Javascript maybe?

任何建议,解释或帮助都会非常感激。

Any suggestions, explanations, or help in general would be greatly appreciated.

我会尝试仅包含我的代码的关键区域以供参考。

I'll try to include only the critical areas of my code for reference.

这是我的设置代码:

gl = null;
try {
    // Try to grab the standard context. If it fails, fallback to experimental.
    gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
    gl.viewportWidth = canvas.width;
    gl.viewportHeight = canvas.height;
}
catch(e) {}

if(gl){
        gl.clearColor(0.0,0.0,0.0,1.0);
        gl.clearDepth(1.0);                 // Clear everything
        gl.enable(gl.DEPTH_TEST);           // Enable depth testing
        gl.depthFunc(gl.LEQUAL);            // Near things obscure far things

        // Initialize the shaders; this is where all the lighting for the
        // vertices and so forth is established.

        initShaders();

        // Here's where we call the routine that builds all the objects
        // we'll be drawing.

        initBuffers();
    }else{
        alert("WebGL unable to initialize");
    }

    /* Initialize actors */
    for(var i=0;i<NUM_SQS;i++){
        sqs.push(new Square(canvas.width*Math.random(),canvas.height*Math.random(),1,1));            
    }

    /* Begin animation loop by referencing the drawFrame() method */
    gl.bindBuffer(gl.ARRAY_BUFFER, squareVerticesBuffer);
    gl.vertexAttribPointer(vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0);
    requestAnimationFrame(drawFrame,canvas);

抽奖循环:

function drawFrame(){
    // Clear the canvas before we start drawing on it.
    gl.clear(gl.COLOR_BUFFER_BIT);

    //mvTranslate([-0.0,0.0,-6.0]);
    for(var i=0;i<NUM_SQS;i++){
        sqs[i].accelerate();
        /* Translate current buffer (?) */
        gl.uniform2fv(translationLocation,sqs[i].posVec);
        /* Draw current buffer (?) */;
        gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
    }
    window.requestAnimationFrame(drawFrame, canvas);
}

以下是Square继承的类:

Here is the class that Square inherits from:

function PhysicsObject(startX,startY,size,mass){
    /* Class instances */
    this.posVec = vec2.fromValues(startX,startY);
    this.velVec = vec2.fromValues(0.0,0.0);
    this.accelVec = vec2.fromValues(0.0,0.0);
    this.mass = mass;
    this.size = size;

    this.accelerate = function(){
            var r2 = vec2.sqrDist(GRAV_VEC,this.posVec)+EARTH_RADIUS;
            var dirVec = vec2.create();
            vec2.set(this.accelVec,
                G_CONST_X/r2,
                G_CONST_Y/r2
            );

        /* Make dirVec unit vector in direction of gravitational acceleration */
        vec2.sub(dirVec,GRAV_VEC,this.posVec)
        vec2.normalize(dirVec,dirVec)
        /* Point acceleration vector in direction of dirVec */
        vec2.multiply(this.accelVec,this.accelVec,dirVec);//vec2.fromValues(canvas.width*.5-this.posVec[0],canvas.height *.5-this.posVec[1])));

        vec2.add(this.velVec,this.velVec,this.accelVec);
        vec2.add(this.posVec,this.posVec,this.velVec);
    };
}

这些是我正在使用的着色器:

These are the shaders I'm using:

 <script id="shader-fs" type="x-shader/x-fragment">
        void main(void) {
        gl_FragColor = vec4(0.7, 0.8, 1.0, 1.0);
        }
    </script>

    <!-- Vertex shader program -->

    <script id="shader-vs" type="x-shader/x-vertex">
        attribute vec2 a_position;

        uniform vec2 u_resolution;

        uniform vec2 u_translation;

        void main() {
        // Add in the translation.
        vec2 position = a_position + u_translation;
        // convert the rectangle from pixels to 0.0 to 1.0
        vec2 zeroToOne = position / u_resolution;

        // convert from 0->1 to 0->2
        vec2 zeroToTwo = zeroToOne * 2.0;

        // convert from 0->2 to -1->+1 (clipspace)
        vec2 clipSpace = zeroToTwo - 1.0;

        gl_Position = vec4(clipSpace*vec2(1,-1), 0, 1);
        }
    </script>

我很抱歉这是啰嗦。同样,任何正确方向的建议或推动都将是巨大的。

I apologize for this being long-winded. Again, any suggestions or nudges in the right direction would be huge.

推荐答案

你不应该单独绘制基元。尽可能一次性地绘制它们。创建一个ArrayBuffer,它包含所有粒子的位置和其他必要属性,然后通过一次调用gl.drawArrays绘制整个缓冲区。
我无法给出确切的说明,因为我在移动设备上但是在opengl中搜索vbo,交错数组和粒子肯定会帮助你找到示例和其他有用的资源。

you should never draw primitives individualy. Draw them all at once, whenever possible. Create an ArrayBuffer that contains position and other necessary attributes of all particles and then draw the whole buffer with one call to gl.drawArrays. I can't give exact instructions because I'm on mobile but searching for vbo, interleaved arrays, and particles in opengl will surely help you find examples and other helpful resources.

我用10fps渲染5m静态点。动态点数将会变慢,因为您必须不断向显卡发送更新的数据,但它会比10000点的速度快15fps。

I'm rendering 5m static points that way with 10fps. Dynamic points will be slower as you'll have to continually send updated data to the graphics card but it will be way faster than 15fps for 10000 points.

编辑:

您可能希望使用gl.POINT而不是TRIANGLE_STRIP。这样,您只需为每个方块指定位置和gl_PointSize(在顶点着色器中)。 gl.POINT呈现为正方形!

You might want to use gl.POINT instead of TRIANGLE_STRIP. That way, you only have to specify the position and and gl_PointSize(in the vertex shader) for each square. gl.POINT are rendered as squares!

您可以查看这两个点云渲染器的来源:

  • https://github.com/asalga/XB-PointStream
  • http://potree.org/wp/download/ (通过我,以下文件可能对您有所帮助:WeightedPointSizeMaterial.js,pointSize。 vs,colouredPoint.fs)

    You can take a look at the source of these two point cloud renderer:

  • https://github.com/asalga/XB-PointStream
  • http://potree.org/wp/download/ ( By me, following files might help you: WeightedPointSizeMaterial.js, pointSize.vs, colouredPoint.fs )

    这篇关于javascript中的高效粒子系统? (WebGL的)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆