Only show opaque objects behind transparent objects - graphics

I am using three.js and WebGl. I would like to make certain objects in my scene transparent, and only show opaque objects behind the transparent objects, not other transparent objects.
Currently, when I make objects transparent, I can see other transparent objects behind them, which I don't want.
This is what happens now:
This is what I want:
Is there a term for this type of transparency rendering? It seems like I could accomplish this with multiple rendering passes.
I am working with three.js and WebGl but I haven't found a solution yet in any language, so I am open to any generic tips.

If what you are looking for is to only render the front most layer of transparent objects, you can try this:
gl.enable(gl.DEPTH_TEST);
// dont write to color buffer, only to depth
gl.depthFunc(gl.LEQUAL);
gl.colorMask(false, false, false, false);
drawTransparentObjects();
// only draw to front most layer
gl.depthFunc(gl.EQUAL);
gl.colorMask(true, true, true, true);
drawTransparentObjects();
// switch back to normal depth testing
gl.depthFunc(gl.LEQUAL);

Just guessing but I think this would work
// at init time
renderer.autoClear = false;
// at render time
renderer.clear(true, true, true);
renderer.render( sceneOfObjectsYouWantInBack, camera)
renderer.clear(false, true, true);
renderer.render( sceneOfObjectsYouWantInMiddle, camera)
renderer.clear(false, true, true);
renderer.render( sceneOfObjectsYouWantInFront, camera)
renderer.clear(false, true, true);

Related

Rendering a ID3D11Texture2D into a SkImage (Skia)

I'm currently trying to create an interop layer to render my render target texture into a Skia SkImage. This is being done to facilitate rendering from my graphics API into Avalonia.
I've managed to piece together enough code to get everything running without any errors (at least, none that I can see), but when I draw the SkImage I see nothing but a black image.
Of course, these things are easier to describe with code:
private EglPlatformOpenGlInterface _platform;
private AngleWin32EglDisplay _angleDisplay;
private readonly int[] _glTexHandle = new int[1];
IDrawingContextImpl context // <-- From Avalonia
_platform = (EglPlatformOpenGlInterface)platform;
_angleDisplay = (AngleWin32EglDisplay)_platform.Display;
IntPtr d3dDevicePtr = _angleDisplay.GetDirect3DDevice();
// Device5 is from SharpDX.
_d3dDevice = new Device5(d3dDevicePtr);
// Texture.GetSharedHandle() is the shared handle of my render target.
_eglTarget = _d3dDevice.OpenSharedResource<Texture2D>(_target.Texture.GetSharedHandle());
// WrapDirect3D11Texture calls eglCreatePbufferFromClientBuffer.
_glSurface = _angleDisplay.WrapDirect3D11Texture(_platform, _eglTarget.NativePointer);
using (_platform.PrimaryEglContext.MakeCurrent())
{
_platform.PrimaryEglContext.GlInterface.GenTextures(1, _glTexHandle);
}
var fbInfo = new GRGlTextureInfo(GlConsts.GL_TEXTURE_2D, (uint)_glTexHandle[0], GlConsts.GL_RGBA8);
_backendTarget = new GRBackendTexture(_target.Width, _target.Height, false, fbInfo);
using (_platform.PrimaryEglContext.MakeCurrent())
{
// Here's where we find the gl surface to our texture object apparently.
_platform.PrimaryEglContext.GlInterface.BindTexture(GlConsts.GL_TEXTURE_2D, _glTexHandle[0]);
EglBindTexImage(_angleDisplay.Handle, _glSurface.DangerousGetHandle(), EglConsts.EGL_BACK_BUFFER);
_platform.PrimaryEglContext.GlInterface.BindTexture(GlConsts.GL_TEXTURE_2D, 0);
}
// context is a GRContext
_skiaSurface = SKImage.FromTexture(context, _backendTarget, GRSurfaceOrigin.BottomLeft, SKColorType.Rgba8888, SKAlphaType.Premul);
// This clears my render target (obviously). I should be seeing this when I draw the image right?
_target.Clear(GorgonColor.CornFlowerBlue);
canvas.DrawImage(_skiaSurface, new SKPoint(320, 240));
So, as far as I can tell, this should be working. But as I said before, it's only showing me a black image. It's supposed to be cornflower blue. I've tried calling Flush on the ID3D11DeviceContext, but I'm still getting the black image.
Anyone have any idea what I could be doing wrong?

