three.js preserveDrawingBuffer not working on iOS - ios

I am rendering a particle system that leaves trails behind. It's working in every browser except on iOS, both safari and chrome. The particles move but the canvas appears to be cleared on every frame, meaning that only the current particles can be seen instead of the history.
I have preserveDrawingBuffer set to true in the render options, so the canvas should not be cleared.
function setup() {
camera = new THREE.OrthographicCamera( canvasSize.width / - 2, canvasSize.width / 2, canvasSize.height / 2, canvasSize.height / - 2, 0.1, 10000 );
camera.position.set(0, 0, -10);
scene = new THREE.Scene();
var material = new THREE.MeshBasicMaterial({
vertexColors: THREE.VertexColors,
opacity: 0.1,
transparent: true,
linewidth: 1
})
for (var i = 0; i < settings.agents; i++) agents.push(new Agent(i, agentDefaults, canvasSize, limits, geometry, colorMixer))
var line = new THREE.LineSegments(geometry, material);
scene.add(line);
renderer = new THREE.WebGLRenderer({
preserveDrawingBuffer: true,
antialias: true,
alpha: true,
});
renderer.setClearColor(0xffffff, 0)
renderer.setPixelRatio(window.devicePixelRatio)
renderer.setSize(canvasSize.width, canvasSize.height)
renderer.sortObjects = false
renderer.autoClearColor = false
camera.lookAt(scene.position)
settings.container.appendChild(renderer.domElement);
}
function draw() {
for (var i = 0; i < agents.length; i++) {
agents[i].update()
}
geometry.verticesNeedUpdate = true;
geometry.colorsNeedUpdate = true
renderer.render(scene, camera)
requestAnimationFrame(draw)
}
Am I missing a particular command specific to iOS?

The problem is in the renderer, iOS doesn't support anti-aliasing. For some reason this breaks the preserveDrawingBuffer option. So remove antialias: true from your render setup.
renderer = new THREE.WebGLRenderer({
preserveDrawingBuffer: true,
// antialias: true,
alpha: true,
});
https://github.com/mrdoob/three.js/issues/7655

Related

Custom Hit Detection on Konva Group

I'm attempting to expand the click area of a group of shapes, but there appears to be no hitFunc property on groups.
var patternControl = new Konva.Group();
patternControl.hitFunc(function(context) {
context.beginPath();
context.arc(0, 0, outerRadius + patternWidth, 0, Math.PI * 2, true);
context.fillStrokeShape(this);
});
Is there any way to do apply custom hit functions to a group?
Only shapes can be used for hit detection. As a workaround, you can disable hits for all shapes with shape.listeting(false) and then add a "fake" shape to the group that will be used as a hit area:
var patternControl = new Konva.Group();
var hitShape = new Konva.Shape({
// make it transparent, so it is not visible
fill: 'rgba(0,0,0,0)',
hitFunc: (context, shape) => {
context.beginPath();
context.arc(0, 0, outerRadius + patternWidth, 0, Math.PI * 2, true);
context.fillStrokeShape(shape);
}
});
patternControl.add(hitShape);

AnchroPoint x:0, y:0 not working with equation

I am trying to build a Breakout game where I set the bricks exactly how I want them for each level using 1 SKSpriteNode. It all works, as in they spawn but way off screen to the bottom left. I am using the following line right at the start of didMove(to view: SKView):
scene?.anchorPoint = CGPoint(x: 0.0, y: 0.0)
And the code I use for spawning the bricks is:
//MARK: Brick Layout Config
let widthOfTiles = 7
let heightOfTiles = 3
let widthPoints = 50
let heightPoints = 20
// Different tile arrangements (e.g. 7 tiles wide, 3 high, 7*3 = 21 total tiles)
var brickArray = [false, true, false, true, false, true, false,
false, true, true, true, false, true, false,
false, true, false, true, false, true, false] // Says 'HI' using tiles
override func didMove(to view: SKView) {
//MARK: Brick
for tile in 0..<brickArray.count {
if brickArray[tile] == true {
let brick = SKSpriteNode(imageNamed: "red_brick")
brick.position = CGPoint(x: (tile % widthOfTiles) * (widthPoints) - (widthOfTiles / 2 * (widthPoints)),
y: ((tile - (tile % widthOfTiles)) / widthOfTiles) * (heightPoints) - (heightOfTiles / 2 * (heightPoints)))
brick.size = CGSize(width: widthPoints, height: heightPoints)
brick.physicsBody = SKPhysicsBody(rectangleOf: brick.frame.size)
brick.physicsBody?.friction = 0
brick.physicsBody?.allowsRotation = false
brick.physicsBody?.friction = 0
brick.physicsBody?.isDynamic = false
brick.physicsBody?.categoryBitMask = brickCategory
self.addChild(brick)
}
}
}
I cannot for the life of me get this to be in the center of the scene. Maybe someone can help me figure this out. Maths is a bad weak point of mine and while I think I got the equation right for the spawning, the position is way off.
If I am missing something that you need to see please let me know.
Unless you need an animation that depends on the anchor point I would not set it and leave it at its default value or it will change the visual representation of the position of the layer.

