Fastest way to tile a drawing with pixi.js? - pixi.js

I have a computationally heavy drawing that is rendered by a pixi.js render.
I then create sprites from the renderer view in order to tile the drawing horizontally and I render the sprites on the on-screen canvas (using webgl as auto-detected)
However, I find the whole operation to be still slow. Can you tell how performances could be improved? I'm not sure if RenderTexture could be used instead, and if it would make a significant gain.
Thanks for your help, this is a code extract of my script:
var canvasRenderer = new PIXI.autoDetectRenderer(w, h, {
view : $('#canvas')[0],
clearBeforeRender : false
});
var canvasGraphics = new PIXI.Graphics();
var canvasStage = new PIXI.Container();
canvasStage.addChild(canvasGraphics);
canvasGraphics.beginFill();
var renderer = new PIXI.autoDetectRenderer(width, height);
var graphics = new PIXI.Graphics();
var stage = new PIXI.Container();
stage.addChild(graphics);
graphics.beginFill();
// Whole lotta rects
for (var i in rects) {
graphics.drawRect(
rects[i].left, rects[i].top, rects[i].width, rects[i].height
);
}
graphics.endFill();
renderer.render(stage);
for (var j = 0; j <= loops; j++) {
var sprite = PIXI.Sprite.from(renderer.view);
sprite.x = j * width;
canvasStage.addChild(sprite);
}
}
canvasGraphics.endFill();
canvasRenderer.render(canvasStage);

PIXI has a TilingSprite for exactly this purpose.
If you're drawing graphics, you should use a RenderTexture, and then put that into a TilingSprite.
var renderer = new PIXI.autoDetectRenderer(width, height);
var stage = new PIXI.Container();
//Draw your Graphics
var graphics = new PIXI.Graphics();
graphics.beginFill();
for (var i in rects) {
graphics.drawRect(
rects[i].left, rects[i].top, rects[i].width, rects[i].height
);
}
graphics.endFill();
//Create a RenderTexture to hold the Graphics.
//I don't know the size of your Graphics, so I'm making it up as 50 x 50
var texture = new PIXI.RenderTexture(new PIXI.BaseRenderTexture(50, 50));
//Render the Graphics into the Texture
renderer.render(graphics, texture);
//Create a TilingSprite from the Texture
var tilesprite = new PIXI.extras.TilingSprite(texture, renderer.width, renderer.height);
stage.addChild(tilesprite);
renderer.render(stage);

Related

Turn 3d .obj into a SVG with SVG renderer

Using the WebGLRenderer, successfully loaded an .obj file created in Cinema4d.
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 );
camera.position.z = 200;
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
var controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.25;
controls.enableZoom = true;
var keyLight = new THREE.DirectionalLight(new THREE.Color('hsl(30, 100%, 75%)'), 1.0);
keyLight.position.set(-100, 0, 100);
var fillLight = new THREE.DirectionalLight(new THREE.Color('hsl(240, 100%, 75%)'), 0.75);
fillLight.position.set(100, 0, 100);
var backLight = new THREE.DirectionalLight(0xffffff, 1.0);
backLight.position.set(100, 0, -100).normalize();
scene.add(keyLight);
scene.add(fillLight);
scene.add(backLight);
const material = new THREE.LineBasicMaterial( {
color: 0xffffff,
linewidth: 1,
linecap: 'round', //ignored by WebGLRenderer
linejoin: 'round' //ignored by WebGLRenderer
} );
scene.add(material)
var objLoader = new THREE.OBJLoader();
objLoader.setPath('/examples/3d-obj-loader/assets/');
objLoader.load('Untitled2.obj', function (object) {
object.position.y -= 60;
scene.add(object);
});
var animate = function () {
requestAnimationFrame( animate );
controls.update();
renderer.render(scene, camera);
};
animate();
Aiming to convert this to vector using the SVGRenderer - tried swapping out the THREE.WebGLRenderer for SVGRenderer but there's clearly more to it than this, and can't find any walkthroughs, or breakdowns on here.
Can see that what I'm looking for is technically possible with three.js!
Linked an image of the 3d file I'm looking to vectorise - a simple mountain style scene - aiming for each edges of the vertices to be stroked, with no texture needed (white shape, black edges).
Tried making a JSON with Bodymovin and proved impossible to join al the paths of the vertices without lots of stray lines appearing.
enter image description here

