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

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>

Related

Threejs: Video texture not working in safari

I have a little scene that uses an mp4 video to texture a rectangle:
* {
margin: 0;
padding: 0;
background-color: #282923;
}
body {
margin: 0;
color: #fff;
font-family: Monospace;
font-size: 13px;
line-height: 24px;
overscroll-behavior: none;
overflow: hidden;
}
canvas {
display: block;
}
.no-highlight {
-webkit-touch-callout: none; /* iOS Safari */
-webkit-user-select: none; /* Safari */
-khtml-user-select: none; /* Konqueror HTML */
-moz-user-select: none; /* Old versions of Firefox */
-ms-user-select: none; /* Internet Explorer/Edge */
user-select: none; /* Non-prefixed version, currently
supported by Chrome, Edge, Opera and Firefox */
}
#play {
color: #fff;
text-align: center;
position: absolute;
top: 50%;
left: 0;
right: 0;
cursor: pointer;
}
<!DOCTYPE html>
<html lang='en'>
<head>
<title>I AM ALAN TURING</title>
<meta charset='utf-8'>
<meta name='viewport' content='width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0'>
<link type='text/css' rel='stylesheet' href='./assets/main.css'>
</head>
<video id='video' crossOrigin='anonymous' loop playsinline controls style='position:fixed; top:-10000px; left: -10000px; width: 512px; height: 256px;'>
<source src='https://duhaime.s3.amazonaws.com/sketches/A565AC1E351B6A21FF7F005AB6FDE6F7/bass-clip.mp4' type='video/mp4; codecs="avc1.42E01E, mp4a.40.2"'>
</video>
<body class='no-highlight'>
<div id='play'>play</div>
<script type='module'>
import * as THREE from 'https://duhaime.s3.amazonaws.com/sketches/A565AC1E351B6A21FF7F005AB6FDE6F7/assets/js/three.module.js';
import { AsciiEffect } from 'https://duhaime.s3.amazonaws.com/sketches/A565AC1E351B6A21FF7F005AB6FDE6F7/assets/js/AsciiEffect.js';
import { TrackballControls } from 'https://duhaime.s3.amazonaws.com/sketches/A565AC1E351B6A21FF7F005AB6FDE6F7/assets/js/TrackballControls.js';
var camera, controls, scene, renderer, effect;
var sphere, plane;
var play, video, videocanvas, videocanvasctx, texture;
var start = Date.now();
init();
animate();
function init() {
camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 1000 );
camera.position.z = 100;
scene = new THREE.Scene();
scene.background = new THREE.Color( 0, 0, 0 );
renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
effect = new AsciiEffect( renderer, ' .:-+*=%##', { invert: true } );
effect.setSize( window.innerWidth, window.innerHeight );
effect.domElement.style.color = 'white';
effect.domElement.style.backgroundColor = 'black';
// use effect.domElement for ascii rendering
document.body.appendChild( effect.domElement );
controls = new TrackballControls( camera, effect.domElement );
window.addEventListener( 'resize', onWindowResize, false );
// video
video = document.querySelector('#video');
play = document.querySelector('#play');
play.addEventListener('click', startVideo);
function startVideo() {
video.play();
play.parentNode.removeChild(play);
// create the canvas
videocanvas = document.createElement('canvas');
videocanvas.height = video.clientHeight;
videocanvas.width = video.clientWidth;
videocanvas.crossOrigin = 'anonymous';
videocanvasctx = videocanvas.getContext('2d');
videocanvasctx.fillStyle = '#000000';
videocanvasctx.fillRect(0,0,video.clientWidth,video.clientHeight);
texture = new THREE.Texture(videocanvas);
var material = new THREE.MeshBasicMaterial( { map: texture } );
var geometry = new THREE.PlaneGeometry( video.clientWidth, video.clientHeight, 32 );
var mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
}
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
effect.setSize( window.innerWidth, window.innerHeight );
}
function animate() {
requestAnimationFrame( animate );
render();
}
function render() {
var timer = Date.now() - start;
controls.update();
effect.render( scene, camera );
if (videocanvasctx && video.readyState == video.HAVE_ENOUGH_DATA) {
videocanvasctx.drawImage(video, 0, 0);
texture.needsUpdate = true;
}
}
</script>
</body>
</html>
This works fine in Chrome, but does not run in Safari. Does anyone know why that might be, or what I should investigate to discover the different behavior in Safari? Any pointers would be very helpful!

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);

ThreeJS Update scene when changing opacity

Here is the constructor of my object :
<code>class Something {
constructor(mesh = undefined, material = undefined) {
this.mesh = undefined;
material = material;
this.gui = undefined;
if (mesh) {
this.mesh_opacity = 1;
this.created = true;
this.mesh = new THREE.Mesh(mesh.geometry, new THREE.MeshPhongMaterial({
// wireframe: true,
transparent : true,
opacity: this.mesh_opacity,
color : 0xffffff
}));
}
</code>
I add this object to the scene, and in my interface, I have a slider where I can change the opacity of my object using this function :
<code><script type="text/javascript">
$('#slider').on('change', function(){
val = $("#slider").val();
scene.something.mesh_opacity = val;
scene.something.material = new THREE.MeshPhongMaterial({
transparent : true,
opacity: val,
color : 0xffffff
});
scene.something.material.needsUpdate = true;
})
</script></code>
but in my scene I don't see any updates. How can I update the change of the opacity in scene instantly ?
Opacity takes a value between 0.0 - 1.0. You need to divide the value you take from your slider (usually 0 - 100) by 100. Something like the following:
val = $("#slider").val() / 100;
Other option, as mentioned by prisoner849, is to set your slider values manually:
<input type="range" id="slider" min="0" max="1" step="0.01" value="0.5" class="slider">
Which allows you to get the value directly:
val = $("#slider").val();
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(
45,
window.innerWidth / window.innerHeight,
1,
100
);
var renderer = new THREE.WebGLRenderer();
var light = new THREE.PointLight(0xcccccc, 1);
light.castShadows = true;
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var geometry = new THREE.SphereGeometry(1, 20, 20);
var material = new THREE.MeshPhongMaterial({
transparent: true,
opacity: 1,
color: 0xffffff
});
var sphere = new THREE.Mesh(geometry, material);
scene.add(sphere);
scene.add(light);
camera.position.z = 5;
light.position.x = 5;
light.position.y = 5;
light.position.z = 5;
document.getElementById("slider").addEventListener("change", function() {
sphere.material.opacity = document.getElementById("slider").value;
});
var render = function() {
requestAnimationFrame(render);
renderer.render(scene, camera);
};
render();
body {
margin: 0;
overflow: hidden;
}
canvas {
width: 100%;
height: 100%
}
.slider {
position: absolute;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/87/three.min.js"></script>
<input type="range" id="slider" min="0" max="1" step="0.01" value="0.5" class="slider">
Also, you don't need to create a new material every time (it slows down the whole rendering process). You should directly edit the material applied, like so:
scene.something.material.opacity = val;
r87

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.

Categories

Resources