EvelynEve

Question About Scrolling/Scaling

Recommended Posts

I'm rather new to Pixi.js, so please bear with me!

I'm converting WebGL into Pixi due to a number of factors. In the WebGL code, we use a shader to "scale" or "zoom" in on relevant data. When I made this into a custom filter, it caused a lot of blurry lines (using Graphics objects to draw a bunch of non-static lines, real time data) and makes it unusable. This was not the case in WebGL, which simply draws the points at their relative locations (the shader is just normalizing these points around the min/max of the data). 

Am I doing something wrong or should I be doing something differently? Here is the relevant snippet of code for the shader:

float xNorm = (aVertexPosition.x - xMin) / (xMax - xMin);
float yNorm = (aVertexPosition.y - yMin) / (yMax - yMin);
gl_Position = vec4(
   xNorm * 2.0 - 1.0,
   yNorm * 2.0 - 1.0,
   0.0,
   1.0);

Thank you for any help or advice! 

Share this post


Link to post
Share on other sites

That is big problem, but I studied it.

The best way to get that data is to multiply by some matrix.

If you are talking about custom filters, please look at their code and which matrices do they use, which helper methods provide them. Please use DisplacementFilter and TwistFilter as a reference. You dont have to calculate the matrix or all these yMax/yMin values, just find already existant helper method that provides it.

One of the main problems is that target framebuffer for a filter in pixi-v4 is power-of-two texture and its larger than your working area.

Please checkout latest version from DEV branch to find that code: https://github.com/pixijs/pixi.js/tree/dev

And may "filterTransforms.js" be with you.

Share this post


Link to post
Share on other sites

Hello. I figured there was some matrix transformation method I was just missing. As I said before, the filter works just fine. It does what I expect it to do in terms of scaling/zooming the data correctly. The issue is that it becomes too blurry/the quality degrades on the graphics object. 

I'm not sure what you mean by the target framebuffer. Could you please clarify?

EDIT: Also the way we're handling the xMin/xMax values are important to the functionality of the overall ... object? Game? Module? Not sure what to call it haha. 

Share this post


Link to post
Share on other sites

Filter manager pools pow2 framebuffers, so when you render 400x400 container with 6 padding, it takes 512x512 texture instead of 412x412. That changes gl_Position.

If you really need xMin/xMax , you make it two points "min" and "max" and apply some matrix to them.

You may show me screenshots of original and pixi demos, I cant figure out what's your problem yet. All words I wrote are just my experience with it :)

Share this post


Link to post
Share on other sites
10 minutes ago, ivan.popelyshev said:

Filter manager pools pow2 framebuffers, so when you render 400x400 container with 6 padding, it takes 512x512 texture instead of 412x412. That changes gl_Position.

If you really need xMin/xMax , you make it two points "min" and "max" and apply some matrix to them.

You may show me screenshots of original and pixi demos, I cant figure out what's your problem yet. All I wrote are just my experience with it :)

I think I understand. I'm still no closer to understanding where that matrix transformation should be happening. 

Here is the picture of what it looked like before:

before.png

