Texturing a sphere with Three.js does'nt work on smartphones - javascript

I have some troubles using Three.js. I want to apply a texture on a sphere (an image). My code works without any problem... until I try it on a smartphone. I try to look for the bug with Firefox and its remote debugger, but I did not find the issue. Here is my code :
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Test</title>
<meta name="viewport" content="initial-scale=1.0" />
<script src="./three.min.js"></script>
<script src="./sphere.js"></script>
<style>
html, body, #container {
margin: 0;
overflow: hidden;
}
</style>
</head>
<body>
<div id="container" style="width: 300px; height: 200px;"></div>
<script>
init();
</script>
</body>
</html>
and :
var renderer, scene, camera, mesh;
function init() {
var container = document.getElementById('container');
var width = container.offsetWidth;
var height = container.offsetHeight;
renderer = new THREE.WebGLRenderer();
renderer.setSize(width, height);
container.appendChild(renderer.domElement);
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(90, width/height, 1, 1000);
camera.position.set(0, 0, 300);
scene.add(camera);
var geometry = new THREE.SphereGeometry(200, 16, 16);
var texture = new THREE.Texture();
var loader = new THREE.ImageLoader();
var f = function(img) {
texture.needsUpdate = true;
texture.image = img;
var material = new THREE.MeshBasicMaterial({map: texture, overdraw: true});
mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
render();
animate();
}
loader.load('sphere.jpg', f);
}
function animate() {
requestAnimationFrame(animate);
mesh.rotation.y += 0.003;
render();
}
function render() {
renderer.render(scene, camera);
}
What do I do wrong?
If you want to see the code in action, you can go here. Note that the problem is here with both WebGLRenderer and CanvasRenderer.

As a repost: The problem is solved by using power of two texture sizes.

Related

Three.js Geometry isn't showing in browser, but the scene is

was following a tutorial and got the whole scene working in the body tag, then I tried moving it inside a div, and now only the scene will render. I'm not getting any errors, and I've console logged everything to make sure it is available to access. But I can't see why I'm nothing displayed.
// console.log ("Java Script is working!")
// get div for 3D area
const container = document.querySelector('#container')
// console.log (container)
var scene = new THREE.Scene()
var camera = new THREE.PerspectiveCamera(
75,
container.innerWidth / container.innerHeight,
0.1,
1000
)
camera.position.z = 3
var renderer = new THREE.WebGLRenderer({
antialias: true
})
renderer.setClearColor('#0D1033')
renderer.setSize(container.innerWidth, container.innerHeight)
container.appendChild(renderer.domElement)
container.addEventListener('resize', () => {
renderer.setSize(container.innerWidth, container.innerHeight)
camera.aspect = container.innerWidth / container.innerHeight
camera.updateProjectionMatrix()
})
var geometry = new THREE.BoxGeometry(10, 1, 1)
var material = new THREE.MeshLambertMaterial({
color: 0x90e9f9,
side: THREE.DoubleSide
})
var mesh = new THREE.Mesh(geometry, material)
scene.add(mesh)
var light = new THREE.PointLight(0xffffff, 5, 500)
light.position.set(10, 0, 25)
scene.add(light)
var render = function() {
requestAnimationFrame(render)
renderer.render(scene, camera)
}
console.log(mesh)
console.log(camera)
render()
* {
box-sizing: border-box;
}
body {
padding: 0;
margin: 0;
height: 100vh;
}
canvas {
display: block;
height: 100%;
width: 100%;
}
#container {
background-color: black;
height: 100vh;
}
<!DOCTYPE html>
<body>
<div id="container">
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/102/three.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.1.2/TweenMax.min.js"></script>
<script src="main.js"></script>
</body>
</html>
I'm trying to get this working first so I know this can work before I move it into my main project, where I'm trying to have a 3d space inside a div on the website, but not take up the full page
You can only use innerWidth and innerHeight on the window object. Use clientWidth and clientHeight instead:
const container = document.querySelector('#container')
const scene = new THREE.Scene()
const camera = new THREE.PerspectiveCamera(
75,
container.clientWidth / container.clientHeight,
0.1,
1000
)
camera.position.z = 3
const renderer = new THREE.WebGLRenderer({
antialias: true
})
renderer.setClearColor('#0D1033')
renderer.setSize(container.clientWidth, container.clientHeight)
container.appendChild(renderer.domElement)
container.addEventListener('resize', () => {
renderer.setSize(container.clientWidth, container.clientHeight)
camera.aspect = container.clientWidth / container.clientHeight
camera.updateProjectionMatrix()
})
const geometry = new THREE.BoxGeometry(10, 1, 1)
const material = new THREE.MeshLambertMaterial({
color: 0x90e9f9,
side: THREE.DoubleSide
})
const mesh = new THREE.Mesh(geometry, material)
scene.add(mesh)
const light = new THREE.PointLight(0xffffff, 5, 500)
light.position.set(10, 0, 25)
scene.add(light)
const render = function() {
requestAnimationFrame(render)
renderer.render(scene, camera)
}
render()
* {
box-sizing: border-box;
}
body {
padding: 0;
margin: 0;
height: 100vh;
}
canvas {
display: block;
height: 100%;
width: 100%;
}
#container {
background-color: black;
height: 100vh;
}
<script src="https://cdn.jsdelivr.net/npm/three#0.133.1/build/three.min.js"></script>
<div id="container">
</div>

