How to avoid fade-out on scaled CCSprite without cancelling anti-aliasing? - graphics

I have 3 sprites. Left edge, right edge, and repeating center which has 1 pixel width but is scaled up. The problem is that the scaled sprite fades out the farther away it is from the center:
I've tried using CCTexture's setAliasTexParameters but the result doesn't look good:
How do I get the antialiased looks in the first picture but without the fade out problem?

You could try this on the sprite:
// These parameters set the texture properties:
// minifying filter - linear interpolation,
// magnification filter - linear interpolation,
// texture repeat in S direction,
// texture repeat in T direction (*)
ccTexParams params = {GL_LINEAR, GL_LINEAR, GL_REPEAT, GL_REPEAT};
[sprite.texture setTexParams:&params];
// This explicitly sets the contentSize of the sprite to (10, 200),
// but also sets the "window to the texture" to this rectangle:
[sprite setTextureRect:CGRectMake(0, 0, 10, 200)];
You have to tweak these settings, but hope you get it.
You don't have to scale the sprite.
(*) For S and T check this: Difference between U V and S T texture coordinates

Related

How to change the saturation and overlay of a sprite in Godot

I have been planning to change my sprite to a bit darker color through changing saturation and hue values. But it seems very tricky to do so as the Godot modules only talk about changing the color of a sprite though the modulate option like this:
node.modulate= Color(0, 50, 2,0.5)
Doing so is changing the entire sprite to a new color whereas I just want to make the existing colors to a bit darker color the way we do in Photoshop using "Curves" or "Levels" - but not as refined. Any rudimentary method would also help.
Currently, I can only do "Color Overlay" without changing the opacity. Any method of adding a color overlay with opacity change would be helpful as long as it doesn't change the opacity of the entire sprite but just the overlay color.
I am working on a 2D game with imported PNG Sprites. If any more information is required, I'll be happy to provide it.
Additional Information -
What my sprite looks like
I want to make it darker through code twice like this -
By doing node.modulate= Color(0.0, 0.0, 0.0,1) it becomes like this -
The reason why I'm avoiding to do this manually because I have too many sprites and doing this for all of them will be tedious.
Here's two examples of how you can darken a sprite via code.
The first method is by using self_modulate. Modulation is calculated by multiplying the modulation value by texture color value. This shows that modulation of (1, 1, 1, 1) is the same as the original texture. A modulation of (0.5, 0.5, 0.5, 1) halves the texture color making it darker like it has a half opacity black overlay.
# On a node that extends CanvasItem
self_modulate = Color(0.5, 0.5, 0.5, 1.0)
The second method is to subtract the texture value by a constant. This creates a texture that's more saturated but darker.
The shader code:
shader_type canvas_item;
uniform float difference: hint_range(0.0, 1.0) = 0.0;
void fragment() {
vec4 tex = texture(TEXTURE, UV);
COLOR.rgb = tex.rgb - vec3(difference);
COLOR.a = tex.a;
}
The other code:
# On a node that extends CanvasItem
material.set_shader_param('difference', 0.3)
These effects can be combined to produce the desired result. Play around with the shader to produce a better result.
Hope this helps.

Lego style split screen camera in godot

