I'm working on a game using PlayN, and there's a bit where I would like to take an image (which is currently in PNG format, with 8-bit alpha already) and I would like to multiply the image by an additional alpha factor, based on a value from my code.
Specifically, I have a picture of a face that currently lives in an ImageLayer, and the effect that I would like would be to have something like this:
void init() {
faceImage = assetManager().getImage("images/face.png");
graphics().rootLayer().add(faceImage);
}
void update(float deltaMilliseconds) {
// start at fully transparent, fade to fully opaque
float transparency = calcTransparency(deltaMilliseconds);
faceImage.setTransparency(transparency);
}
I expect that there's some way to do some trickiness with GroupLayers and blend modes, perhaps blending the image with a CanvasLayer painted with a solid white rectangle with transparency controlled by my code, but it's not obvious to me if that's the best way to achieve what seems like a pretty common effect.
If you just want to fade the image in from fully-transparent to fully-opaque, then just do the following:
ImageLayer faceLayer;
void init() {
Image faceImage = assetManager().getImage("images/face.png");
faceLayer = graphics().createImageLayer(faceImage);
graphics().rootLayer().add(faceLayer);
}
void update(float delta) {
float alpha = calcAlpha(delta);
faceLayer.setAlpha(alpha);
}
Where alpha ranges from 0 (fully transparent) to 1 (fully opaque).
Related
So I thought I could do a smart manipulation of the color of a random shaped PNG image, by actually having 4 images of the same shape, but in Red, Green, Blue and Black, then set then on top of each other and manipulate their opacities.
I tried using the formula channelOpacity = channelVal / 255 / 3;
Well, it's not really that easy, it turns out. Has anyone attempted similar things and what would be a solution? Thank you.
It's an interesting idea. However, opacity alone doesn't seem to accomplish your objective, because the order in which the PNGs are defined will affect the color of their combination.
For example, if you have a red PNG, a green PNG, then a blue PNG, all with opacity 0.33, you'll get something like this:
If you rearrange their order as green, red, then blue, you'll get this:
Green, blue, then red will give you this:
There may be a way to take the order into account in your calculations, which could make your idea really useful.
Here's a snippet that sets the opacity of stacked red, green, and blue circles, based on the normalized rgb hex values from a color picker. It does a decent job for colors that are primarily red, green, or blue, but it suffers from the issue I've described:
var colorPicker= document.getElementById('colorPicker');
colorPicker.oninput= function() {
var red = document.getElementById('red');
var green= document.getElementById('green');
var blue = document.getElementById('blue');
var r= parseInt(this.value.substr(1,2),16);
var g= parseInt(this.value.substr(3,2),16);
var b= parseInt(this.value.substr(5,2),16);
var factor = 1/(r+g+b);
red.style.opacity = r * factor;
green.style.opacity= g * factor;
blue.style.opacity = b * factor;
}
colorPicker.oninput();
img {
position: absolute;
}
Choose color: <input id="colorPicker" type="color" value="#ff0000">
<hr>
<img id="red" src="http://upload.wikimedia.org/wikipedia/commons/thumb/e/e2/Bullet-red.png/240px-Bullet-red.png">
<img id="green" src="http://upload.wikimedia.org/wikipedia/commons/thumb/6/68/Bullet-green.png/240px-Bullet-green.png">
<img id="blue" src="http://upload.wikimedia.org/wikipedia/commons/thumb/f/f7/Bullet-blue.png/240px-Bullet-blue.png">
I found a way to do it through canvas, here: permadi.com
Given that Firefox has also added support (v34) for the methods involved, this solution should work fine. Careful, there are a lot of mistakes in the code at the above link (I corrected them below), but the idea is awesome. Here's what it's about, roughly:
// image is an html image element
var myCanvas=document.createElement("canvas");
var myCanvasContext=myCanvas.getContext("2d");
var imgWidth=image.width;
var imgHeight=image.height;
// You'll get some string error if you fail to specify the dimensions
myCanvas.width= imgWidth;
myCanvas.height=imgHeight;
// alert(imgWidth);
myCanvasContext.drawImage(image,0,0);
// This function cannot be called if the image is not rom the same domain.
// You'll get security error if you do.
var imageData=myCanvasContext.getImageData(0,0, imgWidth, imgHeight);
// This loop gets every pixels on the image and
for (i=0; i<imageData.height; i++)
{
for (j=0; j<imageData.width; j++)
{
var index;
index=(i*4)*imageData.width+(j*4);
// then access your data and set it like this:
// imageData.data[index+0]; // red
// imageData.data[index+0]; // green
// imageData.data[index+0]; // ... till alpha
}
}
myCanvasContext.putImageData(imageData,0,0,0,0, imageData.width, imageData.height);
return myCanvas.toDataURL();
I have a QImage in a QGraphicsView which I need to show images continously. Some times I need to show the inverted images continuously. For this I use
img.invertPixels(QImage::InvertRgba);
But at this time, the display is flickering due to the continuous inverting process. How can I implement the inverting process without affecting the performance? The display seems to be smooth without invert. `
QImage img(byImageBuf, width, height, QImage::Format_Indexed8);
scene->clear();
if(bInvertPixel)
{
/* Inverted image */
img.invertPixels(QImage::InvertRgba);
}
scene->addPixmap(QPixmap::fromImage(img));
view->fitInView(0, 0, width, height, Qt::IgnoreAspectRatio);
view->update();`
Since you are using an indexed image type (QImage::Format_Indexed8) you can invert the color table and just toggle that:
if(bInvertPixel)
{
/* Inverted image */
img.setColorTable( invertedColorTable );
}
else
{
img.setColorTable( standardColorTable );
}
standardColorTable and invertedColorTable are arrays of QRgb values.
The beauty of the color table is that you do not have to update it every time you display your image; just set it once and forget about it. Connect a signal from a button for inverting the colors and set the color table there.
I've create simple example: background surface layer and 10 small "dots" on it (10 surface layers 10x10 px each filled with color via fillRect()). Paint method simply moves the dots around periodically:
private SurfaceLayer background;
private List<Layer> dots = new ArrayList<Layer>();
#Override
public void init()
{
background = graphics().createSurfaceLayer(graphics().width(), graphics().height());
background.surface().setFillColor(Color.rgb(100, 100, 100));
background.surface().fillRect(0, 0, graphics().width(), graphics().height());
graphics().rootLayer().add(background);
for (int i = 0; i < 10; i++)
{
SurfaceLayer dot = graphics().createSurfaceLayer(10, 10);
dot.surface().clear();
dot.surface().setFillColor(Color.rgb(250, 250, 250));
dot.surface().fillRect(0, 0, 10, 10);
dot.setDepth(1);
dot.setTranslation(random()*graphics().width(), random()*graphics().height());
dots.add(dot);
graphics().rootLayer().add(dot);
}
}
#Override
public void paint(float alpha)
{
for (Layer dot : dots)
{
if (random() > 0.999)
{
dot.setTranslation(random()*graphics().width(), random()*graphics().height());
}
}
}
Somehow java version draws all dots while html and android version draw only 1.
Manual doesn't clearly say if i should re-draw all these dots in every paint() call. And as far as i understood SurfaceLayer is meant for cases when you do not modify layer on every frame (so same buffer can be reused?), but this doesn't work.
So can you guys help me with correct SurfaceLayer usage? If i just filled a rectangular on SurfaceLayer - would it ramin on this layer forever or should i fill it in each paint call? If yes - is this different from ImmeadiateLayer?
You don't need to redraw a surface layer on every call to paint. As you have shown, you draw it only when preparing it, and the texture into which you've draw will be rendered every frame without further action on your part.
If the Android and HTML backend are not drawing all of your surface layers, there must be a bug. I'll try to reproduce your test and see if it works for me.
One note: creating a giant surface the size of the screen and drawing a solid color into it is a huge waste of texture memory. Just create an ImmediateLayer that calls fillRect() on every frame, which is far more efficient than creating a massive screen-covering texture.
Has anyone used the photo filter in Photoshop? Edit > Adjustments > Photo Filter...
It produces a really nice image tint that I've been unable to reproduce with blending modes. Has anyone got any idea of the pixel maths behind this filter? - So I can build a shader based on it.
It seems to basically be a luminosity preserving colour tint.
Has variables: Color, Amount and Preserve Luminosity.
Any ideas?
Filters (in light) are multiplicative, as in:
red_filter = ( 1 , 0 , 0 ) * color
I don't think any blend-modes exist for it, since any transparent overlay with that system would darken the image to some degree.
It's incredibly simple, but if anyone wants the hlsl code for this:
// Photoshop PhotoFilter style effect.
// Input filter color.
float4 FilterColor;
// Implicit texture sampler.
sampler TextureSampler : register(s0);
float4 PhotoFilter(float4 color : COLOR0, float2 texCoord : TEXCOORD0) : COLOR0
{
return tex2D(TextureSampler, texCoord) * FilterColor;
}
technique GeneralEffect
{
pass Pass1
{
PixelShader = compile ps_2_0 PhotoFilter();
}
}
I am trying to rotate a Sprite in three dimensions around its centerpoint, and I am struggling to understand some of the behavior of matrix3D.
Ive overridden the set rotationX, rotationY, and rotationZ methods of the Sprite as follows:
override public function set rotationX (_rotationX:Number) : void {
this.transform.matrix3D.prependTranslation(this.width/2.0, this.height/2.0, 0);
this.transform.matrix3D.prependRotation(-this.rotationX, Vector3D.X_AXIS);
this.transform.matrix3D.prependRotation(_rotationX, Vector3D.X_AXIS);
this.transform.matrix3D.prependTranslation(-(this.width/2.0), -(this.height/2.0), 0);
}
override public function set rotationY (_rotationY:Number) : void {
this.transform.matrix3D.prependTranslation(this.width/2.0, this.height/2.0, 0);
this.transform.matrix3D.prependRotation(-this.rotationY, Vector3D.Y_AXIS);
this.transform.matrix3D.prependRotation(_rotationY, Vector3D.Y_AXIS);
this.transform.matrix3D.prependTranslation(-(this.width/2.0), -(this.height/2.0), 0);
}
override public function set rotationZ (_rotationZ:Number) : void {
this.transform.matrix3D.prependTranslation(this.width/2.0, this.height/2.0, 0);
this.transform.matrix3D.prependRotation(-this.rotationZ, Vector3D.Z_AXIS);
this.transform.matrix3D.prependRotation(_rotationZ, Vector3D.Z_AXIS);
this.transform.matrix3D.prependTranslation(-(this.width/2.0), -(this.height/2.0), 0);
}
I am using prependTranslation to correct the centerpoint of the rotation, and the first prependRotation to cancel out any previously-applied rotation.
Testing it out, rotationX works exactly as expected, and the Sprite rotates around its horizontal axis.
rotationY and rotationZ also appear to work fine. However, there is one problem: whenever rotationY or rotationZ are set, all of the other rotation values change as well. This is not a problem with rotationX -- if I set rotationX, nothing else changes. But if I set rotationY or rotationZ all the rotation values change, which is a problem for my app (which is trying to save and restore values).
I think I am just lacking some understanding about what is going on with matrix3D. How can I implement this so there is no interdependence between the values?
Another easy solution is to add the object and center it within a container sprite and do the 3D transformations on the containing sprite.
I know nothing about AS3 etc. But just looking at your code, I wonder why you translate on the z-axis using what I understand to be x and y values (width and height). Shouldn't the z-axis be translated using something like "depth"?
This is very simple, you can try use the following code:
var matrix3d:Matrix3D = s.transform.matrix3D;
matrix3d.appendRotation( -1, Vector3D.Z_AXIS , new Vector3D( 390, 360, 0 ) );
while s is your sprite, the third parameter, Vector3D indicate your sprite's center position.
The Above code will make the sprite s rotate more -1 degree.