Cannot set a texture to box (html5 / js / babylon.js)

I'm trying out Babylon.js. I want to set my floor texture but it doesn't work. I get the following error:
"Uncaught TypeError: _this.getScene is not a function" (for google search)
I really don't get this, the youtube tutorial made it seem so easy.
Source code:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<style>
#canvas {
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script src="https://cdn.babylonjs.com/babylon.max.js"></script>
<script>
window.addEventListener('DOMContentLoaded', function () {
var canvas = document.getElementById('canvas');
var engine = new BABYLON.Engine(canvas, true);
var createScene = function () {
var scene = new BABYLON.Scene(engine);
scene.clearColor = new BABYLON.Color3.White();
var floor = BABYLON.MeshBuilder.CreateBox("floor", { height: 25, width: 800, depth: 900 }, scene);
floor.position.y = -162.5;
floor.position.x = 100;
floor.position.z = 400;
var camera = new BABYLON.ArcRotateCamera(
'camera1',
BABYLON.Tools.ToRadians(45),
BABYLON.Tools.ToRadians(45),
1000.0,
new BABYLON.Vector3(0, 50, 400),
scene);
camera.attachControl(canvas, true);
var light = new BABYLON.PointLight("pointlight", new BABYLON.Vector3(800, 700, 1000), scene);
light.diffuse = new BABYLON.Color3(1, 1, 1);
var floormaterial = new BABYLON.StandardMaterial("floormaterial", scene);
floormaterial.diffuseTexture = BABYLON.Texture("floor.png", scene);
floor.material = floormaterial;
return scene;
};
var scene = createScene();
engine.runRenderLoop(function () {
scene.render();
});
});
</script>
</body>
</html>
If I remove the "floormaterial.diffuseTexture = BABYLON.Texture("floor.png", scene);" line everything works perfectly.
you are missing the new before the texture. the line should be:
floormaterial.diffuseTexture = new BABYLON.Texture("floor.png", scene);

How to center the three js canvas?

I have this really weird (possibly intended?) bug with my three js canvas.
I want to have it not fill the complete page and center the canvas inside a div.
As you can see in the code below, the canvas is inside the div. I even added some test headings to make sure I'm not going crazy here, but the canvas seems to move itself outside the div and I have no idea how to fix this.
<head>
<meta charset=utf-8>
<title>My first three.js app</title>
<style>
body { margin: 0; }
#test {
width: 100px;
height:100px;
margin: 0px auto;
border: 1px solid red;
}
</style>
<style type="text/css" src="css/main.css"></style>
</head>
<body>
<div id="test">
<h1>test1</h1>
<canvas id="canvasID"></canvas>
<h2>test2</h2>
</div>
<script src="https://github.com/mrdoob/three.js/blob/master/examples/js/Detector.js"></script>
<script src="three.js-master/build/three.js"></script>
<script>
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
var canvas = document.getElementById("canvasID");
var renderer = new THREE.WebGLRenderer({ canvas: canvas });
renderer.setSize( window.innerWidth*0.9, window.innerHeight*0.9 );
document.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 = 5;
function render() {
requestAnimationFrame( render );
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render( scene, camera );
}
render();
if (Detector.webgl) {
init();
animate();
} else {
var warning = Detector.getWebGLErrorMessage();
document.getElementById('container').appendChild(warning);
}
</script>
</body>
As you can see, the canvas has "magically" moved outside of its parent div
In your code you have this line document.body.appendChild( renderer.domElement ); which appends the canvas to the end of the <body> tag. So you are adding the canvas outside of your required div.
You can add your canvas inside that div with a simple javascript selector like:
document.getElementById('test').appendChild( renderer.domElement );
or
document.querySelector('#test').appendChild( renderer.domElement );
That way you are adding the renderer inside the div with the id="test". Let me know if it worked.

three.js webcam as background

