THREE.JS canvas not responsive after landscape mode - javascript

my three.js canvas is not responsive on ios
when I go to landscape mode on iPhone 12 the canvas is not responsive. it becomes small an squarish, and when I go back to portrait mode it stays in this new size (small square)
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75,window.innerWidth/window.innerHeight,0.01,1000);
var clock = new THREE.Clock();
var renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
window.addEventListener ('resize', ()=> {
renderer.setSize(window.innerWidth,window.innerHeight);
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
})
var rmapped = 0;
const controls = new OrbitControls( camera, renderer.domElement );
var loader = new GLTFLoader();
scene.background = new THREE.Color(0x000000)
const cube = new THREE.BoxGeometry( 1,1,1 );
var light1 = new THREE.PointLight( 0xff0040, 2, 50 );
light1.add( new THREE.Mesh( cube, new THREE.MeshBasicMaterial( { color: 0xff0040 } ) ) );
scene.add( light1 );
var light2 = new THREE.PointLight( 0x0040ff, 2, 50 );
light2.add( new THREE.Mesh( cube, new THREE.MeshBasicMaterial( { color: 0x0040ff } ) ) );
light2.position.x=3;
var light2Obj = new THREE.Object3D();
light2Obj.add(light2);
scene.add(light2Obj);
camera.position.set(0, 5, 10);
function animate(){
requestAnimationFrame(animate);
light1.rotateY(0.005);
light2Obj.rotateY(0.009);
renderer.render( scene, camera );
function render() {
renderer.render( scene, camera );
}
}
animate()
Any idea of what the problem is ? seems to work on Android.
read somewhere that resizeobserver api could be a solution but i cannot figure it out
this is what it looks like
lanscape mode:
https://i.stack.imgur.com/LXnnz.jpg
back to portrait mode
https://i.stack.imgur.com/QjkBR.jpg

Related

How to center three js object into DIV:

I cannot center three js object into DIV
Here is my code:
import * as THREE from 'https://cdn.skypack.dev/pin/three#v0.128.0-iDyvDZdRCoyR9DXa2rWg/mode=imports,min/optimized/three.js';
const container = document.getElementById("canvas");
// const selected = document.querySelector("#canvas");
// document.body.appendChild(container);
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( container.offsetWidth, container.offsetWidth );
// renderer.setSize( item.clientWidth, item.clientHeight );
container.appendChild( renderer.domElement );
const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
const cube = new THREE.Mesh( geometry, material );
scene.add( cube );
camera.position.z = 5;
const animate = function () {
requestAnimationFrame( animate );
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render( scene, camera );
};
animate();
And that's how the problem looks:
Object just going outside the DIV:
I dont know why it happens. I'm trying to fix this a couple of days and try a lot of ways and it still does not work. Probably I don't understand something and need your help...
I guess i solved the problem. I just delete padding of the #canvas in css and its now work as expected.

Problems getting camera navigation working in threejs

I'm trying to work out camera navigation functionality in threejs, using THREE.OrbitControls. Even though I'm following a guide, I just can't seem to get it working.
The link to my fiddle code is: https://jsfiddle.net/Matty1/uc671jbL/18/
It's on line 18/19 of the javascript:
const controls = new THREE.OrbitControls( camera, renderer.domElement );
controls.update();
Any advice would be appreciated.
You have included OrbitControls from a relative path in your fiddle. Try it like so:
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x19d7f8);
const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
camera.position.set(0,0,5);
const renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
window.addEventListener('resize', function(){
var width = window.innerWidth;
var height = window.innerHeight;
renderer.setSize(width, height);
camera.aspect = width/height;
camera.updateProjectionMatrix;
} )
const controls = new THREE.OrbitControls( camera, renderer.domElement );
const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
const cube = new THREE.Mesh( geometry, material );
scene.add( cube );
function animate() {
requestAnimationFrame( animate );
renderer.render( scene, camera );
}
animate();
body {
margin: 0;
}
<script src="https://cdn.jsdelivr.net/npm/three#0.124/build/three.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three#0.124/examples/js/controls/OrbitControls.js"></script>

Three.JS Panorama Doesn't Resize Properly on Mobile

