Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

No way to render shapes without graphics #2933

Closed
Dadibom opened this issue Sep 9, 2016 · 18 comments
Closed

No way to render shapes without graphics #2933

Dadibom opened this issue Sep 9, 2016 · 18 comments
Labels
📢 Accepting PRs Would welcome a PR from the community. 🥶 Low Priority Generally issues or PRs that don’t need to make it into the next release. Stale Previously “Won’t Fix”, bots should tag with this for inactive issues or pull-requests. 💾 v4.x (Legacy) Legacy version 4 support
Milestone

Comments

@Dadibom
Copy link

Dadibom commented Sep 9, 2016

Hey, I think I should be able to render rectangles without having to draw to graphics objects. It would make a lot of my code so much easier! :)

@GoodBoyDigital
Copy link
Member

Certainly something we could look at :)

@GoodBoyDigital GoodBoyDigital added this to the v4.1 milestone Sep 9, 2016
@ivanpopelyshev
Copy link
Collaborator

Well, you can use "Graphics._renderSpriteRect" approach. Graphics uses renderTexture and sprites for sipmle rectangles, you can do the same: create renderTexture, then use sprites.

var rect = this.graphicsData[0].shape;
    if(!this._spriteRect)
    {
        if(!Graphics._SPRITE_TEXTURE)
        {
            Graphics._SPRITE_TEXTURE = RenderTexture.create(10, 10);

            var currentRenderTarget = renderer._activeRenderTarget;
            renderer.bindRenderTexture(Graphics._SPRITE_TEXTURE);
            renderer.clear([1,1,1,1]);
            renderer.bindRenderTarget(currentRenderTarget);
        }

        this._spriteRect = new Sprite(Graphics._SPRITE_TEXTURE);
    }
    if (this.tint === 0xffffff) {
        this._spriteRect.tint = this.graphicsData[0].fillColor;
    } else {
        var t1 = tempColor1;
        var t2 = tempColor2;
        utils.hex2rgb(this.graphicsData[0].fillColor, t1);
        utils.hex2rgb(this.tint, t2);
        t1[0] *= t2[0];
        t1[1] *= t2[1];
        t1[2] *= t2[2];
        this._spriteRect.tint = utils.rgb2hex(t1);
    }
    this._spriteRect.alpha = this.graphicsData[0].fillAlpha;
    this._spriteRect.worldAlpha = this.worldAlpha * this._spriteRect.alpha;

    Graphics._SPRITE_TEXTURE._frame.width = rect.width;
    Graphics._SPRITE_TEXTURE._frame.height = rect.height;

    this._spriteRect.transform.worldTransform = this.transform.worldTransform;

    this._spriteRect.anchor.set(-rect.x / rect.width, -rect.y / rect.height);
    this._spriteRect.onAnchorUpdate();

    this._spriteRect._renderWebGL(renderer);

@GordoRank
Copy link

GordoRank commented Sep 9, 2016

We render rectangles, triangles and circles using only custom shaders. It's much faster than using Pixi Graphics objects and all edges are completely anti-aliased due to using a distance field calculation in the shader.

Adding outlines, glows, shadows and other effects to these shapes is trivial. We simply adjust color, strokeWidth, strokeColor and various effects uniforms for the shaders.

I would suggest looking into shader based shape/primitives rendering for a future version of Pixi, as it is infinitely superior to the current approach.

@Dadibom
Copy link
Author

Dadibom commented Sep 9, 2016

Yeah but the thing is that render textures are much more cpu heavy than simple primitives (a rectangle is a textureless quad with a shader) should be, and if I have to resize that shape a lot (which i usually do) then either performance will take a hit or it will require a lot more code.

@GoodBoyDigital
Copy link
Member

That sounds really interesting @GordoRank ! Would love to see your implementation!

@Dadibom - Graphics Rectangles are super optimised in pixi at the moment as they are batched into the sprite system. This is all done behind the scenes :)

I guess what your asking for is a short hand way of creating a rectangle?