And this is what it looks like with pixi (minus some padding that is added to the before picture that I hadn't gotten around to doing in the after picture yet): 

after.png

Share this post


Link to post
Share on other sites

@ivan.popelyshev suggested I try overriding the primitive shader to get the desired effect. I did so with some slight modifications to allow the translations and now don't see anything. Here is the shader I am using:

function PrimitiveShader(shaderManager)
{
    Shader.call(this,
        shaderManager,
        // vertex shader
        [
            'attribute vec2 aVertexPosition;',
            'attribute vec4 aColor;',

            'uniform mat3 translationMatrix;',
            'uniform mat3 projectionMatrix;',

            'uniform float xMin;',
            'uniform float xMax;',
            'uniform float yMin;',
            'uniform float yMax;',

            'uniform float alpha;',
            'uniform float flipY;',
            'uniform vec3 tint;',

            'varying vec4 vColor;',

            'void main(void) {',
                'float xNorm = (aVertexPosition.x - xMin) / (xMax - xMin);',
                'float yNorm = (aVertexPosition.y - yMin) / (yMax - yMin);',

                'gl_PointSize = 8.0;',
                'gl_Position = vec4(',
                    '(projectionMatrix * translationMatrix * ' +
                    'vec3(' +
                        'xNorm * 2.0 - 1.0,' +
                        'yNorm * 2.0 - 1.0,' +
                        '1.0)).xy,',
                    '0.0,',
                    '1.0);',
                'vColor = aColor * vec4(tint * alpha, alpha);',
            '}'
        ].join('\n'),
        
        // [
        //     'attribute vec2 aVertexPosition;',
        //     'attribute vec4 aColor;',
        //
        //     'uniform mat3 translationMatrix;',
        //     'uniform mat3 projectionMatrix;',
        //
        //     'uniform float alpha;',
        //     'uniform float flipY;',
        //     'uniform vec3 tint;',
        //
        //     'varying vec4 vColor;',
        //
        //     'void main(void){',
        //     '   gl_Position = vec4((projectionMatrix * translationMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);',
        //     '   vColor = aColor * vec4(tint * alpha, alpha);',
        //     '}'
        // ].join('\n'),
        // fragment shader
        [
            'precision mediump float;',

            'varying vec4 vColor;',

            'void main(void){',
            '   gl_FragColor = vColor;',
            '}'
        ].join('\n'),
        // custom uniforms
        {
            tint:   { type: '3f', value: [0, 0, 0] },
            alpha:  { type: '1f', value: 0 },
            translationMatrix: { type: 'mat3', value: new Float32Array(9) },
            projectionMatrix: { type: 'mat3', value: new Float32Array(9) },
            xMin: { type: 'f', value: 0 },
            xMax: { type: 'f', value: 100 },
            yMin: { type: 'f', value: 0 },
            yMax: { type: 'f', value: 100 }
        },
        // custom attributes
        {
            aVertexPosition:0,
            aColor:0
        }
    );
}

This is what I am seeing:

after01.png

This is what I see if I allow the original shader to run:

before01.png

And this is what I am expecting to see (more or less):

before.png

Does anyone have any advice? 

Share this post


Link to post
Share on other sites

I believe that yours minX, maxX things can be embedded into matrices (projectionMatrix and translationMatrix). Can you just position your Graphics element that way it fits (0, 0) - (renderer.width, renderer.height) ? 

 

PIXI projects (0,0)-(renderer.width,renderer.height) to (-1,-1)-(1,1) and that's what projectionMatrix for. You can change Graphics position and scale that way (minX,minY)-(maxX,maxY) will be transformed into (0,0)-(renderer.width,renderer.height) by translationMatrix.

Share this post


Link to post
Share on other sites
4 minutes ago, ivan.popelyshev said:

I believe that yours minX, maxX things can be embedded into matrices (projectionMatrix and translationMatrix). Can you just position your Graphics element that way it fits (0, 0) - (renderer.width, renderer.height) ? 

 

PIXI projects (0,0)-(renderer.width,renderer.height) to (-1,-1)-(1,1) and that's what projectionMatrix for. You can change Graphics position and scale that way (minX,minY)-(maxX,maxY) will be transformed into (0,0)-(renderer.width,renderer.height) by translationMatrix.

Could you point me to some resources about the projection matrix so I can better understand what value is where for manipulation? I understand you're saying to just throw it in there, but the question is where and how. I can't find anything about it beyond people mentioning it exists and code references within the source. 

Preferably a tutorial with some examples of projection matrix transformations. 

Share this post


Link to post
Share on other sites
8 minutes ago, EvelynEve said:

Could you point me to some resources about the projection matrix so I can better understand what value is where for manipulation? I understand you're saying to just throw it in there, but the question is where and how. I can't find anything about it beyond people mentioning it exists and code references within the source. 

Preferably a tutorial with some examples of projection matrix transformations. 

Basically, if you multiply your result by projectionMatrix, then you can use SCREEN coordinates (0,0)-(renderer.width, renderer.height) instead of standart webgl (-1,-1) - (1,1) , (btw, its reverted by Y axis)

If you want to move graphics around, use its position and scale, that will modify translationMatrix.

If you want just animate some lines, do it in SCREEN coordinates, forget about your min-max stuff.

Share this post


Link to post
Share on other sites
1 minute ago, ivan.popelyshev said:

Basically, if you multiply your result by projectionMatrix, then you can use SCREEN coordinates (0,0)-(renderer.width, renderer.height) instead of standart webgl (-1,-1) - (1,1)

If you want to move graphics around, use its position and scale. If you want just animate some lines, do it in SCREEN coordinates, forget about your min-max stuff.

The problem is the data sets I am using. I can't use screen coordinates, I need to use WebGL coordinates. I can't forget the min/max stuff, it's the whole reason the program even works. I'm not really sure what you mean by result (vague). I have been trying to scale and the scaling has the same problems as the filters. It doesn't fix anything and I'm pretty sure it's slower. 

Share this post


Link to post
Share on other sites
4 minutes ago, ivan.popelyshev said:

OK, use standart shader and graphics object, and try this:


graphics.pivot.set(minX, maxY);

graphics.scale.set((maxX-minX) / renderer.width, (maxY - minY) / renderer.height);

 

No luck. Nothing shows up. Just a black box. 

EDIT: I am using a polygon to draw the array of x and y points. 

Share this post


Link to post
Share on other sites
1 minute ago, ivan.popelyshev said:

Sorry , my bad.

 


graphics.pivot.set(minX, maxY);

graphics.scale.set((maxX-minX) / renderer.width, (minY - maxY) / renderer.height);

Please post your example somewhere (jsfiddle?)

It's too large and sensitive to post somewhere, sorry. 

Still no luck with that. 

Share this post


Link to post
Share on other sites

OK, I think you have mistaken in resizing canvas or something like that, otherwise i dont know how did you get that kind of effect on line. Please post minimal demo, just make it from scratch and post in jsfiddle. That's normal practice for consultations about sensitive stuff - you make a demo and then we fix it and show how it really must be done

Share this post


Link to post
Share on other sites
6 minutes ago, ivan.popelyshev said:

graphics.pivot.set(minX, maxY);

graphics.scale.set(renderer.width/(maxX-minX), renderer.width/(minY - maxY));

Please do not use your shader AT ALL, just put all coordinates in graphics and add these two lines.

I am not using the shader at all. I'm using the normal/default shader. These are all more or less things I have already tried to do unsuccessfully. 

Also, I missed the result of the last try. It gives me this: 

teensy.png

There's a teensy triangle of lines at the top. 

That last bit of math is better, but still has an issue with the scaling of the lines which worries me that it could cause other problems later. Much better than what was happening before though:

download.png

 

EDIT: I'd still just prefer using my own shader, however. It's more reliable and faster. I'll be dealing with a lot of data. I'd prefer just trying to figure out why the primitive shader override is simply not working as opposed to using both scaling and setting the pivot. All the things drawn on my canvases will require this type of scaling, so I don't see it being a problem unless there is something I am missing or changes have been made to scaling which I did not read about previously. 

Share this post


Link to post
Share on other sites

OK, then I have better solution for you 

function getX(u) {
    return (u-minX) / (maxX-minX) * renderer.width;
}

function getY(v) {
    return (v-maxY) / (minY - maxY) * renderer.height;
}

use it every time when you pass coords to graphics.

Its working differently because "graphics.lineTo(getX(x), getY(y)) wont change the width of line, while scale is actually doing it :)

You can even hook it in graphics: make your own lineTo moveTo that will take into account your min-max transformation. Pass width and height too :)

