Howto convert a Shadertoy shader to a pixijs v6 shader/filter - pixi.js

i need help to convert a shadertoy filter (https://www.shadertoy.com/view/7tsfWS) to newest pixijs version filter.
Somehow my canvas stays black and i dont know what i do wrong.
I prepared sth on pixiplayground: https://www.pixiplayground.com/#/edit/av3kcgJuH2ISiPpSmz4uI
Thx already in advance for the help 🙂

The issue is in how you are passing the uniform values to the shader. It's fixed by removing the wrapping object:
var width = window.innerWidth;
var height = window.innerHeight;
const uniforms = {
iResolution: [width, height],
iTime: 0
};
As you can see in the examples, in PIXI version 5 and above you don't need to declare the uniforms in objects with type and value. This can also be found in the migration guide.

Related

How to apply transform to graphics in OpenFL

I'm converting a JavaScript library to Haxe. In this library, there is an animated effect constructed with many of shapes. So I used the OpenFL library to render shapes.
But now I have a technical problem with transformation.
Some of the shapes has the child shapes so it's transform should be applied to the child shapes too.
For example, please imagine shapeC is attached on shapeB and, shapeB and shapeD are also attached on shapeA. In this case, shapeB, shapeD should be transformed by both of transformA and their own transform and, shapeC also should by transformA, transformB and transformC.
To achieve this, is it a good solution to render the same level shapes in one graphic and apply the parent's transform to that graphic? (on above example, render shapeB and shapeD to one graphic and a apply transformA to that graphic)
I think it's not a good optimized solution to calculate the final transform from all parents transforms and apply that to all vertexes of that shape. Please tech me the best optimized solution for rendering.
Any suggestion will be welcome.
And if there is any confused things on this question, please pardon me and let me check.
You can use the Sprite class:
var parentShape = new Sprite ();
parentShape.graphics.beginFill (0xFF0000);
parentShape.graphics.drawRect (0, 0, 100, 100);
var childShape = new Sprite ();
childShape.graphics.beginFill (0x00FF00);
childShape.graphics.drawCircle (0, 0, 50);
childShape.x = 200;
childShape.y = 200;
parentShape.addChild (childShape);
addChild (parentShape);
Each shape will use its own canvas element, so if you create a lot of shapes, you may decide to flatten it into a single image when you are ready. This is possible using cacheAsBitmap or bitmapData.draw
parentShape.cacheAsBitmap = true;
...or
removeChild (parentShape);
var bitmapData = new BitmapData (Math.ceil (parentShape.width), Math.ceil (parentShape.height), true, 0);
bitmapData.draw (parentShape);
var bitmap = new Bitmap (bitmapData);
addChild (bitmap);

Why isn't this mask working in Phaser?

I must be missing something...why isn't this working? Instead of clipping to the circle the entire 800x800 backdrop image is displayed...
var mask;
var img;
function preload() {
game.load.image('back', 'backdrop.jpg');
}
function create() {
img = game.add.image(game.world.centerX, game.world.centerY,'back').anchor.setTo(0.5);
mask = game.add.graphics(0, 0);
mask.beginFill(0xffffff);
mask.drawCircle(game.world.centerX, game.world.centerY, 600);
img.mask = mask;
}
jsfiddle here
Disclaimer: I have no formal experience in phaser.io
I was able to fix this in your fiddle by changing
img = game.add.image(game.world.centerX, game.world.centerY,'back').anchor.setTo(0.5);
to
img = game.add.image(0, 0, 'back');
JSFiddle Fork
I would assume that placing the image in the centerX,centerY position results in the mask being offset of the image. Hopefully someone with more experience than I could explain the specifics here, but I will research further and update my answer as I figure out the why to go along with the how.
Update
Okay so I've done some digging through the documentation. First, you want to use img = game.add.image(0, 0, 'back'); due to the fact that the x and y parameters in this case dictate the upper-left origin of the image, not the center. By using game.world.centerX and game.world.centerY you are trying to throw the background image to the center of the canvas even though the canvas is the same size as the image.
using .anchor.setTo(0.5) from what I can gather, is attempting to set the anchor point at which the image originates to the centerX position. However, when you remove this anchor, suddenly the mask works, even though it is not showing correctly (because the position of the background image is incorrect).
Theory - By anchoring the image, I believe that it is no longer possible to apply a mask to it. By all experimenting that I've done, having an anchor set on the background image prevents it from being masked, so the mask simply is added as a child to img and is placed as it's center, thus why you are seeing the white circle instead of the circle properly masking the image.
it appears I was a mistaken about the fluidity of the api in trying to chain that last function call... if I break it up:
img = game.add.image(game.world.centerX, game.world.centerY, 'back');
img.anchor.setTo(0.5);
it now works!
Fiddle Here

d3.js geo - rendering svg path

I'd like to create choropleth map of Czech Republic. Inspired by this article http://bl.ocks.org/mbostock/4060606, I have created this
http://jsfiddle.net/1duds8tz/2/
var width = 960;
var height = 500;
var svg = d3.select("body").append("svg").attr("width", width).attr("height", height);
var offset = [width / 2, height / 2];
var projection = d3.geo.mercator().scale(6000).center([15.474, 49.822]).translate(offset);
var path = d3.geo.path().projection(projection);
queue().defer(d3.json, "..map.geojson").await(ready);
function ready(error, reg) {
var group = svg.selectAll("g").data(reg.features).enter().append("g");
group.append("path").attr("d", path).attr("fill", "none").attr("stroke", "#222");
}
When I tried to fill svg path with some color, I ended on this
http://jsfiddle.net/1duds8tz/3/
group.append("path").attr("d", path).attr("fill", "red").attr("stroke", "#222");
There are odd values in path d attribute.
My GeoJSON data must be somehow faulty but I can't figure what is wrong.
Everything looks right here: https://gist.github.com/anonymous/4e51227dd83be8c2311d
Your geoJSON is corrupted and as a result your polygons are being drawn as the interiors of an infinitely bounded polygon. That's why when you attempt to give a fill to the path, it goes beyond the extent of the screen but still displays the border just fine. I tried to reverse the winding order of your coordinates array, and that seemed to fix all of them except for "Brno-venkov", which might be the source of your problems (especially given its administrative shape).
I'd suggest going back to where you created the original GeoJSON and try to re-export it with simplification. If you want to reverse the coordinates on your GeoJSON to correct the winding order, that's pretty simple:
geodata = d3.selectAll("path").data();
for (x in geodata) {geodata[x].geometry.coordinates[0] = geodata[x].geometry.coordinates[0].reverse()}
But this won't fix the problem polygon, nor will not reversing its coordinates.
In case you are familiar with svg manipulation you can try geojson2svg. This allows you manipulate svg in standard way but you have to code a little more. In case your application requires d3 for many other purpose then d3 is best solution.
I've got exactly the same problem with Mapzen's .geojson files.
.reverse()-ing isn't good enough, if you can't make sure all your data has the same winding order.
I solved it with this one:
https://www.npmjs.com/package/geojson-rewind
You'll need to have npm & require available
Install it, and save it to your project
npm i -g geojson-rewind
Import it, to make it useable
var rewind = require('geojson-rewind');
Use it on the data, in this case:
req = rewind(req);
Tip: If you are working with static data, you can do this only once on the console, and you're good to go.

SKIA - Inaccurate value returned by measureText()

I have a problem measuring text using skia measureText() function.
The value returned is inaccurate.
SkPaint *skPaint = new SkPaint();
SkTypeface* myFont = SkTypeface::CreateFromName("Impact", SkTypeface::kNormal);
skPaint->setTypeface(myFont);
skPaint->setAntiAlias(true);
skPaint->setTextAlign(SkPaint::kLeft_Align);
skPaint->setTextEncoding(SkPaint::kUTF16_TextEncoding);
skPaint->setTextSize(SkIntToScalar(120));
skPaint->setColor(0xff000001);
canvas->drawText(text, length, SkIntToScalar(x) , SkIntToScalar(y) , *skPaint);
SkScalar width = skPaint->measureText(text, length);
The width returned by measureText() is 451.
I checked the generated bitmap text via a photo editor app, the actual width is only 438.
Any thoughts on getting the accurate width of text in SKIA?
Thank you!
I believe what you are trying to match will come from "bounds"
SkRect bounds;
SkScalar textWidth = paint.measureText("some", 4, &bounds);
which is a minimum rectangle to fit a given text, whereas textWidth is slightly larger than that.
I faced this issue too. Dont know why exactly it happens, maybe because of kerning differences, but i came to this:
SizeF RenderTextAndroid::GetStringSizeF() {
UpdateFont();
const base::string16& text = GetLayoutText();
std::vector<SkScalar> widths(text.length());
paint_.getTextWidths(text.c_str(), GetStrByteLen(text), &widths[0], NULL);
return SizeF(std::accumulate(widths.begin(), widths.end(), 0),
font_metrics_.fBottom - font_metrics_.fTop);
}
Where UpdateFont just sets new parameters to SkPaint

How to create a `pixelized' SVG image from a bitmap?

I have a 16x16 bitmap and want to create an SVG that contains 16x16 squares with the colors of the pixels of the image. Is there an easy way to achieve this?
My current thoughts go into the direction of using Python and PIL to read the bitmap image and dynamically create an SVG image file with the corresponding objects. But this feels a little clumsy and like reinventing the wheel.
Is there a better way to do this?
If you don't need the output to be SVG, I would suggest using an HTML5 Canvas where you can sample the pixels of the image client-side (using getImageData() on the context) and then draw your own up-scaled image. Or, if you need SVG, you could still use Canvas for the image sampling and then use procedurally-created <rect/> elements in SVG for each pixel.
I've written an example using just HTML Canvas so you can see how to do this. In short:
function drawPixelated(img,context,zoom,x,y){
if (!zoom) zoom=4; if (!x) x=0; if (!y) y=0;
if (!img.id) img.id = "__img"+(drawPixelated.lastImageId++);
var idata = drawPixelated.idataById[img.id];
if (!idata){
var ctx = document.createElement('canvas').getContext('2d');
ctx.width = img.width;
ctx.height = img.height;
ctx.drawImage(img,0,0);
idata = drawPixelated.idataById[img.id] = ctx.getImageData(0,0,img.width,img.height).data;
}
for (var x2=0;x2<img.width;++x2){
for (var y2=0;y2<img.height;++y2){
var i=(y2*img.width+x2)*4;
var r=idata[i ];
var g=idata[i+1];
var b=idata[i+2];
var a=idata[i+3];
context.fillStyle = "rgba("+r+","+g+","+b+","+(a/255)+")";
context.fillRect(x+x2*zoom, y+y2*zoom, zoom, zoom);
}
}
};
drawPixelated.idataById={};
drawPixelated.lastImageId=0;
If you really need SVG involved, I'd be happy to write an example that dynamically generated that.
Edit: OK, I've created an SVG version just for fun and practice. :)
As an aside (from an initial misreading of your question) this demo file from ASVG3 their old SVG Examples Page shows how to use some complex compositing of many different effects to create pixelation on arbitrary vector data. Unfortunately the demo does not load in Chrome, having been hardwired to require the (now-discontinued) Adobe SVG Viewer.

Resources