Three.js: Resize rendering canvas (GPU hungry fragment shader) - javascript

I am running resource hungry fragment shader with three.js. I have setup rendering size to 800 * 600 to keep shader running smooth even on lowend cards.
I am setting my rendering canvas like this:
var canvas1 = document.getElementById('canvas1') ;
renderer = new THREE.WebGLRenderer(canvas1);
renderer.setSize( 800, 600 );
renderer.autoClear = false;
document.body.appendChild( renderer.domElement );
On body element i have
<canvas id='canvas1' style=" position: absolute; left: 0; top: 0; z-index: -10; background-color: #000000; "></canvas>
I am then in css header doing width: 100%; height: 100%;
This does not help much, as Three.js creates new canvas of size 800*600 on top of canvas1.
What is best approach to zoom Three.js rendering canvas to match web browsers window size, without touching rendering size?

renderer = new THREE.WebGLRenderer( { canvas: canvas1 } );
Passes canvas1 to WebGLRenderer as rendering target.
Then remove:
document.body.appendChild( renderer.domElement );
as we already have canvas1 element in our dom.
Three.js documentation is little bit tricky sometimes,
{ canvas: },
to pass parameter.

Related

How do I make the blank areas not scrollable for iOS without hurting the game?

I'm trying to improve my phaser game experience by enabling body-scroll-lock.
Currently, the code from the official example renders like this
where the areas pointed out by the red rectangles are scrollable, which is not good as the player might accidentally touch that area during the game.
I tried to change the config
scale: {
mode: Phaser.Scale.FIT,
parent: 'phaser-example',
autoCenter: Phaser.Scale.CENTER_BOTH,
width: window.innerWidth,
height: window.innerHeight,
},
and I got
where the area pointed out by the red arrow is not scrollable though the game is now a mess.
I also tried the approach in another tutorial.
<style>
html,
body {
overflow: hidden;
}
</style>
<script>
document.body.ontouchend = (e) => {
e.preventDefault();
};
</script>
none of them works.
this make things worse
body {
position: fixed;
}
How do I make the area not scrollable without hurting the game?
I personally would use html and css to solve it, but if it didn't work., here is an alternative solution.
You could use the Phaser.Scale.FITscale-mode and just display the game scene, with the viewport I would keep the gameScene at the right scape/size.
Here the Main Idea (I think it is abit hacky, but should work):
you create a background Scene (you could set a background color or a blur effect like on horiziontal videos)
On top of that Scene you display the actual Scene that contains the game
(depending the size of the Game the width and height would have to be adjusted)
And I would additionally use the css-styles: html, body {padding:0; margin:0;} just to be on the save side, that the canvas covers the whole window.
var config = {
type: Phaser.AUTO,
scale: {
mode: Phaser.Scale.FIT,
parent: 'phaser-example',
autoCenter: Phaser.Scale.CENTER_BOTH,
width: window.innerWidth,
height: window.innerHeight,
},
...
scene: [{
key: 'background',
create: function() {
// Game size
let width = 800;
let height = 600;
// Get The game Scene
let gameScene = this.game.scene.getScene('gameScene');
// Set Zone for the Game-Scene
gameScene.parent = this.add.zone(this.cameras.main.centerX, this.cameras.main.centerY, width, height);
// set the part of the scene that should be displayed
gameScene.cameras.main
.setViewport(gameScene.parent.x - gameScene.parent.width / 2, gameScene.parent.y - gameScene.parent.height / 2, gameScene.parent.width, gameScene.parent.height);
},
},
GameScene
]
};
Info: just mentioning this part because it it not 100% obvious at first: this.cameras.main.centerXand this.cameras.main.centerY would give you the coordinates of center of the scene.

Trouble rendering a 2D SVG in Three.js & WebGL

