PIXI remove spriteSheet Texture cache - javascript

I have loaded spriteSheetFrame using json.
const loader = new PIXI.loaders.Loader();
loader.add('bunny', 'data/bunny.png')
.add('spaceship', 'assets/spritesheet.json');
loader.load((loader, resources) => {
});
I want to remove all the TextureCache which was loaded using this spritesheet.json only.
I have tried.
PIXI.Texture.removeFromCache("spaceship");
PIXI.Texture.removeTextureFromCache("spaceship");
But in PIXI.TextureCache names of all the spriteFrame were included there.
And still i am able to use image form frame. Using this.
var bgSprite2 = PIXI.Sprite.fromFrame("ship1");
bgSprite2.anchor.set(0.5, 0.5);
var pos = {x: 300, y: 200};
bgSprite2.position.set(pos.x, pos.y);
stage.addChild(bgSprite2);
I want to remove all the entries of spriteFrame in TextureCache and i want to load new set of spriteFrame.
I am doing this because i have spritesheet animations of two diffrent spaceship but the individual symbol name of both spaceship are same.

I would agree with Hachi that you could gain some performance from just replacing the texture rather than destroying and re-creating over and over. Caching could be the answer.
You could then eventually call destroy when your done with them to make sure there is nothing lingering around.

Related

three.js: How can I target object's position to another (grouped) object, while allowing rotation to follow AR camera?

I'm using an augmented reality library that does some fancy image tracking stuff. After learning a whole lot about this project, I'm now beyond my current ability and could use some help. For our purposes, the library creates an (empty) anchor point at the center of an IRL image target in-camera. Then moves the virtual world around the IRL camera.
My goal is to drive plane.rotation to always face the camera, while keeping plane.position locked to the anchor point. Additionally, plane.rotation values will be referenced later in development.
const THREE = window.MINDAR.IMAGE.THREE;
document.addEventListener('DOMContentLoaded', () => {
const start = async() => {
// initialize MindAR
const mindarThree = new window.MINDAR.IMAGE.MindARThree({
container: document.body,
imageTargetSrc: '../../assets/targets/testQR.mind',
});
const {renderer, scene, camera} = mindarThree;
// create AR object
const geometry = new THREE.PlaneGeometry(1, 1.25);
const material = new THREE.MeshBasicMaterial({color: 0x00ffff, transparent: true, opacity: 0.5});
const plane = new THREE.Mesh(geometry, material);
// create anchor
const anchor = mindarThree.addAnchor(0);
anchor.group.add(plane);
// start AR
await mindarThree.start();
renderer.setAnimationLoop(() => {
renderer.render(scene, camera);
});
}
start();
});
Everything I've tried so far went into the solutions already massaged into the (functioning draft) code. I have, however, done some research and found a couple avenues that might or might not work. Just tossing them out to see what might stick or inspire another solution. Skill-wise, I'm still in the beginner category, so any help figuring this out is much appreciated.
identify plane object by its group index number;
drive (override lib?) object rotation (x, y, z) to face camera;
possible solutions from dev:
"You can get those values through the anchor object, e.g. anchor.group.position. Meaning that you can use the current three.js API and get those values but without using it for rendering i.e. don't append the renderer.domElement to document."
"You can hack into the source code of mindar (it's open source)."
"Another way might be easier for you to try is to just create another camera yourself. I believe you can have multiple cameras, and just render another layer on top using your new camera."
I think it may be as simple as calling lookAt in the animation loop function:
// start AR
await mindarThree.start();
renderer.setAnimationLoop(() => {
plane.lookAt(new THREE.Vector3());
renderer.render(scene, camera);
});
This assumes the camera is always located at (0,0,0) (i.e., new THREE.Vector3()). This seems to be true from my limited testing. I found it helpful to debug by copy-pasting the MindAR three.js example into this codepen and printing some relevant values to the console.
Also note that, internally, MindAR's three.js module seems to directly modify the world matrix of the anchor.group object without modifying the position/rotation/scale parameters.

Three.js adding a rigged, animated Asset to an existing Scene