So I'm currently working with Three.Js and it's device orientation library to create a panorama that one can navigate by moving their phone. The issue I'm having is that this is what I want it to look like:
Proper Panorama
and when the page loads for the first time, it does this properly. However, when I refresh the page it turns to this:
Panorama on Refresh
My friend looked at it and said that it has something to do with the camera not resizing properly for mobile. But I've looked and can't find anything that goes in depth about what to do for the Camera Resize for mobile. Here's my code:
<script src="../build/three.min.js"></script>
<script src="js/controls/DeviceOrientationControls.js"></script>
<script src="js/renderers/THREEx.WindowResize.js"></script>
(function() {
"use strict"
window.addEventListener('load', function() {
var container, camera, scene, renderer, controls, geometry, mesh;
var animate = function(){
window.requestAnimationFrame( animate );
controls.update();
renderer.render(scene, camera);
};
container = document.getElementById( 'container' );
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 1100);
controls = new THREE.DeviceOrientationControls( camera );
scene = new THREE.Scene();
var geometry = new THREE.SphereGeometry( 500, 16, 8 );
geometry.applyMatrix( new THREE.Matrix4().makeScale( -1, 1, 1 ) );
var material = new THREE.MeshBasicMaterial( {
map: THREE.ImageUtils.loadTexture( 'textures/2294472375_24a3b8ef46_o.jpg' )
} );
var mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
var geometry = new THREE.BoxGeometry( 100, 100, 100, 4, 4, 4 );
var material = new THREE.MeshBasicMaterial( { color: 0xff00ff, side: THREE.BackSide, wireframe: true } );
var mesh = new THREE.Mesh( geometry, material );
// scene.add( mesh );
renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.domElement.style.position = 'absolute';
renderer.domElement.style.top = 0;
container.appendChild(renderer.domElement);
Specific Camera Stuff
window.addEventListener('resize', function() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}, false);
THREEx.WindowResize(renderer, camera);
controls.connect();
animate();
}, false);
})();
Any ideas of how to make it so that it resizes properly no matter what?
Try to set the pixel ratio when you are creating the renderer:
renderer.setPixelRatio(window.devicePixelRatio);

Cannot read property 'uniform' of undef when rendering mesh with multiple materials

I have exported a 3d model from blender to a three.js file. It has 2 materials applied to different portions of it. It has a lot of vertices and uv coords so i wont post the code here. I can see that it indeed has 2 materials though, so im pretty sure my error is in my three.js code. It does have 0 bones, morph targets, and colors though. I dont know if those are important for my application or not, so my error might be there.
Here is what I have so far:
var camera, scene1, scene2, raycaster, renderer, staticMesh , loader;
var highlighted, standard;
var mouse = new THREE.Vector2(), INTERSECTED;
init();
animate();
function init() {
standard = new THREE.MeshLambertMaterial( { color: 0x9999ff } );
highlighted = new THREE.MeshLambertMaterial( { color: 0xff0000 } )
camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 10000 );
camera.position.z = 15;
scene1 = new THREE.Scene();
scene2 = new THREE.Scene();
loader = new THREE.JSONLoader();
loader.load( "abs.json", function( geometry ) {
var mesh = new THREE.Mesh( geometry, new THREE.MeshLambertMaterial( { color: 0x9999ff } ) );
//mesh.scale.set( 10, 10, 10 );
mesh.position.y = -6;
mesh.position.x = 0;
scene2.add( mesh );
} );
loader.load( "bodyTest.json", function(geometry, material) {
material[0] = new THREE.Mesh( geometry, new THREE.MeshLambertMaterial( { color: 0x9999ff } ) );
material[1] = new THREE.Mesh( geometry, new THREE.MeshLambertMaterial( { color: 0x9999ff } ) );
var materials = new THREE.MeshFaceMaterial(material);
staticMesh = new THREE.Mesh( geometry, materials );
scene1.add( staticMesh );
} );
var directionalLight = new THREE.DirectionalLight(0xffffff);
directionalLight.position.set(-1, -1, -1).normalize();
scene1.add(directionalLight);
directionalLight = new THREE.DirectionalLight(0xffffff);
directionalLight.position.set(1, 1, 1).normalize();
scene1.add(directionalLight);
directionalLight = new THREE.DirectionalLight(0xffffff, .5);
directionalLight.position.set(1, 0, 0).normalize();
scene1.add(directionalLight);
directionalLight = new THREE.DirectionalLight(0xffffff, .5);
directionalLight.position.set(-1, 0, 0).normalize();
scene1.add(directionalLight);
raycaster = new THREE.Raycaster();
renderer = new THREE.WebGLRenderer({ antialiasing: true});
renderer.setClearColor( 0xffffff );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.sortObjects = false;
document.body.appendChild( renderer.domElement );
document.addEventListener( 'mousemove', onDocumentMouseMove, false );
window.addEventListener( 'resize', onWindowResize, false );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function onDocumentMouseMove( event ) {
event.preventDefault();
mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
}
function animate() {
requestAnimationFrame( animate );
scene1.rotation.y += 0.007;
scene2.rotation.y += 0.007;
/*
var vector = new THREE.Vector3( mouse.x, mouse.y, 1 ).unproject( camera );
raycaster.set( camera.position, vector.sub( camera.position ).normalize() );
var intersects = raycaster.intersectObjects( scene2.children );
if ( intersects.length > 0 ) {
if ( INTERSECTED != intersects[ 0 ].object ) {
if(staticMesh) staticMesh.material.materials[1] = staticMesh.currentMat;
INTERSECTED = intersects[ 0 ].object;
staticMesh.currentMat = staticMesh.material.materials[1]
staticMesh.material.materials[1] = highlighted;
}
} else {
if(staticMesh) staticMesh.material.materials[1] = staticMesh.currentMat;
INTERSECTED = null;
}
*/
renderer.render( scene2, camera );
renderer.render( scene1, camera );
}
As you can see I already commented out portions that I thought the error might be coming from. I have also tried running it with renderer.render( scene1, camera ); commented out and it had no errors.
I don't fully understand how this fixed it, but I found this in a different example and it ended up working. standard is a lambert material i have defined prior.
loader.load( "bodyTest.json", function(geometry) {
var material = [];
material.push( standard );
material.push( standard );
var materials = new THREE.MeshFaceMaterial(material);
staticMesh = new THREE.Mesh( geometry, materials );
scene1.add( staticMesh );
} );
I'd still appreciate an explanation if someone knows what my problem was.