I want to have lego style splitscreen camera with seamless transitions.
Anyone has any experience creating something like this? I thought of creating one normal camera and then another camera for second player that by default wouldn't be visible. Then, when i would want to show it, i would draw a triangle to split the screen and set it texture as camera #2 view.
I found this Unity implementation but i couldn't implement it in Godot. I've managed to create second viewport with it's own camera, but for some reason the view of the second camera is not showing anything. I'm thinking that the problem is that the world of the second viewport is different than the main viewport.
Source code can be found here.
I just setup a toy project to test this out and it turned out to be simpler than expected.
Here is an overview of the process and then code examples will follow.
Add one main camera
And a secondary camera with tree: Control > Viewport > Camera
Draw the shape of the split screen with Control using the draw_* api
Add a shader to Control that takes a texture and draws it at SCREEN_UV
Get the viewport texture from Viewport
Pass the viewport texture to the Control shader every frame.
Animate the split by animating and redrawing the Control shape.
I'm not sure how to do the border.
To make the split join you'll probably have to shift the Control shape by the thickness of border and then shrink that border as the cameras go towards each other. Use that distance between the players to calculate the border width.
The split border is also at an angle between the two players so when animating the shape you'll want to use that angle. This will make the joining of the viewport look smoother.
Control code:
extends Control
func _draw():
# in this case animate tl and bml to get the
# rotating split like effect in the lego game
var tl = Vector2()
var tr = rect_size
tr.y = 0
var br = rect_size
var bml = rect_size
bml.x /= 2.0
draw_polygon([tl, tr, br, bml, tl], [Color(), Color(), Color(), Color(), Color()], [])
func _process(d):
material.set_shader_param('viewport', $Viewport.get_texture())
Shader Code:
shader_type canvas_item;
uniform sampler2D viewport;
void fragment(){
COLOR=texture(viewport, SCREEN_UV);
}
I hope this helps get you started!
It is a complex effect with many parts so be warned.
I found that the easiest way is to create a separate scene with your viewports and cameras which will be your main scene and then add your game scene under it like this:
Spatial
Viewport1
Camera1
Viewport2
Camera2
GameScene
You should then be able to make a ColorRect with a shader material and send in the textures from each viewport:
shader_type canvas_item;
render_mode unshaded, cull_disabled;
uniform sampler2D viewport1;
uniform sampler2D viewport2;
void fragment() {
vec3 view1 = texture(viewport1, UV).rgb;
vec3 view2 = texture(viewport2, UV).rgb;
vec3 col = vec3(0);
// mix them in a satisfying way depending on distance and angle between cameras
// float mixVal = <your formula here>
// col = mix(view1, view2, mixVal)
COLOR = vec4(col, 0.0); // this may not work in Godot shaders
}
This is a great guide to get you started:
https://docs.godotengine.org/en/3.1/tutorials/viewports/using_viewport_as_texture.html

How to isolate a Phaser shader to a specific object/shape?

I'm using the Phaser framework. Here is the jsfiddle:
http://jsfiddle.net/Dillybob/u3mGL/13/
Here is where the filter is getting populated:
background = game.add.sprite(0, 0);
background.width = 800;
background.height = 600;
filter = game.add.filter('Fire', 800, 600);
filter.alpha = 0.0;
background.filters = [filter];
My line object is assigned to the variable drawnObject
So I assign that object to receive the filter like so:
drawnObject.filters = [filter];
But my line is now a red fiery square instead of being a line with a fiery background, why?
Firstly, be aware that drawnObject is actually a bitmap, which is rectangular shaped. It consists of white pixels, which build your line, and transparent pixels, which are taking the rest of bitmap space.
The filter you use is a pixel shader. Pixel shader describes instructions that GPU invokes for each pixel of a provided bitmap. In case of this shader, it creates fire effect based on some noise functions, but it doesn't take original bitmap into account. The original color of pixels is not preserved, it doesn't add to final effect in any way.
To achieve your expected result, you have to amend fragmentSrc in Fire.js, so that shader uses and mixes/blends original color into final pixel color and/or doesn't change pixel transparency.

androidplot background image shift