Frame rate drops / efficiency problem in three.js [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 4 years ago.
Improve this question
Upon running there is a slow but consistent drop in fps. I have tried to identify the responsible function and it seems to be that:
updatepoints() and rotateTriangle() seem to be the main culprits but it's clear I have misunderstood something or used an inefficient means of calculating something somewhere
Upon further inspection using browser tools it seems to be an array and an object that are filling up the memory which I'm guessing is what is causing the frame drops.
I have also noticed that the buffer in the performance tab for the browser tools is filling up
I know bufferGeometry is the more efficient means of creating objects but I'd still like to know the cause the performance issues
Sorry to just dump code but I feel as though it'll be something obvious.
Any advice or ways of going about finding the problem and solution would be greatly appreciated
//every scene needs these
var scene, camera, renderer, controls;
//links div with canvas
var canvas = document.getElementById('canvas');
// What I need are number of particles and the length the curve goes to be uncoupled
// Each part of degree array serves one particles
// If I added a factor so:
// factor * coord *
//creating particles
var particleCount = 360;
var particles = [];
var particles2 = [];
var particles3 = [];
var SPEED = 0.01;
var radians, y, x;
var centerX = 0;
var centerY = 0;
var radius = 231.84;
var pointPositions=[];
var vupdateXvertices, updateYvertices, updateXvertices2, updateYvertices2,
updateXvertices3, updateYvertices3;
var pivot1;
var parent;
var pointsX = [];
var pointsY = [];
var particleMaterial = new THREE.MeshBasicMaterial({
color: 0x7a7a7a,
transparent: true,
opacity: 0.8
});
init();
animate();
function init() {
scene = new THREE.Scene();
//setup camera for scene
//PerspectiveCamera(fov, aspect, near, far [In terms of camera frustum plane])
camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 10000 );
camera.position.z = 1000;
//setup renderer for scene (generation of whatever you've made)
renderer = new THREE.WebGLRenderer();
renderer.setClearColor(0x31AED1, 1);
renderer.setSize( window.innerWidth, window.innerHeight );
//OrbitControls(Camera, HTMLDOMElement)
controls = new THREE.OrbitControls( camera, renderer.domElement );
// Set to true to enable damping (inertia), which can be used to give a sense
//of weight to the controls. Default is false.
controls.enableDamping = true;
controls.dampingFactor = 0.25;
controls.enableZoom = false;
console.log("Called");
fillSceneWithParticles();
fillSceneWithShapes();
canvas.appendChild( renderer.domElement );
renderer.render( scene, camera );
}
function fillSceneWithParticles() {
var particleGeometry = new THREE.SphereGeometry(3, 32, 32);
parent = new THREE.Object3D();
scene.add(parent);
for (var i = 0; i < particleCount; i++) {
particles[i] = new THREE.Mesh( particleGeometry, particleMaterial );
particles[i].position.x = 0;
particles[i].position.y = 0;
particles[i].position.z = (0);
particles2[i] = new THREE.Mesh( particleGeometry, particleMaterial );
particles2[i].position.x = (200);
particles2[i].position.y = (-115.57);
particles2[i].position.z = (0);
particles3[i] = new THREE.Mesh( particleGeometry, particleMaterial );
particles3[i].position.x = (0);
particles3[i].position.y = (231.84);
particles3[i].position.z = (0);
scene.add(particles[i]);
scene.add(particles2[i]);
scene.add(particles3[i]);
}
}
function fillSceneWithShapes() {
//Add a 2d Triangle W centre = 200, 115.57
var geometry = new THREE.Geometry();
geometry.vertices.push( new THREE.Vector3(-200, -115.57, 0));
geometry.vertices.push( new THREE.Vector3( 200, -115.57, 0 ));
geometry.vertices.push( new THREE.Vector3( 0, 231.84, 0 ));
geometry.vertices.push( new THREE.Vector3( -200, -115.57, 0 ));
var material = new THREE.LineBasicMaterial( { color: 0xffffff, linewidth: 10 } );
line = new THREE.Line( geometry, material );
scene.add(line);
}
function rotateTriangle() {
var geom = line.geometry.clone();
geom.applyMatrix(line.matrix);
updateXvertices = geom.vertices[0].x;
//The circle that we use to place our points
var centerX = 0;
var centerY = 0;
var radius = 231.84;
for(var degree = 90; degree < 450; degree++){
var radians = degree * Math.PI/180;
var x = centerX + radius * Math.cos(radians);
var y = centerY + radius * Math.sin(radians);
pointsX[degree - 90] = x;
pointsY[degree - 90] = y;
}
}
function updatePoints() {
//link counter with number of degrees initially created
//These are intialised because V1 = 120 degrees from V0 and V2 = 240 degrees
var counter = 120;
var counter2 = 240;
var zCounter = 0;
var curveFactor = 1;
var material = new THREE.LineBasicMaterial( { color: 0xffffff, linewidth: 10 } );
var secondTriangle = new THREE.Geometry();
for (var i = 0; i < particleCount; i++) {
parent.add(particles[i]);
//Plot points around the circle relative to vertices of triangle
particles[i].position.x = (pointsX[i]);
particles[i].position.y = (pointsY[i]);
particles[i].position.z = zCounter * curveFactor;
//If array index out of bounds then loop back to the start of array
//i.e. Go back around the circle relative to the triangle vertices
parent.add(particles2[i]);
if (counter == 360) {
counter = 0;
}
particles2[i].position.x = (pointsX[counter]);
particles2[i].position.y = (pointsY[counter]);
particles2[i].position.z = zCounter * curveFactor;
counter++;
if (counter2 == 360) {
counter2 = 0;
}
parent.add(particles3[i]);
particles3[i].position.x = (pointsX[counter2]);
particles3[i].position.y = (pointsY[counter2]);
particles3[i].position.z = zCounter * curveFactor;
counter2++;
zCounter++;
}
//Give the second triangle the position of the last particles in array
secondTriangle.vertices.push( new THREE.Vector3(particles[particleCount-1].position.x, particles[particleCount-1].position.y, particles[particleCount-1].position.z ));
secondTriangle.vertices.push( new THREE.Vector3(particles2[particleCount-1].position.x, particles2[particleCount-1].position.y, particles2[particleCount-1].position.z ));
secondTriangle.vertices.push( new THREE.Vector3(particles3[particleCount-1].position.x, particles3[particleCount-1].position.y, particles3[particleCount-1].position.z ));
secondTriangle.vertices.push( new THREE.Vector3(particles[particleCount-1].position.x, particles[particleCount-1].position.y, particles[particleCount-1].position.z ));
line1 = new THREE.Line( secondTriangle, material );
scene.add(line1);
parent.add(line1);
}
function animate() {
requestAnimationFrame( animate );
controls.update();
rotateTriangle();
updatePoints();
line1.rotation.z -= SPEED *2;
line.rotation.z -= SPEED *2;
parent.rotation.z -= SPEED *2;
renderer.render( scene, camera );
}
In retrospect it seems obvious what the problem was.
Since I had geometry.vertices.push inside my animate loop it was continuously pushing new Vectors to a buffer.
I just had to move the pushing of those vertices and that solved any frame rate and memory problems I was having