I am trying to get the camera video of background of a threejs scene. Below is the code. Currently the background mesh is coming as blank. Not sure why this is happening.
I was following the below link to replace the image with the camera video.
http://jeremy.assenat.free.fr/Lab/threejsbg/
(function () {
var video, videoImage, videoImageContext, videoTexture;
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
window.URL = window.URL || window.webkitURL;
var camvideo = document.getElementById('monitor');
if (!navigator.getUserMedia)
{
document.getElementById('errorMessage').innerHTML =
'Sorry. <code>navigator.getUserMedia()</code> is not available.';
} else {
navigator.getUserMedia({video: true}, gotStream, noStream);
}
function gotStream(stream)
{
if (window.URL)
{
camvideo.src = window.URL.createObjectURL(stream);
} else // Opera
{
camvideo.src = stream;
}
camvideo.onerror = function (e)
{
stream.stop();
};
stream.onended = noStream;
}
function noStream(e)
{
var msg = 'No camera available.';
if (e.code == 1)
{
msg = 'User denied access to use camera.';
}
document.getElementById('errorMessage').textContent = msg;
}
var color = 0x000000;
// Create your main scene
var scene = new THREE.Scene();
// Create your main camera
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
// Create lights
var light = new THREE.PointLight(0xEEEEEE);
light.position.set(20, 0, 20);
scene.add(light);
var lightAmb = new THREE.AmbientLight(0x777777);
scene.add(lightAmb);
// Create your renderer
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
renderer.domElement.className = "mainCanvas"
// Create a cube
var geometry = new THREE.BoxGeometry(1, 1, 1);
var material = new THREE.MeshLambertMaterial({
color: 0xff00ff,
ambient: 0x121212,
emissive: 0x121212
});
var cube = new THREE.Mesh(geometry, material);
scene.add(cube);
// Set up the main camera
camera.position.z = 5;
///////////
// VIDEO //
///////////
video = document.getElementById('monitor');
videoImage = document.getElementById('videoImage');
videoImageContext = videoImage.getContext('2d');
videoImageContext.translate(320, 0);
videoImageContext.scale(-1, 1);
// background color if no video present
videoImageContext.fillStyle = '#000000';
videoImageContext.fillRect(0, 0, videoImage.width, videoImage.height);
videoTexture = new THREE.Texture(videoImage);
videoTexture.minFilter = THREE.LinearFilter;
videoTexture.magFilter = THREE.LinearFilter;
var movieMaterial = new THREE.MeshBasicMaterial({map: videoTexture, overdraw: true, side: THREE.DoubleSide});
// the geometry on which the movie will be displayed;
// movie image will be scaled to fit these dimensions.
var movieGeometry = new THREE.PlaneGeometry(100, 100, 1, 1);
var movieScreen = new THREE.Mesh(movieGeometry, movieMaterial);
movieScreen.position.set(0, 50, 0);
/* scene.add(movieScreen);
camera.position.set(0, 150, 300);
camera.lookAt(movieScreen.position);
*/
// Load the background texture
/* var texture = THREE.ImageUtils.loadTexture('images/checkerboard.jpg');
var backgroundMesh = new THREE.Mesh(
new THREE.PlaneGeometry(2, 2, 0, 0),
new THREE.MeshBasicMaterial({
map: videoTexture
})
);*/
var backgroundMesh = movieScreen;
backgroundMesh.material.depthTest = false;
backgroundMesh.material.depthWrite = false;
// Create your background scene
var backgroundScene = new THREE.Scene();
var backgroundCamera = new THREE.Camera();
backgroundScene.add(backgroundCamera);
backgroundScene.add(backgroundMesh);
// Rendering function
var render = function () {
requestAnimationFrame(render);
// Update the color to set
if (color < 0xdddddd)
color += 0x0000ff;
// Update the cube color
cube.material.color.setHex(color);
// Update the cube rotations
cube.rotation.x += 0.05;
cube.rotation.y += 0.02;
renderer.autoClear = false;
renderer.clear();
renderer.render(backgroundScene, backgroundCamera);
renderer.render(scene, camera);
};
render();
})();
If you want the video to be static in background, I wouldn't transfer the video into the 3D scene as texture. Instead I would leave it in a div placed behind the canvas. The canvas can be set transparent, so only the meshes will be rendered, but background stays clear.
var renderer = new THREE.WebGLRenderer({ alpha: true });
renderer.setClearAlpha(0.0);
.parent {
position: relative;
width: 1024px;
height: 768px;
}
#monitor, #mainCanvas {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
#monitor {
transform: scaleX(-1);
}
<div class="parent">
<div id="monitor"></div>
<div id="mainCanvas"></div>
</div>
There doesn't seem to be any code that actually draws to the texture as the video plays. You will probably need to add something like
videoImageContext.drawImage(video, 0, 0);
videoTexture.needsUpdate = true;
to your renderloop.

Three.js animation from blender