I'm trying to separate the background of the graph grid in 3 areas using this code:
int[] data = {0xff000000, 0x80008000, 0xff000000};
bgBitmap = Bitmap.createBitmap(data, 1, 3, Bitmap.Config.ARGB_8888);
RectF rect = plot.getGraphWidget().getGridRect();
BitmapShader myShader = new BitmapShader(
Bitmap.createScaledBitmap(bgBitmap, 1, (int) rect.height(), false),
Shader.TileMode.REPEAT,
Shader.TileMode.REPEAT);
plot.getGraphWidget().getGridBackgroundPaint().setShader(myShader);
So scaling a 3 pixel bitmap to the graph height and repeating it over the whole domain area.
However the resulting graph show that the background seems to be shifted up a bit.
It looks like the shift size is about equal to the domain label height.
How can I fix this?
Hm cannot post picture because of 'reputation' sigh.
Link to the example graph: http://marcel.mesa.nl/androidplot.png
I think you're running into the issue mentioned near the end of this thread. Essentially, the origin of the shader is the top-left corner of the screen, not the top-left corner of component for which the background is being drawn using the shader. The solution is to translate to the top-left point of the graphWidget like this:
RectF rect = plot.getGraphWidget().getGridRect();
Matrix m = new Matrix();
m.setTranslate(rect.left, rect.top);
shader.setLocalMatrix(m); // where shader is your shader instance

Very large HTML5 canvas circle imprecise

I'm developing an application where users draw euclidean constructions on the HTML5 canvas. As such I can't really limit the size of certain shapes. When exaploring very large circles being drawn on the screen I noticed that very large circles don't have a constant radius.
To be more specific, a circle defined by two points, a center point and one specifing the radius doesn't pass throught the radius point anymore!
Progressivly larger circles. These are all supposed to pass through point E.
The error doesn't occure on multiples of 45 degrees = PI/4. Between these multiples the error is biggest (PI/8 for example)
Here is a jsfiddle containing the first example above:
http://jsfiddle.net/D28J2/2/
My questions: Why does this occure? and Is there some way to (efficently) work around this?
The way I worked around this issue completely was roll my own implementation of a circle draw approximation with bezier curves. An article detailing the implementation can be found here http://www.tinaja.com/glib/ellipse4.pdf.
function magic_circle(ctx, x, y, r){
m = 0.551784
ctx.save()
ctx.translate(x, y)
ctx.scale(r, r)
ctx.beginPath()
ctx.moveTo(1, 0)
ctx.bezierCurveTo(1, -m, m, -1, 0, -1)
ctx.bezierCurveTo(-m, -1, -1, -m, -1, 0)
ctx.bezierCurveTo(-1, m, -m, 1, 0, 1)
ctx.bezierCurveTo( m, 1, 1, m, 1, 0)
ctx.closePath()
ctx.restore()
}
With just these four segements I was able to approximate a circle much better then the build in google chrome canvas implementation.
This is probably a floating point cutoff error. Possibly because sine and cosine aren't giving perfectly accurate values. You can get around it (in Chrome at least) by rotating the canvas instead of the arc.
ctx.save(); // Save the canvas so we can rotate back.
ctx.translate(x, y); // Translate to the origin point.
ctx.rotate(alpha); // Rotate the proper angle.
ctx.arc(0, 0, 3, 0, Math.PI*2); // Draw the small circle at the origin.
ctx.fill();
ctx.arc(r, 0, r, 0, Math.PI*2); // Create a big with the origin 1 radius away.
ctx.restore(); // Restore the canvas to the original orientation
// before drawing. Otherwise the circle looks bad.
ctx.strokeStyle = "black";
ctx.stroke(); // Draw!
I am a big fan of manipulating the canvas instead of shapes. It gives you a more logical area to work with. See http://jsfiddle.net/D28J2/10/
Just throwing this out there but could it be an issue without specifying enough digits of PI? Whenever I do things like that I tend to go slightly overboard and use about 10 digits of PI.
In Google chrome I can repeat the issue but in IE 9 and IE 10 all is fine.
So my guess is that the implementation is wrong in Chrome. It might be a rounding error or they used an interpolation method to avoid sin and cos which isn't very acurate.
Look here as well: HTML5 canvas arcs not rendering correctly in Google Chrome
The only work around I can imagine is drawing the circle by your own code or using a (jQuery?) plug-in that does this for you.

Resources