three.js orbit object around a changing axis

I have a simple 3D object and I am able to rotate i.e., move with my left mouse button, around the centre of axis - works fine. When I pan using the right mouse button the axis also shifts, as such it no longer moves around it’s present axis.
How can I move the object around it’s current axis, no matter where I drag the object?
Below is the complete code of script.js
var scene = new THREE.Scene();
var axisHelper = new THREE.AxisHelper(100);
scene.add(axisHelper);
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 );
camera.position.y = -200;
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
var controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.25;
controls.enableZoom = true;
var keyLight = new THREE.DirectionalLight(new THREE.Color('hsl(30, 100%, 75%)'), 1.0);
keyLight.position.set(-100, 0, 100);
var fillLight = new THREE.DirectionalLight(new THREE.Color('hsl(240, 100%, 75%)'), 0.75);
fillLight.position.set(100, 0, 100);
var backLight = new THREE.DirectionalLight(0xffffff, 1.0);
backLight.position.set(100, 0, -100).normalize();
scene.add(keyLight);
scene.add(fillLight);
scene.add(backLight);
var mtlLoader = new THREE.MTLLoader();
mtlLoader.setTexturePath('assets/');
mtlLoader.setPath('assets/');
mtlLoader.load('180319_object01.mtl', function (materials) {
materials.preload();
var objLoader = new THREE.OBJLoader();
objLoader.setMaterials(materials);
objLoader.setPath('assets/');
objLoader.load('180319_object01.obj', function (object) {
object.scale.set( 200, 200, 200 );
scene.add(object);
object.position.x = -100;
object.position.y = -100;
object.position.z = 0;
});
});
var animate = function () {
requestAnimationFrame( animate );
controls.update();
renderer.render(scene, camera);
};
animate();
It is because your camera is being moved by the controller and not the object itself, rather than update the cameras position and direction ((ie which is what the orbit controller is doing).in your render method you'll want to update position and Euler angle on the object itself to achieve the desired effect. To do this you'll want to track and update the position and angle of rotation about the (y?) Axis of the object,in the object (model) space.hope that makes sense, let me know if you need me to elaborate.

Phaser BitmapData Sprite Immovable on Drag

I am a noob with Phaser games in general but I am trying to make a scrabble like game.
I made my tiles as BitmapData and added to sprite. I want to be able to drag and drop them on my scrabble board but not be able to place one tile in a spot where another tile is.
For debugging purposes Ive been just trying to get the individual tiles to respect each other's physics when you drag and drop. The behavior I want is, when dragging, to bump into another tile with that tile "holding its ground" and the dragging tile unable to cross on top of the other tile. Currently the dragged tile just goes on top of other tiles. I've looked at a lot of examples and feel that my issue may be either because my sprite is made with bitmapData or something around the drag event...
function makeTile (tileIndex, tile) {
var bmd = game.add.bitmapData(canvasZoom, canvasZoom);
// draw to the canvas context
bmd.ctx.beginPath();
bmd.ctx.rect(0, 0, canvasZoom, canvasZoom);
bmd.ctx.fillStyle = '#efefef';
bmd.ctx.fill();
bmd.ctx.fillStyle = '#234234';
bmd.ctx.font="20px Georgia";
bmd.ctx.fillText(tile.tileName, 7,23);
// use the bitmap data as the texture for the sprite
var tileSprite = game.make.sprite((tileIndex * canvasZoom) + canvasZoom, canvasZoom, bmd);
game.physics.arcade.enable([tileSprite]);
tileHandGroup.add(tileSprite);
tileSprite.inputEnabled = true;
var bounds = new Phaser.Rectangle(canvasZoom, canvasZoom, spriteWidth * canvasZoom, (spriteHeight * canvasZoom) + (canvasZoom * 2));
tileSprite.input.boundsRect = bounds;
tileSprite.name = 'tileSpriteName' + tileIndex;
tileSprite.input.enableDrag(true);
tileSprite.input.enableSnap(canvasZoom, canvasZoom, true, false);
tileSprite.immovable = true;
tileSprite.body.moves = false;
tileSprite.events.onDragStart.add(onDragStart, this);
tileSprite.events.onDragStop.add(onDragStop, this);
}
function firstTileHand() {
tileHandGroup = game.add.physicsGroup(Phaser.Physics.ARCADE);
game.physics.enable(tileHandGroup, Phaser.Physics.ARCADE);
tileHandGroup.enableBody = true;
tileHandGroup.name = 'tileHandGroup';
for (var i = 0; i < tiles.length; i++)
{
makeTile(i, tiles[i]);
}
}

How to create a shadow pixi.js?

Why are there no shadow? What you need to do to make the filter work? If possible then show me in code how to create a shadow.
var renderer = PIXI.autoDetectRenderer(500, 200, {
transparent: true
});
document.getElementsByTagName('body')[0].appendChild(renderer.view);
var stage = new PIXI.Container();
function update(){
renderer.render(stage);
window.requestAnimationFrame(update);
}
update();
var graphics = new PIXI.Graphics();
graphics.beginFill(0x848484);
graphics.drawPolygon([0,0,100,0,100,100,0,100,0,0]);
graphics.endFill();
var dropShadowFilter = new PIXI.filters.DropShadowFilter();
dropShadowFilter.alpha = 1;
dropShadowFilter.blur = 2;
dropShadowFilter.distance = 20;
graphics.filters = [dropShadowFilter];
stage.addChild(graphics);
<script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/3.0.7/pixi.js"></script>
Don't make the renderer transparent. I guess, if the renderer is transparent, then it's texture has alpha = 0 and the shadow is drawn on that. Also, only works for webGL.
var renderer = new PIXI.WebGLRenderer(500, 200);
renderer.backgroundColor = 0xffffff;
document.getElementsByTagName('body')[0].appendChild(renderer.view);
var stage = new PIXI.Container();
function update(){
renderer.render(stage);
window.requestAnimationFrame(update);
}
update();
var graphics = new PIXI.Graphics();
graphics.beginFill(0x8484cc);
graphics.drawPolygon([20,20,120,20,120,120,20,120,20,20]);
graphics.endFill();
var dropShadowFilter = new PIXI.filters.DropShadowFilter();
dropShadowFilter.color = 0x000020;
dropShadowFilter.alpha = 0.2;
dropShadowFilter.blur = 6;
dropShadowFilter.distance = 20;
graphics.filters = [dropShadowFilter];
stage.addChild(graphics);
<script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/3.0.7/pixi.js"></script>

Resources