I'm working on a Tamagotchi like browser app in three.js at the moment. But currently I'm stuck with implementing a hand, that pets the avatar when clicked.
The Hand is a rigged Blender model with 2 animations, idle and the poking animation. In the gltf Viewer the model works fine with both animations.
But when added in js, the hand is either completely distorted, or rendered correctly but, positions aren't recognized(for movement with the cursor).
Most of the examples I looked at only added a general scene, but not just one animated model. In both versions of those animations, I get an animation error.
Code for the distorted version:
loader.load('resources/models/gltf/Hand.gltf', function(gltf) {
gltf.scene.traverse(function(node) {
if (node.isMesh) hand = node;
});
//hand.material.morphTargets = true;
scene.add(hand);
mixer = new THREE.AnimationMixer(hand);
clips = hand.animations;
hand = gltf;
scene.add(hand.scene);
});
The second version, where the Hand is rendered correctly, but positions for event handling aren't recognized.
loader.load('resources/models/gltf/Hand.gltf', function(gltf) {
var hand = gltf.scene;
var animations = gltf.animations;
mixer = new THREE.AnimationMixer(hand);
for (var i = 0; i < animations.length; i++) {
mixer.clipAction(animations[i]).play();
}
scene.add(hand);
});
function for idle animation:
function idleAnim() {
var idleClip = THREE.AnimationClip.findByName(clips, "Idle");
var action = mixer.clipAction(idleClip);
action.play();
console.log("idling");
}
Link: https://github.com/JoeJoe49/AnimTest
Thanks in advance and greetings.
In your first example, you're pulling the "hand" object out of your import scene, adding it to your render scene, Then adding the rest of the import scene to your render scene.
My guess is that you need to pull out "hand" from higher in the hierarchy. It probably has a few parent objects that need to come along with to preserve the correct hierarchy for the animation.
It's worth doing a scene.traverse((o)=>{console.log(o)} to get a clear picture of how your scene is being exported. I've found with the blender gltf exporter for instance, there are usually 2 separate parent nodes, one for positioning and one for scaling+rotation, so.. it's worth looking at because it might not be exactly what you expect.
fwiw I grabbed your repo and opened the gltfs in my model previewer, but I didn't seem to see any animations on them. My previewer is set to play all animations it finds, in sequence.. so not sure what's going on there. I'm guessing these are skinnedmeshes and not morphtargets?

Fabric.js - how to use custom cursors without drawing mode