Drawing Text to the canvas using three.js

To start, I am not the most advanced javascript developer. I have only now started to undertake a more serious study of the subject.
So one of my first forays in this subject is to draw some text to the canvas using the three.js library.But for the life of me, I can't get this sucker to work. I have looked on google and even through the three.js documentation. When I inspect the page in chrome, the page doesn't show any errors either. Here is my code for reference:
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75, window.innerWidth /
window.innerHeight, 0.1, 1000);
var renderer = new THREE.WebGLRenderer({ alpha: true });
renderer.setClearColor(0xdddddd);
var spotlight = new THREE.SpotLight(0xffffff,);
spotlight.castShadow = true;
spotlight.position.set(30,60,60);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var loader = new THREE.FontLoader();
loader.load( 'fonts/helvetiker_regular.typeface.json', function ( font ) {
var textGeo = new THREE.TextGeometry( 'Hello three.js!', {
font: font,
size: 80,
height: 5,
curveSegments: 12,
bevelEnabled: true,
bevelThickness: 10,
bevelSize: 8,
bevelSegments: 5
} );
var color = new THREE.Color();
color.setRGB(255, 250, 250);
textGeo.computeBoundingBox();
textGeo.computeVertexNormals();
var textMaterial = new THREE.MeshBasicMaterial({ color: color });
var mesh = new THREE.Mesh(textGeo, textMaterial);
mesh.position.x = textGeo.boundingBox.max.x / 2;
mesh.position.y = textGeo.boundingBox.max.y / 2;
mesh.castShadow = true;
scene.add(mesh);
} );
var render = function (){
requestAnimationFrame(render);
renderer.render(scene, camera);
}
camera.lookAt(scene.position);
render();
Also, for some background if it's needed, I am running this in debug mode in an asp.net application.
Thanks everyone.
I had my camera directly on the scene, so I couldn't see anything. Thanks prisoner for comment.

Three.js: Why does the size of CanvasRenderer affect performance on iPhone5s' browsers(chrome, safari)