I have a ThreeJS Scene (below, or here on CodePen) with some objects in it - one is a Mesh object of a cat, one is a cube, and now, I'm trying to render a 2D SVG illustration I made. I want to put the SVG illustration in the scene in between the cat image and the cube, displayed the same way the cat image appears (upright, and 2D).
It has taken me days to figure out how to render my own SVG, I find the documentation and examples on ThreeJs.org for SVGRenderer and SVGLoader extremely cumbersome and hard to pick apply to my own image (I'm a novice). The closest I've come to rendering my SVG is using the code from this SO thread that uses a LegacySVG Loader. Problem is, I'm completely lost on how to render this code onto a canvas versus a DOM, and it appears this LegacySVG Loader was a solution to a bug which makes it extremely hard to find resources.
So, essentially, I have rendered an SVG in an individual CodePen using the above resources and now I am lost on how to render it onto the same scene as my cube and cat image. Is it possible to use LegacySVG to render onto a canvas? Or, is there a simpler way to get my SVG onto the same canvas as the other objects?
let renderer;
let camera;
//let controls;
let scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(54, window.innerWidth / window.innerHeight, 0.1, 1000);
renderer = new THREE.WebGLRenderer({
antialias: true,
canvas: document.getElementById("viewport")
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(new THREE.Color(0xfefefe));
// document.body.appendChild(renderer.domElement);
camera.position.x = 1;
camera.position.y = 1;
camera.position.z = 15;
let light = new THREE.AmbientLight(0xFFFFFF);
scene.add(light);
let gridHelper = new THREE.GridHelper(10, 10);
scene.add(gridHelper);
// example code
const geometry1 = new THREE.BoxGeometry(1, 1, 1);
const material1 = new THREE.MeshStandardMaterial({
color: 0xff0000
});
const topBox = new THREE.Mesh(geometry1, material1);
scene.add(topBox);
var loader = new THREE.TextureLoader();
// Load an image file into a custom material
var material = new THREE.MeshLambertMaterial({
map: loader.load('https://images.unsplash.com/photo-1518791841217-8f162f1e1131?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=2850&q=80')
});
// create a plane geometry for the image with a width of 10
// and a height that preserves the image's aspect ratio
var geometry = new THREE.PlaneGeometry(2, 1.5);
// combine our image geometry and material into a mesh
var mesh = new THREE.Mesh(geometry, material);
// set the position of the image mesh in the x,y,z dimensions
mesh.position.set(0,0,5);
// add the image to the scene
scene.add(mesh);
let animate = function() {
requestAnimationFrame(animate);
//controls.update();
renderer.render(scene, camera);
};
//////////////////
animate();
function updateCamera(ev) {
camera.position.z = 15 - window.scrollY / 250.0;
}
window.addEventListener("scroll", updateCamera);
body {
overflow-x: hidden;
overflow-y: scroll;
padding: 0;
margin: 0;
}
canvas {
position: fixed;
height: 100vh;
}
#threeD {
position: fixed;
margin: 0;
padding: 0;
left: 0;
top: 0;
right: 0;
bottom: 0;
}
.page-wrapper {
padding: 0px;
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 4000vh;
}
#container {
height: 500vh;
position: fixed;
}
<html>
<script src="https://raw.githubusercontent.com/mrdoob/three.js/master/src/loaders/LoadingManager.js"></script>
<script src="https://unpkg.com/three#0.102.1/build/three.min.js"></script>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script src="https://cdn.rawgit.com/mrdoob/three.js/r68/examples/js/loaders/SVGLoader.js"></script>
<script src="https://raw.githubusercontent.com/mrdoob/three.js/master/examples/js/renderers/SVGRenderer.js"></script>
<link rel="stylesheet" type="text/css" href="index1.css" />
<body>
<canvas id="viewport"></canvas>
<div class="page-wrapper" >
<h1> scroll! </h1>
</div>
</body>
<script src="index1.js"></script>
</html>
There are a few things you need to keep in mind.
SVGRenderer does not render the same things as WebGLRenderer.
a. SVGRenderer takes items inside an <svg> element and applies transformations to its internal <path>, <circle>, <rect>, etc, elements. You can see the svg_sandbox example. All SVG elements are 2D, but can give the impression of being 3D when rotated.
b. WebGLRenderer draws onto a <canvas> element, and can render all kinds of true 3D geometry. If you want to draw an SVG in WebGL, you'll need to first convert the SVG file into a geometry that WebGL can understand by using THREE.SVGLoader. You can see how that's done in the webgl_loader_svg example, (the source code is available by clicking on the <> button on the bottom right).
You cannot have <svg> elements co-existing in the same 3D space as WebGL elements in the <canvas>. If you want to add cubes and planes with cat images to the same space, I recommend you use the WebGLRenderer approach.
I noticed in your code snippet that you're using files from many different sources, and all kinds of Three.js revisions. Some files are r102.1, some are r68, and some are the latest, which is r113. You should stick to one revision to avoid conflicts when trying to get older files to work with newer ones. For example:
https://raw.githubusercontent.com/mrdoob/three.js/r113/build/three.min.js
https://raw.githubusercontent.com/mrdoob/three.js/r113/examples/js/loaders/SVGLoader.js

2D Canvas (behind a 3D Canvas) not drawing images

I'm currently exploring with Three.js, and working on a small project of mine.
The project consists on having a canvas focused on 3D models and animations, and another one behind, which handles the simpler 2D work.
I've set up the 3D canvas properly, so it's background is transparent, and I can see boxes I draw manually on the 2D canvas, which leads me to assume the setup is right.
The issue I'm having is when it comes to images. I simply cannot get an image to display on the 2D canvas. I've experimented on a separate project, and could draw Images there, no problem. The code is pretty basic, and I actually found it here, but is as follows:
window.onload = function() {
var canvas = document.getElementById('bgcanvas');
var context = canvas.getContext('2d');
var logoText = new Image();
logoText.onload = function() {
context.drawImage(logoText, 69, 50);
};
logoText.src = 'images/logotext.png';
}
#canvas {
position: fixed;
z-index: 0;
}
#bgcanvas {
z-index: -10;
position: fixed;
width: 100vw;
height: 100vh;
}
<div id="fixedContainer">
<canvas id="bgcanvas"></canvas>
<canvas id="canvas"></canvas>
</div>
What's going on that I'm unaware of?
Massive thanks in advance!
UPDATE EDIT: The issue was that I had an image on which the top left corner was transparent, and didn't know the image would stretch. user3412847's comment helped me figure it out
Specifying image width and height is a good habit to get into. Use this syntax: context.drawImage(image, x, y, width, height).
Hope this helps.
I'm guessing you don't have an image at that path; It works fine for me with a valid image (eg: http://lorempixel.com/100/100):
window.onload = function() {
var canvas = document.getElementById('bgcanvas');
var context = canvas.getContext('2d');
var logoText = new Image();
logoText.onload = function() {
context.drawImage(logoText, 69, 50);
};
logoText.src = 'http://lorempixel.com/100/100';
}
#canvas {
position: fixed;
z-index: 0;
}
#bgcanvas {
z-index: -10;
position: fixed;
width: 100vw;
height: 100vh;
}
<div id="fixedContainer">
<canvas id="bgcanvas"></canvas>
<canvas id="canvas"></canvas>
</div>