I have no idea how to set up cursor image for drawing on the Canvas. I have noticed that I can set it only when
FABRICCANVAS.isDrawingMode = true;
However, the problem is that I have created dedicated drawing tools and I don't want to use those that are built into the Fabric.js.
Sample of my code (which doesn't work properly):
const FABRICCANVAS = new fabric.Canvas('canvas-draft');
const DRAFT = document.querySelector(".upper-canvas");
button.addEventListener('click', () => {
DRAFT.style.cursor = 'url(img/cursors/image.png) 0 34, auto';
});
But when I set isDrawingMode to true, it works. Unfortunately, I don't want to use built-in drawing tools because they leave paths (that can then be moved later, when FABRICCANVAS.selection = true).
Do you know any solution for this problem?
For the Canvas you can set different cursors:
e.g.
canvas.hoverCursor
canvas.defaultCursor
canvas.moveCursor
You can use absolute or relative paths to your cursor image:
canvas.moveCursor = 'url("...") 10 10, crosshair';

Pattern for using Meteor with advanced SVG or Canvas Ouput

Is it sensible to use Meteor for a reactive data display that isn't primarily HTML based?
To be specific, I want to display a graph database as a set of boxes connected by lines. I'd like to allow live interaction with these boxes, and I'd also like them to be reactive, so if one user edits the data the display of any other users currently viewing the graph will update.
Meteor seems great for the reactivity, but most of the examples I've found focus on either HTML templates or very simple API interactions for doing things like adding a pin to a map.
I am currently thinking about using SVG or Canvas to display the graph database, but I am very unsure how best to integrate that with Meteor and/or some other library like maybe D3.
I found that Meteor works perfectly with canvas, I don't know if what I do is the best practice but I got the best results using Kinetic.js (available for Meteor via "mrt install kineticjs" and I use the template engine to call on functions that set up the elements on my canvas, this is a small example of a code I use to place the players on my map:
the Template:
<template name="canvas_map">
<div id="grid_map" class="grid"></div>
{{#with clear_canvas}}
{{#each human}}
{{handle_member_pos}}
{{/each}}
{{/with}}
the "clear_canvas" helper sets up a new Kinetic.Stage and the "handle_member_pos" helper gets a human object and places it on said canvas.
here are the helpers (coffeescript):
Template.canvas_map.clear_canvas = =>
if Session.get('init')
kinetic_elements.stage = new Kinetic.Stage
container: 'grid_map'
width: 385
height: 375
kinetic_elements.layer = new Kinetic.Layer()
else
false
Template.canvas_map.handle_member_pos = ->
[x, y] = pos_to_str #profile.pos
left = Math.floor(11 * x)
top = Math.floor(11 * y)
name = #profile.name
unless kinetic_elements.avatars[name]?
imageObj = new Image()
imageObj.onload = =>
element = new Kinetic.Image
x: left
y: top
image: imageObj
width: 50
height: 50
element.on 'click', (evt) =>
Session.set 'selected', #profile._id
window.propogation = false
false
kinetic_elements.layer.add element
kinetic_elements.avatars[name] = [element, text]
kinetic_elements.stage.add kinetic_elements.layer
imageObj.src = 'human.png'
else
element = kinetic_elements.avatars[name]
layer = kinetic_elements.layer
element.setX left
element.setY top
layer.draw()
return
as I said, I'm not sure if that is the best practice, but it works great for me, hope this helps in any way.

Fabric.js loadSVGFromUrl not displaying multiple imported SVGS

I'm using fabric.js and loading a number of SVG files into it. I have no problem displaying one of these imported files using this code;
fabric.loadSVGFromURL('ico-svg/drink.svg', function(objects, options) {
var drink = fabric.util.groupSVGElements(objects, options);
drink.set({left: 80,
top: 175,
width: 32,
height: 32 });
canvas.add(drink);
canvas.calcOffset();
canvas.renderAll();
});
However, when I repeat this code, the page only shows one of the two SVGs, and they actually change upon page refresh - only one icon will show one time, one icon will show the other, on the odd occasion they will both show but one of the SVGs won't display completely.
To load the other SVG, i'm simply copying the above code and changing the required variables;
fabric.loadSVGFromURL('exporttest.svg', function(objects, options) {
var dollars = fabric.util.groupSVGElements(objects, options);
dollars.set({left: 80,
top: 90,
width: 350,
height: 342 });
canvas.add(dollars);
canvas.calcOffset();
canvas.renderAll();
});
fabric.loadSVGFromURL('ico-svg/drink.svg', function(objects, options) {
var drink = fabric.util.groupSVGElements(objects, options);
drink.set({left: 80,
top: 175,
width: 32,
height: 32 });
canvas.add(drink);
canvas.calcOffset();
canvas.renderAll();
});
Is this something i'm doing wrong? I've read that the library support for loading SVGs from URLs isn't that fantastic - could it be that? Ideally, loading the SVGs from an URL this way or in a similar way is my best option as there are so many, and they are each quite complex and require different positioning.
I think this was a bug that has been fixed in the library.
Current fabricjs.com offer a kitchensink demo where you can try code.
http://fabricjs.com/kitchensink/
copy paste the code below in the execute tab to load 3 svg togheter without any strange issue or taking any precaution.
// clear canvas
canvas.clear();
// remove currently selected object
canvas.remove(canvas.getActiveObject());
fabric.loadSVGFromURL('../assets/1.svg', function(objects, options) {
var dollars = fabric.util.groupSVGElements(objects, options);
canvas.add(dollars);
canvas.calcOffset();
canvas.renderAll();
});
fabric.loadSVGFromURL('../assets/2.svg', function(objects, options) {
var drink = fabric.util.groupSVGElements(objects, options);
canvas.add(drink);
canvas.calcOffset();
canvas.renderAll();
});
fabric.loadSVGFromURL('../assets/3.svg', function(objects, options) {
var drink = fabric.util.groupSVGElements(objects, options);
canvas.add(drink);
canvas.calcOffset();
canvas.renderAll();
});
I actually do this as well, where a user can select any number of SVG files to load and later come back to edit their work. When they come back, I had the same issue while trying to reload the multiple files. In my case, I am actually building an array of objects that hold the svg url along with other useful pieces of information. This allowed me to load them into a stack (most suiting for my loading order, though you could easily implement it with a queue) and then pop them off one at a time.
var loadingLayerStack = [url1, url2, url3];
function ProcessLayerLoading()
{
var layerUrl = loadingLayerStack.pop();
DrawSvgToCanvas(layerUrl);
}
function DrawSvgToCanvas(url)
{
fabric.loadSVGFromURL(url, function(objects, options) {
var obj = fabric.util.groupSVGElements(objects, options);
// ...any code for special handling of the loaded object
// put object on the canvas
canvas.add(obj);
// get the next image
ProcessLayerLoading();
});
}
It is noteworthy to point out that I have the setting to enable Rendering when an object is added. So that canvas.add call also takes care of the initial rendering for me.
Hope this helps you somehow. :)
I just ran into this same problem, after seeing your post I decided to dig in to it a bit further myself. It turns out to be due to a scope issue in the onComplete callback within loadSVGFromURL. The problem stems from not isolating the url to a single scope; making multiple back-to-back calls results in the last url always being used when onComplete fires. As a workaround you could either chain your SVG loads or just make an ajax request yourself and load it using loadSVGFromString instead.
I'm learning fabric seems to be full of these bugs, errr, gotchas :(
Edit
I spoke too soon, loadSVGFromString suffers from the same weakness, it does not work asynchronously. That being said chaining is the most obvious work-around.
fabric.loadSVGFromURL() fetches the SVG via XmlHttpRequest. If you wait for each request to complete you can load multiple. Which means you need a tool for making and composing asynchronous promises in JavaScript. Check out q. https://github.com/kriskowal/q

Categories

Resources