By the way, THATS A FREAKING AWESOME IDEA: "plotTransform" that changes point coords by does not scale lines width :)

Share this post


Link to post
Share on other sites
9 minutes ago, ivan.popelyshev said:

OK, then I have better solution for you 


function getX(u) {
    return (u-minX) / (maxX-minX) * renderer.width;
}

function getY(v) {
    return (v-maxY) / (minY - maxY) * renderer.height;
}

use it every time when you pass coords to graphics.

Its working differently because "graphics.lineTo(getX(x), getY(y)) wont change the width of line, while scale is actually doing it :)

You can even hook it in graphics: make your own lineTo moveTo that will take into account your min-max transformation. Pass width and height too :)

By the way, THATS A FREAKING AWESOME IDEA: "plotTransform" that changes point coords by does not scale lines width :)

Good idea!

Unfortunately, I'm dealing with a LOT of data. I'm not using the native lineTo/moveTo methods. I am, instead, using the polygon and passing it an array of x and y coordinates, as I mentioned before. Sadly, that would be a LOT of extra load to process, which is why I was hoping to just do it via GPU shaders that can leave the CPU alone. 

Share this post


Link to post
Share on other sites

The problem with lines in Graphics - they do not exist. Every stroked line is made of triangles, because lineWidth needs to be taken into account.

Did you use gl.LINES in original code? If so, then I can help you to make an object (not graphics!) with its own renderer and shader that will do it.

Anyway, can we please move it to chat? please send me your email in PM, I wlil add you to pixi slack and we'll solve your issue :)

Share this post


Link to post
Share on other sites
Just now, ivan.popelyshev said:

The problem with lines in Graphics - they do not exist. Every stroked line is made of triangles, because lineWidth needs to be taken into account.

Did you use gl.LINES in original code? If so, then I can help you to make an object (not graphics!) with its own renderer and shader that will do it.

Yes. I know that. 

I did originally use gl.LINES. If you have any resources you could point me to, I would greatly appreciate it. 

Share this post


Link to post
Share on other sites
Just now, ivan.popelyshev said:

We can copy src/Mesh and make a thing that works with your data, it wont be that difficult :) Do you want me to do it? That way you'll have super-speedy webgl solution that will beat your original solution by usability :) 

I'd prefer to do it myself since I need to know how to use this stuff. Are you think of copying Mesh.js or is there another file I should be looking at? 

Share this post


Link to post
Share on other sites

1. copy the mesh, name it "MegaLine". You can use the same shader as mesh. just call gl.LINES instead of gl.TRIANGLES. You can even hack original mesh that way it can choose between LINES and TRIANGLES. you can pass empty array as uvs.

2. make a container , use that trick:

plotContainer.pivot.set(minX, maxY);

plotContainer.scale.set(renderer.width / (maxX-minX), renderer.height / (minY - maxY));

3. for every plot line, add a modified mesh inside the container.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...

  • Recently Browsing   0 members

    No registered users viewing this page.