Select and manipulate particular paths within a path group fabric.js

I am making an app that involves shapes like cylinders and boxes, and need to be able to do this with fabric.js. I know about three.js but for my purposes, it must be in 2D.
Initially I thought I would just create them in 3D software and render images which can then be added to the canvas, which I did successfully...
However, I have run into a hurdle where fabric only allows patterns to be filled onto paths or objects (rect, circle etc.)....not images (png).
Since I absolutely need patterns, I now need to create these cylinders in SVG. I have gotten as far as making the cylinders in Illustrator, saving them as SVG's and then using them on the canvas, then adding fill patterns on them. So far so good.
Now I want to be able to fill a different pattern for the top of the cylinder, and a different pattern to the side BUT still have it as one object.
So...How can I select and manipulate particular paths within a path group? Is there anyway to give each path within the group a custom attribute (eg. name) which I can then target? Do I need to create two seperate SVG files and then add them seperately, and if so, how can I do this and still have it as one object?
Here's how I am adding the svg to the canvas...
fabric.loadSVGFromURL("/shapes/50-250R.png", function(objects) {
var oImg = fabric.util.groupSVGElements(objects);
oImg.perPixelTargetFind = true;
oImg.targetFindTolerance = 4;
oImg.componentType = "Shape";
oImg.lockUniScaling = true;
oImg.lockScalingX = true;
oImg.lockScalingY = true;
oImg.setControlsVisibility({'tl': false, 'tr': false, 'bl': false, 'br': false});
canvas.add(oImg);
canvas.renderAll();
});
Here is how I am adding the pattern...
var textureIMG = new Image;
textureIMG.crossOrigin = "anonymous";
textureIMG.src = texture.image;
obj.setFill(); //For some reason, the fill doesn't happen without this line.
var pattern = new fabric.Pattern({
source: textureIMG,
repeat: 'repeat'
});
if (obj instanceof fabric.PathGroup) {
obj.getObjects().forEach(function(o) {
o.setFill(pattern);
});
} else {
obj.setFill(pattern);
}
canvas.renderAll();
Thanks in advance.
So I managed to figure this out. Each path within the path group is stored in the 'paths' array of the object.
I can now add a pattern to the top of the cylinder using...
var obj = canvas.getActiveObject();
obj.paths[0].fill = patternOne;
and to the sides using...
obj.paths[1].fill = patternTwo;

cocos2d js - Touch on overlay sprites that move up together

I used latest version cocos2d-js to create my game. On the game screen, I added multiple sprites overlay in a row, like this
Overlay sprites
I added an event listener to move up a sprite on y-axis when it was clicked. However, when I clicked on the point that any two sprites contain, the two sprites moved up together.
This is my event listener code
var listener = cc.EventListener.create({
event: cc.EventListener.TOUCH_ONE_BY_ONE,
swallowTouches: true,
onTouchBegan: function (touch, event) {
var target = event.getCurrentTarget();
var location = target.convertToNodeSpace(touch.getLocation());
var targetSize = target.getContentSize();
var targetRectangle = cc.rect(0, 0, targetSize.width, targetSize.height);
if (cc.rectContainsPoint(targetRectangle, location)){
target.setPositionY(50);
}
}
});
How can I prevent to move them up together and move only one sprite?
Thanks.
onTouchBegan must returns boolean value as result, if returns true it's means touch was handled and event cycle will be stopped. Try to return true, if rect contains point.
Hope this helps. And sorry for my English.

Phaser.io - Load objects from Tiled