Three.js skybox seems broken after rotating camera

js and I'm trying to create a simple skybox based on this demo. Everything seems ok so far except 1 thing when I rotate my camera (I'm using orbitControls.js) and the z value is not the minimum possible then textures act weird and seem broken.
Source:
var camera, scene, renderer, controls, skybox;
var toRadians = function(deg) {
return deg * Math.PI / 180
}
var toDegrees = function(radians) {
return radians * (180 / Math.PI);
}
var init = function() {
// scene
scene = new THREE.Scene();
scene.fog = new THREE.FogExp2( 0xffffff, 0.00010);
// camera
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 20000 );
camera.position.z = 5000;
scene.add( camera );
// skydome
var urlPrefix = "http://three.dev/skybox/textures/";
var urls = [urlPrefix + "px.png", urlPrefix + "nx.png",
urlPrefix + "py.png", urlPrefix + "ny.png",
urlPrefix + "pz.png", urlPrefix + "nz.png"];
var textureCube = THREE.ImageUtils.loadTextureCube( urls );
var shader = THREE.ShaderLib[ "cube" ];
shader.uniforms[ "tCube" ].value = textureCube;
var material = new THREE.ShaderMaterial( {
fragmentShader: shader.fragmentShader,
vertexShader: shader.vertexShader,
uniforms: shader.uniforms,
depthWrite: false,
side: THREE.BackSide
} ),
skybox = new THREE.Mesh( new THREE.BoxGeometry( 10000, 10000, 10000 ), material );
scene.add( skybox );
//var texture = THREE.ImageUtils.loadTexture( 'http://three.dev/skybox/textures/wood.jpg')
//var paintMaterial = new THREE.MeshBasicMaterial({map: textureCube})
// var lightAmb = new THREE.AmbientLight(0x333333);
// lightAmb.position.set( 0,0,0 );
// scene.add(lightAmb);
// var directionalLightTop = new THREE.DirectionalLight( 0xffffff, 1 );
// directionalLightTop.position.set( 0, 0, 0 ).normalize();
// scene.add( directionalLightTop );
// var color = new THREE.Color("rgb(255,0,0)");
// var pointLightRed = new THREE.PointLight(color, 1, 8000);
// pointLightRed.position.set( 0, 0, 0);
// camera.add( pointLightRed );
// renderer
renderer = new THREE.WebGLRenderer( {alpha: true, antialias: true} );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setClearColor( 0xffffff, 1 );
renderer.autoClear = false;
controls = new THREE.OrbitControls( camera, renderer.domElement );
controls.rotateSpeed = 0.5;
controls.minDistance = 500;
controls.maxDistance = 6000;
document.body.appendChild( renderer.domElement );
window.addEventListener( 'resize', onWindowResize, false );
// start rendering
render();
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
render();
}
var update = function() {
}
var render = function() {
update();
controls.update();
requestAnimationFrame( render );
renderer.render(scene, camera);
}
window.onload = function(){
init();
}
You're adding a skybox in the 'main' scene. A better way to accomplish a skydome would be to create a new scene. this will be the 'background' to your 'main' scene. There's also a discussion about skydomes v.s. skyboxes, simply put, a box saves polys, a dome looks better. in this example i'll be using a dome/sphere.
var renderer = new THREE.WebGLRenderer( {alpha: true, antialias: true} );
var mainScene = new THREE.Scene();
var mainCamera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 20000 );
var skydome = {
scene: new THREE.Scene(),
camera: new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 20000 );
};
skydome.material = new THREE.MeshBasicMaterial({color: 0x0F0F0F}) //the material for the skydome, for sake of lazyness i took a MeshBasicMaterial.
skydome.mesh = new THREE.Mesh(new THREE.SphereGeometry(100, 20, 20), skydome.material);
skydome.scene.add(skydome.mesh);
now, during the render function you adjust only the rotation of the skydome camera, not the position.
var render = function(){
requestAnimationFrame( render );
skydome.camera.quaternion = mainCamera.quaternion;
renderer.render(skydome.scene, skydome.camera); //first render the skydome
renderer.render(mainScene, mainCamera);//then render the rest over the skydome
};
renderer.autoclear = false; //otherwise only the main scene will be rendered.

Categories