I am trying to use Three.js to make some graphics. At the beginning stage, I found out: till now on ios7.0, I cannot use WebGL. So instead, I use CanvasRenderer. However, it seems that the size of CanvasRenderer will seriously affect the performance. Could someone give share some thoughts? Or provide a good resolution for CanvasRenderer on ios devices?
Note: I displayed the resolution of chrome on the iPhone5s: 980x1544.
If I set resolution to 640*1024, it works fine.
If I use smaller resolution: (window.innerWidth/2 , window.innerHeight/2), that works fine as well.
However, if I use full width and full height, the cube will not display. Even if I set height to (640,1025), the spinning cube will be really slow.
My question is : how does the size of CanvasRenderer impact on the performance? (Specifically for iPhone5 browsers in this case)
The following is the simple code I wrote to render a cube:
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(40, window.innerWidth/window.innerHeight, 0.1, 1000);
document.getElementById("debug").innerHTML = window.innerWidth + " " + window.innerHeight;
renderer = webglAvailable() ? new THREE.WebGLRenderer() : new THREE.CanvasRenderer();
renderer.setSize(640, 1024);
document.getElementById("body").appendChild(renderer.domElement);
var geometry = new THREE.BoxGeometry(1,1,1);
var material = new THREE.MeshBasicMaterial({color: 0x00ff00});
var cube = new THREE.Mesh(geometry, material);
scene.add(cube);
camera.position.z = 10;
var render = function () {
requestAnimationFrame(render);
cube.rotation.x += 0.1;
cube.rotation.y += 0.1;
renderer.render(scene, camera);
};
render();
For reference, you could try to use your iPhone to load these two pages. You can easily see the performance difference.
Resolution 640*1024: http://shawnfandev.com/Testing/workingResolution/Cube.php
Resolution 640*1200: http://shawnfandev.com/Testing/higherResolution/Cube.php
Any thoughts is appreciated!
I made a simple simulation that can change resolution and calculates FPS.
The simulation renders 100 cubes to lower FPS to make it easy to compare.
FPS monitor is provided by stats.js.
This is jsfiddle.
HTML:
<div id="renderer"></div>
<div id="input_fileds">
width: <input type="text" id="width" value="200">
height: <input type="text" id="height" value="200">
</div>
javascript:
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(40, 1, 0.1, 1000);
var renderer = new THREE.CanvasRenderer();
renderer.setSize(200, 200);
container = document.getElementById('renderer');
document.body.appendChild(container);
container.appendChild(renderer.domElement);
stats = new Stats();
stats.domElement.style.position = 'absolute';
stats.domElement.style.top = '0px';
container.appendChild(stats.domElement);
var geometry = new THREE.BoxGeometry(.3, .3, .3);
var material = new THREE.MeshBasicMaterial({color: 0x00ff00});
var cubes = [];
for (var i = 0; i < 100; i++) {
var cube = new THREE.Mesh(geometry, material);
cube.position.x = Math.random() * 6 - 3;
cube.position.y = Math.random() * 6 - 3;
cubes.push(cube);
scene.add(cube);
}
camera.position.z = 10;
var render = function() {
cubes.forEach(function(cube) {
cube.rotation.x += 0.1;
cube.rotation.y += 0.1;
});
stats.update();
renderer.render(scene, camera);
setTimeout(render, 1000 / 60);
};
render();
var width_input = document.getElementById('width');
var height_input = document.getElementById('height');
width_input.addEventListener("keyup", function() {
resize();
});
height_input.addEventListener("keyup", function() {
resize();
});
function resize() {
camera.aspect = width_input.value / height_input.value;
camera.updateProjectionMatrix();
renderer.setSize(width_input.value, height_input.value);
}
css:
#renderer{
margin-top:50px;
}
#renderer canvas{
background-color: #000000;
}
#input_fileds{
position:fixed !important;
top:0px;
padding-left:100px;
}
#stats{
position:fixed !important;
}
Result on my iPhone5s
19 FPS on 600x600
19 FPS on 800x800
19 FPS on 1000x1000
19 FPS on 1024x1024
5 FPS on 1025x1025
FPS and resolution are not directly proportional to each other, but when resolution is greater than some point, FPS falls sharply.

In Three.js, lights don't work

I've been fooling around with Three.js for a while, and I don't seem to be able to get any sort of lights to work. The scene renders normally with the 0xFFFFFF ambient lighting, but adding lights doesn't have any effect. I've copied the code directly from the examples and the lights are listed in the children of scene, only not showing up...
var camera;
var scene;
var renderer;
$(document).ready(function() {
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 10000);
camera.position.z = 600;
scene = new THREE.Scene();
scene.add(new THREE.PointLight(0xFF0000, 3.0, 1000));
renderer = new THREE.WebGLRenderer();
//renderer = new THREE.CanvasRenderer();
renderer.domElement.id = "canvas";
renderer.setSize(window.innerWidth, window.innerHeight);
$(window).resize(function() {
renderer.setSize(window.innerWidth, window.innerHeight);
});
$("#container").get(0).appendChild(renderer.domElement);
function Animate() {
requestAnimationFrame(Animate);
renderer.render(scene, camera);
}
Animate();
});
Your code does not give much to work with, but one thing to check is that your materials support lights. That means you should be using MeshLambertMaterial or MeshPhongMaterial. Also note that if you are using a custom ShaderMaterial, it does not magically get scene lighting.

Resources