I'm new to phaser, and for the past few days I've been trying to make a really simple game, platformer-style, where the player must navigate to certain areas before being able to exit the level.
I have the basics running, but now I can't seem to figure out how to check if the player is in those areas.
The relevant part of the code so far is as follows:
var game = new Phaser.Game(800, 600, Phaser.AUTO, "mygame", {
preload: preload,
create: create,
update: update,
render: render
});
function preload() {
game.load.tilemap("questMap", "assets/quest.json", null, Phaser.Tilemap.TILED_JSON);
game.load.image("tilesheet", "assets/tilesheet.png");
game.load.image("npc", "assets/npc.png");
game.load.spritesheet("player", "assets/player.png", 64, 64);
}
var map;
var tileset;
var groundBg;
var props;
var houses;
var houseProps;
var npc;
var ground;
var areas;
var player;
function create() {
game.physics.startSystem(Phaser.Physics.ARCADE);
game.stage.backgroundColor = "#A8DBFF";
map = game.add.tilemap("questMap");
map.addTilesetImage("tilesheet");
map.addTilesetImage("npc");
ground = map.createLayer("ground");
groundBg = map.createLayer("groundbg");
props = map.createLayer("props");
houses = map.createLayer("houses");
houseProps = map.createLayer("houseprops");
npc = map.createLayer("npc");
map.setCollisionBetween(1, 5000);
ground.resizeWorld();
Not too pretty, I know.
I've created the map with tiled and there are a lot of small props and decorative tiles, hence the multiple "map.createLayer()" calls. The only one with collision is the ground layer.
Now, on my Tiled file, I've created an Object layer and drawn small rectangles on the areas I want to check if the player is in. I thought this was going to be an easy process but I can't seem to figure out how to load those areas into Phaser, and then check if the player is within bounds.
Googling has given me some results, but none seem to fit, as they usually cover how to add a sprite to an object, which in this case does not apply.
I simply need that small area to exist and check if the player is there. I've also given names to each of those rectangles in Tiled, via the custom properties tab.
I would try using a transparent image as the area you wish to check if your sprite is over and use
if(sprite1.overlap(transparentImage)){
//do something
}

d3 basic animations

Trying to follow along the tutorial here, but there isn't enough code presented to me to bridge the gaps.
Here is the fiddle I am working on to accomplish the same thing, with d3 loaded, however, the animation transitions are not concurrently happening, let alone at all, it is just changing the attributes, something I am already familiar with in SVG hard coding with JQuery selectors. So where am I going wrong, or missing the boat?
// example code doesn't work
var circle = svg.selectAll("circle");
circle.style("fill", "steelblue");
circle.attr("cy", 90);
circle.attr("r", 30);
// this does, but animations don't work
d3.selectAll('circle').style("fill", "steelblue");
d3.selectAll('circle').attr("cy", 90);
d3.selectAll('circle').attr("r", 30);
I am eventually trying to leverage the tweening of d3, but I cant get the basics off the ground. Thanks for you help in advance....
In the example code, svg is previously assigned to a d3 selection object:
var svg = d3.select("#chart-2").append("svg")
.attr("width", w)
.attr("height", h);
Therefore, you can use it to select the child elements, as in the original example.
Eg. your fiddle could be rewritten like so:
var svg = d3.select("#svg");
//svg is now a d3.selection object.
svg.on("click", function() {
var circle = svg.selectAll("circle");
circle.style("fill", "steelblue");
circle.attr("cy", 90);
circle.attr("r", 30);
});
Something to note about binding events using d3:
Within the anonymous function:
The event is bound to d3.event
The dom element - not the d3.selection object - is bound to this
If you pass an argument to the function, it will be bound to the data which is joined to the element.
Not really code, but should show what I mean:
var someD3Selection = d3.select("#someElement");
someD3Selection.on("click", function(boundData) {
d3.event.preventDefault(); // <-- here's the event
this; // <-- the actual dom element which is selected in someD3Selection
d3.select(this); // <-- same as someD3Selection.
});
Is this what you're looking for? The duration is optional but it's easier to see what's happening when it's a bit slower.
$('#svg').on('click', function() {
d3.selectAll('circle').style("fill", "grey").transition().duration(5000).style("fill", "steelblue").attr("cy", 90).attr("r", 30);
});

Resources