InsOp Posted November 24, 2014 Share Posted November 24, 2014 Hello dear PixiJS community,finally i began to love pixijs now I want to a ) outline a sprite (from a png file as a texture)like ive done it here with canvas:https://twitter.com/InsOp_de/status/514917023839944704b ) change a certain color into another one (usually magenta or pink)again, like in my example the blue square.that way i dont have to make a sprite for every color, but use only one andmanipulate the image data. With canvas i did it like that// getting Stuff var imgData = game.canvasForegroundContext.getImageData(x, y, imageSize, imageSize); var data = imgData.data; //height of the image section var row = imgData.data.length/imageSize; var sur = { nw:-row-4,n:-row,no:-row+4, w:-4, o:+4, sw:+row-4,s:+row,so:+row+4 }; for (var i = 0; i < data.length; i += 4) { //surroundings if(data[i+3]!=255){ for(var key in sur){ j = i+sur[key] //ignore shadows, check if isnt already an outline if(data[j+3]>100 && data[j] != rgba.r && data[j + 1] != rgba.g && data[j + 2] != rgba.{ data[i] = rgba.r; data[i + 1] = rgba.g; data[i + 2] = rgba.b; data[i + 3] = rgba.a; } } } }and this was pretty ugly. is there already a filter or a function for this? or perhaps is there something like "imgData.data;" ? Quote Link to comment Share on other sites More sharing options...
InsOp Posted December 1, 2014 Author Share Posted December 1, 2014 *push*come on guys, is there something like an outline or a glow for sprites? Quote Link to comment Share on other sites More sharing options...
agamemnus Posted December 2, 2014 Share Posted December 2, 2014 You have to make a webgl filter for it (somewhat complex, but not impossible), or modify it as a 2d canvas and then generate a texture from it. InsOp 1 Quote Link to comment Share on other sites More sharing options...
InsOp Posted December 3, 2014 Author Share Posted December 3, 2014 Thanks!Hmm Since i have a Working function in 2d canvas I like the second solution.But for the first solution: how to manipulate webgl data in a sprite? Edit: I found this fiddle: http://jsfiddle.net/Eskel/g593q/9/but no Idea how to implement that with pixijs Quote Link to comment Share on other sites More sharing options...
agamemnus Posted December 4, 2014 Share Posted December 4, 2014 Yes, I found that link too. Actually got a step by step lesson on how to do this in my IRC logs. If you want, I can PM you the whole log of me talking with another guy in #webgl on Freenode about making a border filter. I didn't bother with trying to go much further with it, because I got my game fast enough to not need this. "How to manipulate webgl data in a sprite?" You don't. You manipulate the texture, and then you make a sprite from that texture using (IIRC) .fromCanvas... Quote Link to comment Share on other sites More sharing options...
bubamara Posted December 4, 2014 Share Posted December 4, 2014 Edit: I found this fiddle: http://jsfiddle.net/Eskel/g593q/9/but no Idea how to implement that with pixijsthis will not outline picture drawn on your texture, but only rectangle on which is texture mapped. and in webgl only what you can do is to have two textures :- 1st will be your original texture- 2nd will be modified texture like you already did with your code ( draw orinigal texture to hidden canvas, do the magic stuff, get new texture using PIXI.Texture.fromCanvas) and then switch them accordingly: mySprite.mouseover = function() { this.setTexture(outlinedTexture);} mySprite.mouseout = function() { this.setTexture(originalTexture);} and this will be working with both - canvas & webgl renderer Quote Link to comment Share on other sites More sharing options...
agamemnus Posted December 10, 2014 Share Posted December 10, 2014 bubamara, that is a fine strategy if you have a very small amount of textures. But if the game is texture heavy, your technique doubles texture use. In my jigsaw game, I recreate each piece from the base image and cut based on a set of bezier curves. Then I apply the outline, or not, and create/destroy the texture as needed. One con of my approach is that for real-time outline color fading/switching effects, this may be a little on the slow side. I do have such effects but I mitigate the problem by only changing colors every 6 frames or so, instead of every frame. Quote Link to comment Share on other sites More sharing options...
achexi Posted December 10, 2014 Share Posted December 10, 2014 http://gamemechanicexplorer.com/#lightning-3 have a look at this. Quote Link to comment Share on other sites More sharing options...
msha Posted December 18, 2014 Share Posted December 18, 2014 b ) change a certain color into another one (usually magenta or pink) ColorMatrixFilter - http://www.html5gamedevs.com/topic/9679-colormatrixfilter-documentation/ a ) outline a sprite (from a png file as a texture)like ive done it here with canvas:https://twitter.com/InsOp_de/status/514917023839944704 You can create a pink version of your sprite using ColorMatrixFilter, scale it up slightly, and put it under the real sprite. But this "outline" will not be very accurate. Might work for simple shapes... InsOp 1 Quote Link to comment Share on other sites More sharing options...
JDW Posted December 19, 2014 Share Posted December 19, 2014 Here is a webgl/threejs example of what you want to do. It might help. http://jsfiddle.net/Eskel/g593q/9/ Quote Link to comment Share on other sites More sharing options...
msha Posted December 22, 2014 Share Posted December 22, 2014 I just found out that Pixi has a ConvolutionFilter, that combined with ColorMatrixFilter can be used to create nice outlines: http://codepen.io/mishaa/pen/bNeyMz InsOp 1 Quote Link to comment Share on other sites More sharing options...
agamemnus Posted January 2, 2015 Share Posted January 2, 2015 Thanks msha, that is awesome. I'd be using that right away, but this isn't quite ideal. I'd prefer to use one sprite... Quote Link to comment Share on other sites More sharing options...
msha Posted January 3, 2015 Share Posted January 3, 2015 Then you need a custom shader. I've never written a shader myself but looking at the source code of ConvolutionFilter it does not seem too hard to modify it to create outlines. Quote Link to comment Share on other sites More sharing options...
InsOp Posted January 31, 2015 Author Share Posted January 31, 2015 Thank you for your answers!@mshaa) i think your solution is what i needed, just implemented it in my game and had a performance issue, since i had a lot of sprites with all those filters on them so i tweaked yoursolution a little bit: http://codepen.io/InsOp/pen/EawxbO(created a temporary renderer in which I copy the sprite via toDataURL and give that back instead of the sprite with the many filters) b ) now i understand color matrices, thank you! but it didnt solved my issue which is to replace a certain color like #ff00d2 to another.With those color matrices i am only able to change colordues, for example all red dues, instead of a certain red shade which is what i need Quote Link to comment Share on other sites More sharing options...
msha Posted February 1, 2015 Share Posted February 1, 2015 Thank you for your answers!@mshaa) i think your solution is what i needed, just implemented it in my game and had a performance issue, since i had a lot of sprites with all those filters on them so i tweaked yoursolution a little bit: http://codepen.io/InsOp/pen/EawxbO(created a temporary renderer in which I copy the sprite via toDataURL and give that back instead of the sprite with the many filters)I made an outline shader recently, it's faster and creates better antialiased outlines than that version, feel free to use it - http://codepen.io/mishaa/pen/emGNRBBut caching the outline is still a good idea. b ) now i understand color matrices, thank you! but it didnt solved my issue which is to replace a certain color like #ff00d2 to another.With those color matrices i am only able to change colordues, for example all red dues, instead of a certain red shade which is what i needThat's easy: http://codepen.io/mishaa/pen/emGNXE InsOp 1 Quote Link to comment Share on other sites More sharing options...
InsOp Posted February 1, 2015 Author Share Posted February 1, 2015 works like a charm! *consider the problem solved!even tho i think those should be native filters in pixijs! whats written in fragmentSrc - is this webgl/opengl? * I had trouble with the OutlineFilter - so I used OutlineFilterMultiPass, which is fast enough if I initialize the filter while loading, not while runtime.anyway those are the results I had with OutlineFilter: (notice two of the small buildings work - not all of them tho) Quote Link to comment Share on other sites More sharing options...
msha Posted February 1, 2015 Share Posted February 1, 2015 @InsOpYes, that's OpenGL shading language - GLSL. " I had trouble with the OutlineFilter - so I used OutlineFilterMultiPass" I guess it was because of the shader property, which is a little limited, for example it only works for sprites, not DOC-s(but it's faster). Also I had a mistake in my example, If you use the shader property, the arguments should be baseTexture width and height: sprite.shader = new OutlineFilter(sprite.texture.baseTexture.width, sprite.texture.baseTexture.height,....); that asymmetry of outlines must be caused by that. Quote Link to comment Share on other sites More sharing options...
InsOp Posted February 1, 2015 Author Share Posted February 1, 2015 Ah I see - have to get known to this! The difference between those who worked, and those who didnt is, that those who work only have one element in their spriteSheet-ArrayPIXI.Sprite.fromFrame(item.spriteSheet[ item.direction ]);so the animated ones are the problem (and even those who arent animated in the moment but have a spriteSheet.length > 1)this should not interfere with the shader at all, but i cant get up with another explanation - and i didnt used DOCs in the first place(but I started to use them right now)so still the same problem: [but im fine - with the other method it works just perfectly fine] Quote Link to comment Share on other sites More sharing options...
msha Posted February 2, 2015 Share Posted February 2, 2015 House outlines are not perfect on this screenshot, horizontal lines are much thicker than vertical, are you sure you're passing renderer.width and height as arguments to the filter? Quote Link to comment Share on other sites More sharing options...
InsOp Posted February 2, 2015 Author Share Posted February 2, 2015 this works: sprite.filters = new OutlineFilterMultiPass(game.renderer.width, game.renderer.height, thickness, "0x"+friendFoeColors[key]); this doesnt:sprite.shader = new OutlineFilter(sprite.texture.baseTexture.width, sprite.texture.baseTexture.height,....) Quote Link to comment Share on other sites More sharing options...
timetocode Posted July 21, 2015 Share Posted July 21, 2015 How do I use msha's color replacement shader? I've copied and pasted it out of codepen, but I keep getting the following error.. which is a syntax error for a comma in the fragment shader maybe..?pixi.js:15985 ERROR: 0:1: ',' : syntax error pixi.js:15586 WebGL: INVALID_VALUE: attachShader: no object or object deletedpixi.js:15592 Pixi.js Error: Could not initialize shader.60.Shader.compile @ pixi.js:1559260.Shader.init @ pixi.js:15526Shader @ pixi.js:15514TextureShader @ pixi.js:1605049.AbstractFilter.getShader @ pixi.js:1397767.SpriteRenderer.flush @ pixi.js:1754848.WebGLRenderer.renderDisplayObject @ pixi.js:1365648.WebGLRenderer.render @ pixi.js:13628animate @ main.js:1078pixi.js:15593 gl.VALIDATE_STATUS false60.Shader.compile @ pixi.js:1559360.Shader.init @ pixi.js:15526Shader @ pixi.js:15514TextureShader @ pixi.js:1605049.AbstractFilter.getShader @ pixi.js:1397767.SpriteRenderer.flush @ pixi.js:1754848.WebGLRenderer.renderDisplayObject @ pixi.js:1365648.WebGLRenderer.render @ pixi.js:13628animate @ main.js:1078pixi.js:15594 gl.getError() 128160.Shader.compile @ pixi.js:1559460.Shader.init @ pixi.js:15526Shader @ pixi.js:15514TextureShader @ pixi.js:1605049.AbstractFilter.getShader @ pixi.js:1397767.SpriteRenderer.flush @ pixi.js:1754848.WebGLRenderer.renderDisplayObject @ pixi.js:1365648.WebGLRenderer.render @ pixi.js:13628animate @ main.js:1078pixi.js:15599 Pixi.js Warning: gl.getProgramInfoLog() missing shaders5pixi.js:15542 WebGL: INVALID_VALUE: getUniformLocation: no object or object deleted3pixi.js:15554 WebGL: INVALID_VALUE: getAttribLocation: no object or object deletedpixi.js:17609 WebGL: INVALID_OPERATION: drawElements: no valid shader program in useThe exact shader is:var ColorReplaceFilter = function (findColor, replaceWithColor, range) { PIXI.AbstractFilter.call(this); this.uniforms = { findColor: {type: '3f', value: null}, replaceWithColor: {type: '3f', value: null}, range: {type: '1f', value: null} }; this.findColor = findColor; this.replaceWithColor = replaceWithColor; this.range = range; this.passes = [this]; this.fragmentSrc = [ 'precision mediump float;', 'varying vec2 vTextureCoord;', 'uniform sampler2D texture;', 'uniform vec3 findColor;', 'uniform vec3 replaceWithColor;', 'uniform float range;', 'void main(void) {', ' vec4 currentColor = texture2D(texture, vTextureCoord);', ' vec3 colorDiff = findColor - (currentColor.rgb / max(currentColor.a, 0.0000000001));', ' float colorDistance = length(colorDiff);', ' float doReplace = step(colorDistance, range);', ' gl_FragColor = vec4(mix(currentColor.rgb, (replaceWithColor + colorDiff) * currentColor.a, doReplace), currentColor.a);', '}' ]//.join('\n'); console.log('FRAGMENTSHADER', this.fragmentSrc.join('\n'));};ColorReplaceFilter.prototype = Object.create(PIXI.AbstractFilter.prototype);ColorReplaceFilter.prototype.constructor = ColorReplaceFilter;Object.defineProperty(ColorReplaceFilter.prototype, 'findColor', { set: function (value) { var r = ((value & 0xFF0000) >> 16) / 255, g = ((value & 0x00FF00) >> 8) / 255, b = (value & 0x0000FF) / 255; this.uniforms.findColor.value = {x: r, y: g, z: b}; this.dirty = true; }});Object.defineProperty(ColorReplaceFilter.prototype, 'replaceWithColor', { set: function (value) { var r = ((value & 0xFF0000) >> 16) / 255, g = ((value & 0x00FF00) >> 8) / 255, b = (value & 0x0000FF) / 255; this.uniforms.replaceWithColor.value = {x: r, y: g, z: b}; this.dirty = true; }});Object.defineProperty(ColorReplaceFilter.prototype, 'range', { set: function (value) { this.uniforms.range.value = value; this.dirty = true; }});My usage is:var shader = new ColorReplaceFilter(0xCBCBCB, 0xff7700, 0.1);someSprite.shader = shader;What am i doing wrong? I'm using the latest pixi v3 Quote Link to comment Share on other sites More sharing options...
xerver Posted July 21, 2015 Share Posted July 21, 2015 The shader he wrote was for v2, so that is the biggest problem https://github.com/pixijs/pixi-extra-filters I've updated and collected some cool shaders there, including the outline filter: https://github.com/pixijs/pixi-extra-filters/blob/master/src/filters/outline/OutlineFilter.js Unfortunately I didn't know about the color-replacement shader. What would be helpful is if you opened a github issue on that repo with a link to the codepen and I can update it and add it to the repo. Quote Link to comment Share on other sites More sharing options...
timetocode Posted July 21, 2015 Share Posted July 21, 2015 That would be awesome. Thanks xerver. I've opened a github issue on the extra-filters repo. Quote Link to comment Share on other sites More sharing options...
timetocode Posted July 24, 2015 Share Posted July 24, 2015 I think I've got this working now. I wrote another shader that does the same thing, and then I think I finally understood what needed to change (almost nothing) to get the original working again. I've included both below. Take it with a heap of salt, b/c I do not know GLSL. Also one of the main issues I ran into was simply that in webgl a color component of a number is a float from 0.0 to 1.0 -- my game uses numbers from 0 - 255, so if you do something like what I've done, you must convert your colors appropriately. Per pixel color replacement shader (this one expects a number originating from javascript in the format new Float32Array([255, 255, 255, 255]) would be 0xffffff at 100% opacity).var shader = [ 'precision mediump float;', 'varying vec2 vTextureCoord;', 'uniform sampler2D texture;', 'uniform vec4 findColor;', 'uniform vec4 replaceWithColor;', 'uniform float range;', 'bool closeEnough(vec4 a, vec4 {', ' if (abs(a.r - b.r) < 0.00001 && abs(a.g - b.g) < 0.00001 && abs(a.b - b. < 0.00001) {', ' return true;', ' } else { ', ' return false;', ' }', '}', 'void main(void) {', ' vec4 current = texture2D(texture, vTextureCoord);', ' if (closeEnough(findColor/255.0, current)) { ', ' gl_FragColor = replaceWithColor/255.0;', ' } else {', ' gl_FragColor = current;', ' }', '}']And here's the v2 color replacement shader updated for v3 (this one wants the numbers to be new Float32Array([1.0, 1.0, 1.0]) note this is a 3 component not a 4 component color, so the alpha is not part of the search/replacement for the colors):var ColorReplaceFilter = function (findColor, replaceWithColor, range) { PIXI.AbstractFilter.call(this, // vertex shader null, // fragment shader [ 'precision mediump float;', 'varying vec2 vTextureCoord;', 'uniform sampler2D texture;', 'uniform vec3 findColor;', 'uniform vec3 replaceWithColor;', 'uniform float range;', 'void main(void) {', ' vec4 currentColor = texture2D(texture, vTextureCoord);', ' vec3 colorDiff = findColor - (currentColor.rgb / max(currentColor.a, 0.0000000001));', ' float colorDistance = length(colorDiff);', ' float doReplace = step(colorDistance, range);', ' gl_FragColor = vec4(mix(currentColor.rgb, (replaceWithColor + colorDiff) * currentColor.a, doReplace), currentColor.a);', '}' ].join('\n'), // custom unifroms { findColor: { type: '3f', value: findColor }, replaceWithColor: { type: '3f', value: replaceWithColor }, range: { type: '1f', value: range } } );};ColorReplaceFilter.prototype = Object.create(PIXI.AbstractFilter.prototype);ColorReplaceFilter.prototype.constructor = ColorReplaceFilter;Object.defineProperty(ColorReplaceFilter.prototype, 'findColor', { set: function (value) { var r = ((value & 0xFF0000) >> 16) / 255, g = ((value & 0x00FF00) >> 8) / 255, b = (value & 0x0000FF) / 255; this.uniforms.findColor.value = {x: r, y: g, z: b}; this.dirty = true; }});Object.defineProperty(ColorReplaceFilter.prototype, 'replaceWithColor', { set: function (value) { var r = ((value & 0xFF0000) >> 16) / 255, g = ((value & 0x00FF00) >> 8) / 255, b = (value & 0x0000FF) / 255; this.uniforms.replaceWithColor.value = {x: r, y: g, z: b}; this.dirty = true; }});Object.defineProperty(ColorReplaceFilter.prototype, 'range', { set: function (value) { this.uniforms.range.value = value; this.dirty = true; }});I believe that the above shader should be faster and accomplishes the same thing because it uses the step function instead of if/else to decide if a color qualifies for replacement. Usage with a 0-255 RGB color: var skinHighlight = new ColorReplaceFilter( new Float32Array([220/255.0, 220/255.0, 220/255.0]), new Float32Array([225/255.0, 200/255.0, 215/255.0]), 0.1 ); // replace the color (220, 220, 220) with the color (225, 200, 215) someSprite.filters = [skinHighlight, etc other shaders here]; // or someSprite.shader = skinHightlight Quote Link to comment Share on other sites More sharing options...
xerver Posted July 24, 2015 Share Posted July 24, 2015 You should PR this into the filters repo I mentioned earlier. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
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.