CURRENTLY, what's the best way to export skinned mesh animations from blender? I'm pretty sure I have the importing down, both for JSON and dae, but I can't get anything to work perfectly.
I've gotten JSON to the point where it seems like only a small portion of my animation will play, and that's after rolling back blender.
I thought it might have been the parent issue, so I tried no parent, parented, and as a modifier. I've tried all these variations with and without both the object and the armature selected and each seperately, I've tried to make sure there was only a single animation action, which from my understanding is fixed.
With dae, it seems to have some crazy scaling difference? And things seem to work sporadic. A model that will load into the editor (albeit w/no animations) in the examples won't load at all in the collada skinned mesh example/my created scene. And if I try to load a foreign model like the version of the avatar model from the three.js server, it shows up with no skin. And all of this required me to download the dev branch of three.js (at least to get my model to import at all)
My blend file:
http://97.95.26.94/examples/basic_animation.blend
I've spent three days working on this. It seems to be different for every version of blender/three.js
EDIT:
heres some code that I recently tried to get working. not sure where I was at on it, at this point I'm just trying every thing. Please ignore the loader above, thats for the rest of my scene. assume all the directories are right... because they are.
<html>
<head>
<meta name="viewport" content="width=device-width, user-scalable=no">
<title>Lost Towers - Level designer</title>
<style>
body { margin: 0; }
canvas { width: 100%; height: 100% }
</style>
</head>
<body>
<div id="monitor"
style=
"
position:absolute;
color:white;
"
>ladidda!!</div>
<script src='xxx/jquery.js'></script>
<script src='xxx/three.min.js'></script><script src="xxx/ColladaLoader.js"></script>
<script>
window.onclick= function() {
var temp= renderer.domElement ;
if(temp.requestPointerLock) temp.requestPointerLock();
else if(temp.mozRequestPointerLock) temp.mozRequestPointerLock();
else if(temp.webkitRequestPointerLock) temp.webkitRequestPointerLock();
}
/// initialize three.js
//init_scene();
var container;
container = document.createElement( 'div' );
document.body.appendChild( container );
//main renderer
renderer = new THREE.WebGLRenderer({ antialias: true, alpha: false });
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
renderer.shadowMapEnabled = true;
renderer.shadowMapSoft = true;
renderer.shadowMapType = THREE.PCFSoftShadowMap;
renderer.shadowCameraNear = 3;
renderer.shadowCameraFar = 100;
renderer.shadowCameraFov = 10;
renderer.shadowMapBias = 0.03;
renderer.shadowMapWidth = 1024;
renderer.shadowMapHeight = 1024;
renderer.autoClear=false;
document.oncontextmenu=function(event){event.preventDefault();};
function onWindowResize() {
windowHalfX = window.innerWidth / 2;
windowHalfY = window.innerHeight / 2;
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
var manager = new THREE.LoadingManager();
var clock = new THREE.Clock();
var delta=0;
var loader = new THREE.BufferGeometryLoader();
var camera;
var scene= new THREE.Scene();
// load a resource
var loader = new THREE.ObjectLoader();
loader.setTexturePath("xxx");
loader.load= function (a, b, c, d) {////////////////Ignore all this, its for loading scene from clara.io
var e = loader,
f = new THREE.XHRLoader(e.manager);
f.setCrossOrigin(loader.crossOrigin);
f.load(a, function (a) {
var x=JSON.parse(a)
if(x.images)
for(var i=0;i<x.images.length;i++)
{
x.images[i].url=loader.texturePath+x.images[i].url;
}
e.parse(x, b)
}, c, d)
}
loader.load('xxx/main.json',function ( obj ) {
scene= obj;
//console.dir(obj);
loader.setTexturePath("xxx");
scene.traverse(function(child){
if(child instanceof THREE.PerspectiveCamera)
{
camera=child;
scene.add(camera);
}
/////////////////////////////////////HERE//////////////////////////////////////////////
});
var daeloader = new THREE.ColladaLoader();
daeloader.load( "xxx/main.dae", function ( collada ) {
console.dir(collada.scene); alert();
collada.scene.traverse( function ( obj ) {
if(obj.type=='Object3D')
obj.traverse( function ( child ) {
if ( child instanceof THREE.SkinnedMesh ) {
console.dir(child);
var animation = new THREE.Animation( child, child.geometry.animation );
animation.play();
camera.lookAt( child.position );
}
} );
} );
scene.add( collada.scene );
} );
},function(){loader.setTexturePath("xxx");});
main();
function main()
{
requestAnimationFrame( main );
THREE.AnimationHandler.update( clock.getDelta() );
if(scene && camera)
renderer.render( scene, camera );
}
</script>
</body>
</html>

Categories

Resources