How do I get pixi to expand my canvas and zoom in?

I'm making a game that uses pixi and it renders on a canvas that's 640x480 pixels. As you can imagine, this is very small when viewed on a PC. I'd like to accomplish this:
I want to increase the size of the canvas so it fills up the whole screen
I want to zoom in on the content so that it fills up as much as possible without changing its aspect ratio
I'd like to center the canvas if there's left over space from the previous step
When I google for how to do this in pixi, I can find each of these individually. But I'd like to have the information on how to do this all in one place and on stackoverflow, because you usually want to do all of these things together.
I modified the source code in this example made by the creator: http://www.goodboydigital.com/pixi-js-tutorial-getting-started/ (source download)
Here's what I came up with:
<!DOCTYPE HTML>
<html>
<head>
<title>pixi.js example 1</title>
<style>
body {
margin: 0;
padding: 0;
background-color: #000000;
}
</style>
<script src="pixi.js"></script>
</head>
<body>
<script>
// create an new instance of a pixi stage
var stage = new PIXI.Stage(0x66FF99);
// create a renderer instance
var renderer = PIXI.autoDetectRenderer(400, 300);
renderer.resize(800, 600);
// add the renderer view element to the DOM
document.body.appendChild(renderer.view);
requestAnimFrame( animate );
// create a texture from an image path
var texture = PIXI.Texture.fromImage("bunny.png");
// create a new Sprite using the texture
var bunny = new PIXI.Sprite(texture);
// center the sprites anchor point
bunny.anchor.x = 0.5;
bunny.anchor.y = 0.5;
// move the sprite t the center of the screen
bunny.position.x = 200;
bunny.position.y = 150;
var container = new PIXI.DisplayObjectContainer();
container.scale.x = 2;
container.scale.y = 2;
container.addChild(bunny);
stage.addChild(container);
function animate() {
requestAnimFrame( animate );
// just for fun, lets rotate mr rabbit a little
bunny.rotation += 0.1;
// render the stage
renderer.render(stage);
}
</script>
</body>
</html>
Now the one thing I didn't do is center it. I see two potential ways to do this. I could use CSS to center the canvas (what I'll probably use), or I could do this in code by adding another outer display object to the stage that centers container.