@Dadibom
Copy link
Author

Dadibom commented Sep 9, 2016

Yeah but I still have to clear a texture and redraw it every frame, instead of just moving the individual rectangles

@GoodBoyDigital
Copy link
Member

How comes you need to clear them each frame?

@ivanpopelyshev
Copy link
Collaborator

@Dadibom use multiple graphics, change position every time.

As for your primitives, if you have something custom set, please make it a plugin. Especially if your stuff is tied to plots. https://github.com/pixijs/pixi-plugin-example . It will help others too.

@Dadibom
Copy link
Author

Dadibom commented Sep 9, 2016

Doesn't work if I want to change the size :(

@Dadibom
Copy link
Author

Dadibom commented Sep 9, 2016

Sure, I can use scale. But it's a lot more code than it has to be

@GordoRank
Copy link

GordoRank commented Sep 9, 2016

We basically have a complete PIXI powered desktop publishing application (shader based SDF text rendering / formatting, photo editing, page layout, drawing, bezier curves etc.) We simply extended PIXI a lot to meet our needs.

This is an old PIXI 3.0 version of a circle / ellipse shader that lets you set the width, height, opacity, strokeWidth, fillColor and strokeColor.

It's a bit messy and could be improved but it works perfectly for us. We have similar shaders for rectangles, triangles and pointed stars.

These shaders are applied to a custom Pixi renderer that simply applies the shaders to a textureless quad.


PIXI.filters.CircleShader = function(shaderManager) {


    PIXI.Shader.call(this,
        shaderManager,
        // vertex shader
        [
            'precision lowp float;',
            'attribute vec2 aVertexPosition;',
            'attribute vec2 aTextureCoord;',
            'attribute vec4 aColor;',

            'uniform mat3 projectionMatrix;',

            'varying vec2 vTextureCoord;',
            'varying vec4 vColor;',

            'void main(void){',
            '   gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);',
            '   vTextureCoord = aTextureCoord;',
            '   vColor = vec4(aColor.rgb * aColor.a, aColor.a);',
            '}'
        ].join('\n'),
        // fragment shader
        [
            '#extension GL_OES_standard_derivatives : enable',
            'precision mediump float;',

            'varying vec2 vTextureCoord;',

            'uniform float width;',
            'uniform float height;',
            'uniform float opacity;',
            'uniform vec4 fillColor;', 
            'uniform vec4 strokeColor;', 
            'uniform float strokeWidth;',

            'float texelSizeX = 1.0 / width;',
            'float texelSizeY = 1.0 / height;',

            'vec2 px = vec2(texelSizeX, texelSizeY);',
            'vec2 ab = vec2(width, height) / 2.0;',
            'vec2 center = vec2(0.5, 0.5);',


            'void main(void){',

            'vec2 pos = (vTextureCoord - center) / px;',
            'pos *= pos;',

            'float outerDist = dot(pos, 1.0 / (ab * ab));',

            'ab -= strokeWidth;',
            'float innerDist = dot(pos, 1.0 / (ab * ab));',

            'float outerDelta = length(vec2(dFdx(outerDist), dFdy(outerDist))) * 0.70710678118654757;',

            'float innerDelta = length(vec2(dFdx(innerDist), dFdy(innerDist))) * 0.70710678118654757;',

            'float innerAlpha = smoothstep(1.0 - innerDelta, 1.0 + innerDelta, innerDist);',
            'float outerAlpha = smoothstep(1.0 - outerDelta, 1.0 + outerDelta, outerDist);',


            'vec4 stroke = mix(strokeColor, vec4(0, 0, 0, 0), outerAlpha);',
            'vec4 fill = mix(fillColor, vec4(0, 0, 0, 0), innerAlpha);',

            'gl_FragColor = mix(vec4(0.0, 0.0, 0.0, 0.0), mix(fill, stroke, innerAlpha), opacity);',

            '}'
        ].join('\n'),
        // custom uniforms
        {
            dimensions: {
                type: '4fv',
                value: new Float32Array([0, 0, 0, 0])
            },
            projectionMatrix: { type: 'mat3', value: new Float32Array(9) },
            strokeWidth: {
                type: '1f',
                value: 0.0
            },
            strokeColor : { type: '4fv', value: new Float32Array([0, 0, 0, 0]) },
            fillColor : { type: '4fv', value: new Float32Array([0, 0, 0, 0]) },
            width : { type : '1f', value: 1.0},
            height : { type : '1f', value: 1.0},
            opacity : { type : '1f', value: 1.0}
        },
        // custom attributes
        {
            aTextureCoord:0,
            aVertexPosition:0,
            aColor:0
        }

    );


    this.strokeWidth = 0.0;
    this.strokeColor = new Float32Array([0, 0, 0, 0]);
    this.fillColor = new Float32Array([0, 0, 0, 0]);
    this.opacity = 1.0;


};

