I've been looking for the solution for some time and haven't yet found it. One of the functions of my app is to load an image and then to change its shape - e.g. I load a normal rectangular image, and then there are 2-3 buttons - change the image to a circle, triangular or some other shape. Is sth like that even possible with Bitmaps? I found a lot of interesting things about Nokia imaging SDK, but all the shape stuff i found was LensBlurEffect, which isn't exactly what i need.
If someone could point me in the right direction, I would be really grateful!
Thank You in advance for help!
Best regards,
Roman
I'm working on filters that draws shapes using Nokia Imaging SDK. To solve your problem, I created sample project that uses Nokia Imaging SDK's blend filter and my custom shape filters.
Actually you can do the same thing with shape image as David refers (background is black, foreground white) instead of using my custom filters (EllipseShapeFilter above example code).
Here is sample code;
var ellipseImage = new WriteableBitmap(1024, 768);
Rect origin = new Rect(new Point(512, 384), new Size(512, 384));
uint white = 0xff000000 | (255 << 16) | (255 << 8) | 255;
var image = LoadFromResources(new Uri(#"/BlendImageSample;component/Assets/Sample.jpg", UriKind.Relative));
using (var ellipseSource = new BitmapImageSource(ellipseImage.AsBitmap()))
using (var ellipse = new EllipseShapeFilter(ellipseSource, white, origin))
{
ellipseImage = await new WriteableBitmapRenderer(ellipse, ellipseImage).RenderAsync();
}
ImageViewer.Source = ellipseImage;
using (var backgroundSource = new BitmapImageSource(ellipseImage.AsBitmap()))
using (var foregroundSource = new BitmapImageSource(image.AsBitmap()))
using (var filterEffect = new FilterEffect(backgroundSource))
{
using (BlendFilter blendFilter = new BlendFilter())
{
blendFilter.ForegroundSource = foregroundSource;
blendFilter.BlendFunction = BlendFunction.Darken;
filterEffect.Filters = new[] { blendFilter };
var OutputBitmap = new WriteableBitmap(image.PixelWidth, image.PixelHeight);
var result = await new WriteableBitmapRenderer(filterEffect, OutputBitmap).RenderAsync();
ImageViewer.Source = result;
}
}
Github - BlendImageSample
Well the bitmap is always going to be rectangular, there is nothing you can do about that.
What you can do is make some pixels transparent, thus making the bitmap appear of a different shape.
One way to do this using the Nokia Imaging SDK is to use the BlendFilter to blend a transparent image (I suggest just a ColorImageSource) over the original image. You can provide different masks to create different "shapes."
Related
I am having banding issues with gradient related textures in my game and I can't seem to find what's the cause and how to solve it.
Here's what I am talking about: On the left is a gradient in my game, whereas on the right is a gradient generated in a gradient generator application(Tint). We can clearly see banding issues.
To create my gradient, I used this code to generate a Texture used to create an Image that I scale to fill the user's screen.
Pixmap pix = new Pixmap(2, 2, Pixmap.Format.RGBA8888);
pix.setColor(colorSchemes[backgroundColorScheme.ordinal()].getTopColor());
pix.fillRectangle(0,0,2,1);
pix.setColor(colorSchemes[backgroundColorScheme.ordinal()].getBottomColor());
pix.fillRectangle(0,1,2,1);
Texture texture = new Texture(pix);
texture.setFilter(Texture.TextureFilter.Linear,
Texture.TextureFilter.Linear);
pix.dispose();
I also have another issue with banding when I try to add fog-like actors on top of the background to animate it a bit. I scale them, change their opacity and move them around and again I get banding issues as highlighted in the picture below.
I am trying to replicate a background effect like in this game
https://www.youtube.com/watch?v=_vBczzj3NAU
I have this code in my render screen render loop:
#Override
public void render (float delta) {
Gdx.gl.glClearColor(0,0,0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
Gdx.gl.glEnable(GL20.GL_BLEND);
Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
}
Any ideas on how I can solve those issues? Any help would be greatly appreciated.
Increasing the number of bits per color channel (I believe the default is 5 bits) to 8 bits fixed the banding problem for me.
In AndroidLauncher.java
AndroidApplicationConfiguration config = new AndroidApplicationConfiguration();
config.r = config.g = config.b = config.a = 8;
In DesktopLauncher.java
LwjglApplicationConfiguration config = new LwjglApplicationConfiguration();
config.r = config.g = config.b = config.a = 8;
In the following example, there is a function called generateTexture().
Is it possible to draw text (numbers) into the pixel array? Or is it possible to draw text (numbers) on top of that shader?
Our goal is to draw a circle with a number inside of it.
https://forge.autodesk.com/blog/using-dynamic-texture-inside-custom-shaders
UPDATE:
We noticed that each circle can't use a unique generateTexture(). The generateTexture() result is used by every single one of them. The only thing that can be customized per object is the color, plus what texture is used.
We could create a workaround for this, which is to generate every texture from 0 to 99, and to then have each object choose the correct texture based on the number we want to display. We don't know if this will be efficient enough to work properly though. Otherwise, it might have to be 0 to 9+ or something in that direction. Any guides on our updated question would be really appreciated. Thanks.
I am able to successfully display text with the following code, simply replace generateTexture() by generateCanvasTexture() in the sample and you should get the result below:
const generateCanvasTexture = () => {
const canvas = document.createElement("canvas")
const ctx = canvas.getContext('2d')
ctx.font = '20pt Arial'
ctx.textAlign = 'center'
ctx.textBaseline = 'middle'
ctx.fillText(new Date().toLocaleString(),
canvas.width / 2, canvas.height / 2)
const canvasTexture = new THREE.Texture(canvas)
canvasTexture.needsUpdate = true
canvasTexture.flipX = false
canvasTexture.flipY = false
return canvasTexture
}
It is possible but you would need to implement it yourself. Shaders are a pretty low level feature so there is no way to directly draw a number or a text, but you can convert a given character into its representation as a 2d pixel array.
I am drawing a PNG image to an HTML canvas and I have implemented a filter system to allow convolute filters to be executed against the image data before it is blitted to the canvas.
Does anyone have an idea how to create a glow effect using either a convolute kernel / matrix (I'm not sure what the terminology is but I'm talking about these: http://www.html5rocks.com/en/tutorials/canvas/imagefilters/) or by other means such as using the globalCompositeOperation (https://developer.mozilla.org/samples/canvas-tutorial/6_1_canvas_composite.html)?
I am aware that you can start with a low opacity and a scaled image then increase opacity while scaling the image down a bit. This works to create a sort-of glow effect but only around the edge of an image.
In an ideal world it would be great to be able to designate areas of the image that have glow using a secondary glow texture. Any ideas on either scenario? :)
Hope the following is along the lines of what you were looking to do, I think it turned out pretty well. So I used the filter library code from the article, and just created a new glow filter for the library, since his code was done pretty well to begin with. Here is a Live Demo showing the glow effect in action.
This is the filter code that you need to add to the library
Filters.glow = function(pixels, passes, image, glowPasses){
for(var i=0; i < passes; i++){
pixels = Filters.convolute(pixels,
[1/9, 1/9, 1/9,
1/9, 1/9, 1/9,
1/9, 1/9, 1/9 ]);
}
var tempCanvas = document.createElement("canvas"),
glowCanvas = document.createElement("canvas"),
tCtx = tempCanvas.getContext("2d"),
gCtx = glowCanvas.getContext("2d");
tempCanvas.width = glowCanvas.width = pixels.width;
tempCanvas.height = tempCanvas.height = pixels.height;
tCtx.putImageData(pixels, 0, 0);
gCtx.drawImage(image, 0, 0);
gCtx.globalCompositeOperation = "lighter";
for(i = 0; i < glowPasses; i++){
gCtx.drawImage(tempCanvas,0,0);
}
return Filters.getPixels(glowCanvas);
}
And this is how you would use the above filter.
var glowImage = document.images[1],
glowMask = document.images[0],
c = document.getElementById("canvas"),
ctx = c.getContext("2d");
window.onload = function() {
var pData = Filters.filterImage(Filters.glow, glowImage, 5, glowMask, 2);
c.width = pData.width;
c.height = pData.height;
ctx.putImageData(pData, 0, 0);
}
You need to provide it with 2 images. The first is the image you want the glow to appear on, and the second is the actual glow mask that is applied to the image. You can then specify how many blur passes to perform, which makes the glow more prominent, and how many glow passes to perform, which add the glow to the image. I use the lighter global composition for the canvas which alpha blends it.
This article is a pretty great resource on creating a glow effect, its also where I got the graphics in order to test my results against theirs.
I am fooling aroung with Papervision3D in as3. I am currently stuck with a BitmapEffectLayer. WHen I want to add an effect to an object, the object with the effects will always be rendered infront of everything. That means, even though its behind another object in the cordinat system, it gets drawn infront of it.
Heres some source code, dunno if it helps.
spherer = new Sphere(shadedMaterial, 120, 20, 14);
//spherer.x = 0;
//spherer.y = 0;
//spherer.z = 0;
displayEarth = new DisplayObject3D();
displayEarth.x =0;
displayEarth.y = 0;
displayEarth.z = 0;
displayEarth.addChild(spherer);
smallSphere = new Sphere(flatMaterial, 10, 10, 10);
smallSphere.x = 0;
smallSphere.z = 130;
smallSphere.y = 00;
displayEarth.addChild(smallSphere);
//scene.addChild(smallSphere);
scene.addChild(light);
var partMaterial:ParticleMaterial = new ParticleMaterial(0x000000, 1.0, ParticleMaterial.SHAPE_CIRCLE);
var part:Particle = new Particle(partMaterial, 3, 0, -150, 30);
var part2:Particle = new Particle(partMaterial, 3, 0,0,135);
var partsHolder:Particles = new Particles();
partsHolder.addParticle(part);
parrr.push(part);
partsHolder.addParticle(part2);
parrr.push(part2);
var effectLayer:BitmapEffectLayer = new BitmapEffectLayer(viewport, stage.stageWidth, stage.stageHeight, true, 0x000000, BitmapClearMode.CLEAR_PRE);
effectLayer.drawLayer.blendMode = BlendMode.OVERLAY;
effectLayer.addDisplayObject3D(smallSphere);
viewport.containerSprite.addLayer(effectLayer);
displayEarth.addChild(partsHolder);
scene.addChild(displayEarth);
effectLayer.addEffect(new BitmapLayerEffect(new BlurFilter(2,2,2)));
And now, the "smallSphere" which is attached to the effectLayer, will always be rendered infront of the "sphere".
Any help is appreciated!
- David
When you set a DisplayObject3D to it's own layer (.useOwnContainer = true; being the simplest option, essentially you get that 3D object rendered into a separate 2D sprite on the 2D typical display list. Using ViewportLayer makes it easier to control this stacking/ordering, so be sure to read through Andy Zupko's detailed post on ViewportLayers. The idea is that if you add 3D objects to 2D render layers, you'll have to deal with sorting. You can for example check the z position of 3D objects and based on that sort the layers if the objects move a lot in 3D. You obviously loose speed when doing this type of operations, so it's best to plan things a bit (e.g. what moves in the scene, what doesn't, what are pros and cons of adding an effect, etc.)
Also it's probably a good idea to bear in mind that the Papervision3D project has not being updated in some time now. It currently only supplies software rendering (with Flash Player 9 and I think partially with Flash Player 10's new drawing API, but probably not in the stable branch). You might want to have a look at Away3D as it's still currently being developed. You can use the Flash Player 10 software rendering API or even the light weight Away3DLite version (which is faster than Papervision3D I think) but there's also the Away3D 4.0 version which uses hardware acceleration.
I'm learning ActionScript/Flash. I love to play with text, and have done a lot of that kind of thing with the superb Java2D API.
One of the things I like to know is "where, exactly, are you drawing that glyph?" The TextField class provides the methods getBounds and getCharBoundaries, but these methods return rectangles that extend far beyond the actual bounds of the whole text object or the individual character, respectively.
var b:Sprite = new Sprite();
b.graphics.lineStyle(1,0xFF0000);
var r:Rectangle = text.getCharBoundaries(4);
r.offset(text.x, text.y);
b.graphics.drawRect(r.x,r.y,r.width,r.height);
addChild(b);
b = new Sprite();
b.graphics.lineStyle(1,0x00FF00);
r = text.getBounds(this);
b.graphics.drawRect(r.x,r.y,r.width,r.height);
addChild(b);
Is there any way to get more precise information about the actual visual bounds of text glyphs in ActionScript?
Richard is on the right track, but BitmapData.getColorBounds() is much faster and accurate... I've used it a couple of times, and optimized for your specific needs its not as slow as one might think.
Cory's suggestion of using flash.text.engine is probably the "correct" way to go, but I warn you that flash.text.engine is VERY (very!) hard to use compared to TextField.
Not reasonably possible in Flash 9 -- Richard's answer is a clever work-around, though probably completely unsuitable for production code (as he mentions) :)
If you have access to Flash 10, check out the new text engine classes, particularly TextLine.
I'm afraid all the methods that are available on TextField are supposed to do what you have already found them to do. Unless performance is key in your application (i.e. unless you intend to do this very often) maybe one option would be to draw the text field to a BitmapData, and find the topmost, leftmost, et c colored pixels within the bounding box retrieved by getCharBoundaries()?
var i : int;
var rect : Rectangle;
var top_left : Point;
var btm_right : Point;
var bmp : BitmapData = new BitmapData(tf.width, tf.height, false, 0xffffff);
bmp.draw(tf);
rect = tf.getCharBoundaries(4);
top_left = new Point(Infinity, Infinity);
btm_right = new Point(-Infinity, -Infinity);
for (i=rect.x; i<rect.right; i++) {
var j : int;
for (j=rect.y; j<rect.bottom; j++) {
var px : uint = bmp.getPixel(i, j);
// Check if pixel is black, i.e. belongs to glyph, and if so, whether it
// extends the previous bounds
if (px == 0) {
top_left.x = Math.min(top_left.x, i);
top_left.y = Math.min(top_left.y, j);
btm_right.x = Math.max(btm_right.x, i);
btm_right.y = Math.max(btm_right.y, j);
}
}
}
var actualRect : Rectangle = new Rectangle(top_left.x, top_left.y);
actualRect.width = btm_right.x - top_left.x;
actualRect.height = btm_right.y - top_left.y;
This code should loop through all the pixels that were deemed part of the glyph rectangle by getCharBoundaries(). If a pixel is not black, it gets discarded. If black, the code checks whether the pixels extends further up, down, right or left than any pixel that has previuosly been checked in the loop.
Obviously, this is not optimal code, with nested loops and unnecessary point objects. Hopefully though, the code is readable enough, and you are able to make out the parts that can most easily be optimized.
You might also want to introduce some threshold value instead of ignoring any pixel that is not pitch black.