Pixi.js sprite not loading

<!DOCTYPE HTML>
<html>
<head>
<title>Test</title>
<style>
body {
margin: 0;
padding: 0;
background-color: #000000;
overflow: hidden;
}
</style>
<script src="http://www.goodboydigital.com/pixijs/examples/1/pixi.js"></script>
</head>
<body>
<script>
// create an new instance of a pixi stage
var stage = new PIXI.Stage(0x66FF99);
// create a renderer instance
var renderer = PIXI.autoDetectRenderer(window.innerWidth, window.innerHeight);
// add the renderer view element to the DOM
document.body.appendChild(renderer.view);
requestAnimFrame( animate );
// create a texture from an image path
var texture = PIXI.Texture.fromImage("https://dl.dropboxusercontent.com/s/en13743nxusaozy/player.PNG?dl=1&token_hash=AAFVxLm8fEjk3xxPad-kAZ98LJqLoZpdFy9fQtGrIfXL-A");
// create a new Sprite using the texture
var player = new PIXI.Sprite(texture);
// center the sprites anchor point
player.anchor.x = 0.5;
player.anchor.y = 0.5;
// move the sprite t the center of the screen
player.position.x = 200;
player.position.y = 150;
stage.addChild(player);
function animate() {
requestAnimFrame( animate );
//rotate player
player.rotation += 0.1;
// render the stage
renderer.render(stage);
}
</script>
</body>
</html>
This is my code (from the pixijs example, Loaiding the bunny), for some reason I can't seem to get the sprite to load... Can someone take a look at the code and help?
When I put in the right link (the stage rendering turns black). When I put in the wrong link to the sprite, then the stage renders fine but there is no sprite.
var texture = PIXI.Texture.fromImage("https://dl.dropboxusercontent.com/s....");
With the above code, a cross domain request is created for the Sprite texture to load. This is usually not allowed (as in Dropbox case).
In order to see the sprite you will have to copy the file to the local web server or allow Cross domain requests on the other server (https://developer.mozilla.org/en-US/docs/HTTP/Access_control_CORS)
//local image instead of cross domain
var texture = PIXI.Texture.fromImage("img/player.PNG");

Categories

Resources