PIXI.filters.CircleShader.prototype = Object.create(PIXI.Shader.prototype);
PIXI.filters.CircleShader.prototype.constructor = PIXI.filters.CircleShader;

PIXI.ShaderManager.registerPlugin('circleShader', PIXI.filters.CircleShader);

I've stripped out the property definitions to keep this comment concise.

@Dadibom
Copy link
Author

Dadibom commented Sep 9, 2016

@GoodBoyDigital because i need to get rid of the old rectangle

@ivanpopelyshev
Copy link
Collaborator

@Dadibom good. You're on the half-way there to be official pixi plugin.

For v4 you can remove "args" parameter of the shader, arguments will be extracted automagically. Also, you cant set anything to uniforms unless shader is bound . When renderer sets value for uniforms it must be something like that:

myShader.bind();
myShader.uniforms.strokeWidth = ...;

Look at example renderer.

Also, shader code can be separated into "frag" and "vert" files, using glsify, example has it too.

@GoodBoyDigital
Copy link
Member

@GordoRank This is really exciting stuff! Would you consider sharing what you have - I think a lot of pixi users would find what you guys have created really awesome :)

@GordoRank
Copy link

GordoRank commented Sep 9, 2016

@GoodBoyDigital Of course. The team are currently tied up building a social networking and real time messaging infrastructure for the collaboration/community/social aspect of our app, and we therefore won't be out of beta until December at the earliest, so I can't really let anyone have a play now. But as soon as we are we will be setting up a developers blog describing our journey, challenges and techniques etc. As soon as that's up i'll share with you guys.

And once we have migrated to PIXI version 4, we will start to look at what we can potentially put back into PIXI in terms of plugins etc. I think the text layout and SDF font rendering would be a huge boon for you guys for starters.

@GoodBoyDigital
Copy link
Member

Amazing! I (and i'm sure the rest of the pixi community) look forward to December :)
Good luck with your beta release!

@englercj englercj added Plugin: Graphics 💾 v4.x (Legacy) Legacy version 4 support 🥶 Low Priority Generally issues or PRs that don’t need to make it into the next release. 📢 Accepting PRs Would welcome a PR from the community. labels Sep 29, 2016
@GoodBoyDigital GoodBoyDigital modified the milestones: v4.2, v4.1 Oct 11, 2016
@stale
Copy link

stale bot commented Feb 24, 2019

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the Stale Previously “Won’t Fix”, bots should tag with this for inactive issues or pull-requests. label Feb 24, 2019
@stagr
Copy link

stagr commented May 24, 2019

Kicking life into this old thread since I am interested in two aspects that @GordoRank mentions.

  1. shader based SDF text rendering
  2. shader based shapes rendering

Did you ever publish any of your work to the public?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
📢 Accepting PRs Would welcome a PR from the community. 🥶 Low Priority Generally issues or PRs that don’t need to make it into the next release. Stale Previously “Won’t Fix”, bots should tag with this for inactive issues or pull-requests. 💾 v4.x (Legacy) Legacy version 4 support
Projects
None yet
Development

No branches or pull requests

7 participants