最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Draw each pixel separately WebGL - Stack Overflow

programmeradmin0浏览0评论

First of all, let me talk about my target. I'm creating another one pixel art online editor and decide to make it with WebGL only (no Canvas2D at all). Pretty stupid of me because I have no knowledge in this technology, but I'm trying! So... the question: how to change the color of the only one pixel? I has struggled with another of my "misunderstand" and found this answer with particle system:

and I rewrote it to make it appear close to my case:

/

As you can see, there are 10 pixels with equal colour when you draw on canvas. Here the main draw method:

function mouseMoveEvent(e) {
    /*... detect x and y...*/
    gl.bindBuffer(gl.ARRAY_BUFFER, particleBuffer);
    var data = new Float32Array(2);
    data[0] = x;
    data[1] = y;
    gl.uniform4f(
        gl.getUniformLocation(shaderProgram, "color"),
        Math.random(),
        Math.random(),
        Math.random(),
        1.0
    );
    gl.bufferSubData(gl.ARRAY_BUFFER, particleId * particleSize * sizeOfFloat, data);
    particleId = (particleId + 1) % vertexBufferSize;
    gl.clear(gl.COLOR_BUFFER_BIT);
    gl.drawArrays(gl.POINTS, 0, vertexBufferSize);
}

So how to change this example to the pixels drawn each with a unique color?

Some of you probably say: "use canvas2d!". - No! I think that the future is not canvas2d. "So use library!". - No, again! For that "simple" thing like draw squares I don't want include large library.

Thank you!

First of all, let me talk about my target. I'm creating another one pixel art online editor and decide to make it with WebGL only (no Canvas2D at all). Pretty stupid of me because I have no knowledge in this technology, but I'm trying! So... the question: how to change the color of the only one pixel? I has struggled with another of my "misunderstand" and found this answer with particle system:

https://stackoverflow./a/16465343/4458277

and I rewrote it to make it appear close to my case:

https://jsfiddle/kurz/rt2n7hmb/1/

As you can see, there are 10 pixels with equal colour when you draw on canvas. Here the main draw method:

function mouseMoveEvent(e) {
    /*... detect x and y...*/
    gl.bindBuffer(gl.ARRAY_BUFFER, particleBuffer);
    var data = new Float32Array(2);
    data[0] = x;
    data[1] = y;
    gl.uniform4f(
        gl.getUniformLocation(shaderProgram, "color"),
        Math.random(),
        Math.random(),
        Math.random(),
        1.0
    );
    gl.bufferSubData(gl.ARRAY_BUFFER, particleId * particleSize * sizeOfFloat, data);
    particleId = (particleId + 1) % vertexBufferSize;
    gl.clear(gl.COLOR_BUFFER_BIT);
    gl.drawArrays(gl.POINTS, 0, vertexBufferSize);
}

So how to change this example to the pixels drawn each with a unique color?

Some of you probably say: "use canvas2d!". - No! I think that the future is not canvas2d. "So use library!". - No, again! For that "simple" thing like draw squares I don't want include large library.

Thank you!

Share Improve this question edited May 23, 2017 at 12:02 CommunityBot 11 silver badge asked Aug 8, 2015 at 11:02 KurzKurz 4135 silver badges13 bronze badges 4
  • 2 WebGL is for 3D, use Canvas :-P. I respect your choice to use whatever you want. But it does equal to saying "I will not use a hammer to hammer this nail, I will use my truck to do it because thats what I decided to do" – EJTH Commented Aug 8, 2015 at 11:10
  • 1 But there are lot of awesome 2d graphic engines based on WebGL! (Pixi.js) – Kurz Commented Aug 8, 2015 at 11:15
  • 2 Still you want to do an "Online pixel art editor", then why not use canvas? It has alot of good features for you (Export jpg,png etc, easy 2d drawing etc). It has more support as well. – EJTH Commented Aug 8, 2015 at 11:16
  • 1 WebGL is just fine for 2D. WebGL is not for 3D. WebGL is a rasterizing engine. You do what you want with it. This entire webpage is rendered in OpenGL ES 2.0 if you're in Chrome. The same tech that WebGL is based on. – user128511 Commented Aug 9, 2015 at 20:38
Add a ment  | 

2 Answers 2

Reset to default 3

What you need to understand about that code which you posted is that it is passing a variable to the fragment shader, it is not doing any drawing. The fragment shader is doing the drawing.

OpenGL is a tool to manipulate different stages of the rendering process on modern graphics cards. It does not try to cover the use case of blitting pixels to the screen buffer. (glDrawPixels was deprecated and is not available in ES 2.0 or WebGL)

However there are ways that you could use it in your application.

I remend these two articles to understand the prerequisites, although you should be aware it is intended for openGL 3.2 and C++, not WebGL and Javascript. So you can ignore things such as context creation, the way in which textures are loaded and you don't have to create VertexArrays.

WebGL solution 1:

  • Create an empty texture.
  • Every frame, Draw a quad to the screen which displays this texture.
  • On mouse clicks, call glTexSubImage2D to modify 1 pixel within the texture.

WebGL solution 2:

  • Change gl_PointSize (Vertex shader line 8)
  • Only draw 1 point
  • Don't clear the screen (javascript line 45)
  • Preserve the webGL screen buffer (javascript lines 86 or 89)

See modified source

This solution is not modifying 1 exact pixel, I think Solution 1 is a better way to do it

Why you should use Canvas2D:

It is a mistake to consider to Canvas2D is inferior to WebGL, One is a screwdriver and the other is hammer. One is great for attaching things with screws the other is great for attaching things with Nails.

Use WebGL when you want to manipulate a 3d render pipeline, use Canvas2D when you want to manipulate raster images.

TL;DR:

If you use Canvas2D you can start making the application you want to today with good performance. If you want to use WebGL, you should make an effort to understand the stages of the render pipeline.

The direct answer to your question is that gl.uniform4f is a global variable. So you are effectively doing this:

var color = randomColor(); // uniform4f call
for each point:
    drawPoint(p.x, p.y,color);

You need to change it into this:

for each point:
    var color = gl.uniform4f(...);
    drawPoint(p.x, p.y, color);

However, I want to note that using a particle system for doing a pixel editor is probably not the way to go. Imagine what happens if the user repeatedly move around the same area, you would have a lot of redundant data. Secondly, how do you (efficiently) support the erase operation? Or Fill?

Eventually, I think you want to move onto using textures. Textures are basically a fancy name for an array of data, but with limitations on its format and what it can contains. However, GPUs can access them really really fast. So what you want to do is draw a quad the same size of screen and give it individual pixel data via a texture to tell it what to draw. Then manipulate the texture data directly when the user does things and redraw.

It is really too long to include how to implement this in webgl, so I suggest following some tutorials on the web. The best one atm for webgl is the webgl fundamentals series. I suggest starting from there.

发布评论

评论列表(0)

  1. 暂无评论