Want to create objects (cubes), within a for loop, then output them in a random location on the page. Cubes do not appear unsure why.
**Info: When I console log the cube get **
-cube.js:24 Mesh {uuid: "8859E918-7D3A-47ED-BDEF-072BC60FF725", name:
"", type: "Mesh", parent: Scene, children: Array(0), …}
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth /
window.innerHeight, 0.1, 1000 )
camera.position.z = 5;
var renderer = new THREE.WebGLRenderer({antialias: true});
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 geometry = new THREE.BoxGeometry(3, 1, 1);
var material = new THREE.MeshLambertMaterial({color: 0x00ff00});
var cube = new THREE.Mesh(geometry, material);
meshX = -5;
for(var i = 0; i<20;i++) { //amount of shapes
cube.position.x = (Math.random() - 0.5) * 10; //Location of shapes
cube.position.y = (Math.random() - 0.5) * 10;
cube.position.z = (Math.random() - 1.2) * 10;
scene.add(cube);
meshX+=1;
console.log(cube);
}
var render = function() {
requestAnimationFrame(render);
renderer.render(scene, camera);
}
render();
You need a light for MeshLambertMaterial (as opposed MeshBasicMaterial which does not use lights).
Also, you need to make a new Cube instance in the loop, otherwise you are just changing the location of the initial cube.
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth /
window.innerHeight, 0.1, 1000 )
camera.position.z = 5;
var renderer = new THREE.WebGLRenderer({antialias: true});
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();
})
// Create ambient light and add to scene.
var light = new THREE.AmbientLight(0x404040); // soft white light
scene.add(light);
var geometry = new THREE.BoxGeometry(3, 1, 1);
var material = new THREE.MeshLambertMaterial({color: 0x00ff00});
//var cube = new THREE.Mesh(geometry, material);
//meshX = -5;
for(var i = 0; i<20;i++) { //amount of shapes
var cube = new THREE.Mesh(geometry, material);
cube.position.x = (Math.random() - 0.5) * 10; //Location of shapes
cube.position.y = (Math.random() - 0.5) * 10;
cube.position.z = (Math.random() - 1.2) * 10;
scene.add(cube);
//meshX+=1;
//console.log(cube);
}
var render = function() {
requestAnimationFrame(render);
renderer.render(scene, camera);
}
render();
body {
padding: 0;
margin: 0;
position: relative;
}
<script src="https://rawgithub.com/mrdoob/three.js/r104/build/three.js"></script>
Related
I'm trying to load a texture with three.js to use it as a normal map. It returns no error or anything else, but the texture is not loading. I end up with a black ball
import * as THREE from 'three';
/** Build the scene. */
const canvas = document.querySelector('#canvas');
const scene = new THREE.Scene();
const textureLoader = new THREE.TextureLoader();
/** Create the sphere. */
const gemoetry = new THREE.SphereBufferGeometry(.5, 64, 64);
const material = new THREE.MeshStandardMaterial({
metalness: 0.7,
roughness: 0.2,
normalMap: textureLoader.load('https://res.cloudinary.com/axiol/image/upload/v1617884764/CodePen/normalMap.png'),
color: new THREE.Color(0x292929)
});
const sphere = new THREE.Mesh(gemoetry, material);
scene.add(sphere);
/** Set the sizes based on the windows size. */
const sizes = {
width: window.innerWidth,
height: window.innerHeight
};
/** Add some light. */
const pointLight = new THREE.PointLight(0xffffff, 0.1)
pointLight.position.x = 2
pointLight.position.y = 3
pointLight.position.z = 4
scene.add(pointLight)
window.addEventListener('resize', () => {
sizes.width = window.innerWidth
sizes.height = window.innerHeight
camera.aspect = sizes.width / sizes.height
camera.updateProjectionMatrix()
renderer.setSize(sizes.width, sizes.height)
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
});
/** Place the camera. */
const camera = new THREE.PerspectiveCamera(75, sizes.width / sizes.height, 0.1, 100);
camera.position.x = 0;
camera.position.y = 0;
camera.position.z = 2;
scene.add(camera);
/** Render the scene. */
const renderer = new THREE.WebGLRenderer({
canvas: canvas,
alpha: true
});
renderer.setSize(sizes.width, sizes.height);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
renderer.render(scene, camera);
I don't really see what I could be missing here. Any idea ?
You render the scene with a normal map which is not yet fully loaded. Try it like so:
/** Build the scene. */
const canvas = document.querySelector('#canvas');
const scene = new THREE.Scene();
scene.background = new THREE.Color(0xffffff);
const textureLoader = new THREE.TextureLoader();
/** Create the sphere. */
const gemoetry = new THREE.SphereBufferGeometry(0.5, 64, 64);
const material = new THREE.MeshStandardMaterial({
metalness: 0.7,
roughness: 0.2,
normalMap: textureLoader.load('https://res.cloudinary.com/axiol/image/upload/v1617884764/CodePen/normalMap.png', render),
color: new THREE.Color(0xffffff)
});
const sphere = new THREE.Mesh(gemoetry, material);
scene.add(sphere);
/** Set the sizes based on the windows size. */
const sizes = {
width: window.innerWidth,
height: window.innerHeight
};
/** Add some light. */
const pointLight = new THREE.PointLight(0xffffff, 1)
pointLight.position.x = 2
pointLight.position.y = 3
pointLight.position.z = 4
scene.add(pointLight)
window.addEventListener('resize', () => {
sizes.width = window.innerWidth
sizes.height = window.innerHeight
camera.aspect = sizes.width / sizes.height
camera.updateProjectionMatrix()
renderer.setSize(sizes.width, sizes.height)
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
});
/** Place the camera. */
const camera = new THREE.PerspectiveCamera(75, sizes.width / sizes.height, 0.1, 100);
camera.position.x = 0;
camera.position.y = 0;
camera.position.z = 2;
scene.add(camera);
/** Render the scene. */
const renderer = new THREE.WebGLRenderer({
canvas: canvas
});
renderer.setSize(sizes.width, sizes.height);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
render();
function render() {
renderer.render(scene, camera);
}
body {
margin:0
}
<script src="https://cdn.jsdelivr.net/npm/three#0.127.0/build/three.js"></script>
<canvas id="canvas"></canvas>
Notice the call of render() in the onLoad() callback of TextureLoader.load().
This is my source code. I am trying to make the text rotate according to mouse position.
// Initialization
const scene = new THREE.Scene();
let camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
let renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
let body = document.getElementsByTagName("body");
let pageX = 0.5;
let pageY = 0.5;
renderer.setSize( window.innerWidth, window.innerHeight );
document.getElementById("board").appendChild(renderer.domElement);
// Handle resize event
window.addEventListener('resize', () => {
renderer.setSize( window.innerWidth, window.innerHeight );
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
});
camera.position.z = 20;
// Create light
let directLight = new THREE.DirectionalLight('#fff', 4);
directLight.position.set(0, 7, 5);
scene.add(directLight);
var light = new THREE.AmbientLight( 0x404040 ); // soft white light
scene.add( light );
function animate (){
requestAnimationFrame( animate );
var loader = new THREE.FontLoader();
loader.load( 'https://threejs.org/examples/fonts/helvetiker_regular.typeface.json', function ( font ) {
var geometry = new THREE.TextGeometry( 'Hello three.js!', {
font: font,
size: 3,
height: 0.5,
curveSegments: 4,
bevelEnabled: true,
bevelThickness: 0.02,
bevelSize: 0.05,
bevelSegments: 3
} );
geometry.center();
var material = new THREE.MeshPhongMaterial(
{ color: '#dbe4eb', specular: '#dbe4eb' }
);
var mesh = new THREE.Mesh( geometry, material );
mesh.rotation.x = (pageY - 0.5) * 2;
mesh.rotation.y = (pageX - 0.5) * 2;
scene.add( mesh );
} );
renderer.render(scene, camera);
}
animate();
// Get mouse coordinates inside the browser
document.body.addEventListener('mousemove', (event) => {
pageX = event.pageX / window.innerWidth;
pageY = event.pageY / window.innerHeight;
});
renderer.render(scene, camera);
</script>
This is the best I could get. The problem is that each time I move the mouse, it instantiates a new mesh and rotates it accordingly, and I only need one mesh to follow the mouse. Can anyone help?
Thanks in advance!
As you already figured out, each frame you're reloading the font and ultimately recreating the mesh each time.
To get around this you need to move the font loading and object creation inside some initialization function, so it just happens once.
The only part of code you want to keep inside the render loop is the updating of the text's rotation according to the mouse movement:
mesh.rotation.x = (pageY - 0.5) * 2;
mesh.rotation.y = (pageX - 0.5) * 2;
This will bring up another problem though. Since mesh is a local object defined inside the callback function of the font loader, it won't be accessible outside. Luckily three.js offers a property called .name which you can use to give your object a name.
e.g.
var mesh = new THREE.Mesh(geometry, material);
mesh.name = "myText";
scene.add(mesh);
Later on you can get a reference to this object using:
scene.getObjectByName("myText")
Here's an example:
var container, scene, camera, renderer, pageX, pageY;
function init() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true
});
pageX = 0.5;
pageY = 0.5;
renderer.setSize(window.innerWidth, window.innerHeight);
document.getElementById("container").appendChild(renderer.domElement);
window.addEventListener('resize', () => {
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
});
camera.position.z = 20;
let directLight = new THREE.DirectionalLight('#fff', 4);
directLight.position.set(0, 7, 5);
scene.add(directLight);
var light = new THREE.AmbientLight(0x404040); // soft white light
scene.add(light);
var loader = new THREE.FontLoader();
loader.load('https://threejs.org/examples/fonts/helvetiker_regular.typeface.json', function(font) {
var geometry = new THREE.TextGeometry('Hello three.js!', {
font: font,
size: 3,
height: 0.5,
curveSegments: 4,
bevelEnabled: true,
bevelThickness: 0.02,
bevelSize: 0.05,
bevelSegments: 3
});
geometry.center();
var material = new THREE.MeshPhongMaterial({
color: '#dbe4eb',
specular: '#dbe4eb'
});
var mesh = new THREE.Mesh(geometry, material);
mesh.name = "myText";
scene.add(mesh);
animate();
});
document.body.addEventListener('mousemove', (event) => {
pageX = event.pageX / window.innerWidth;
pageY = event.pageY / window.innerHeight;
});
}
function animate() {
requestAnimationFrame(animate);
render();
}
function render() {
scene.getObjectByName("myText").rotation.x = (pageY - 0.5) * 2;
scene.getObjectByName("myText").rotation.y = (pageX - 0.5) * 2;
renderer.render(scene, camera);
}
init();
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r120/three.min.js"></script>
<div id="container"></div>
I am new to three.js and 3D model rendering and have been playing around with this sample code that i found on the internet. My aim here is to be able to render my 3D model using the chrome browser.
The default code is :
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 );
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
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;
var animate = function () {
requestAnimationFrame( animate );
cube.rotation.x += 0.1;
cube.rotation.y += 0.1;
renderer.render(scene, camera);
};
animate();
When i go to my browser and type in http://localhost:8080/ i get a cube rotating
Now i try modifying the code to
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 );
camera.position.z = 200;
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
var controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.25;
controls.enableZoom = true;
var keyLight = new THREE.DirectionalLight(new THREE.Color('hsl(30, 100%, 75%)'), 1.0);
keyLight.position.set(-100, 0, 100);
var fillLight = new THREE.DirectionalLight(new THREE.Color('hsl(240, 100%, 75%)'), 0.75);
fillLight.position.set(100, 0, 100);
var backLight = new THREE.DirectionalLight(0xffffff, 1.0);
backLight.position.set(100, 0, -100).normalize();
scene.add(keyLight);
scene.add(fillLight);
scene.add(backLight);
var mtlLoader = new THREE.MTLLoader();
mtlLoader.setTexturePath('/examples/3d-obj-loader/assets/');
mtlLoader.setPath('/examples/3d-obj-loader/assets/');
mtlLoader.load('r2-d2.mtl', function (materials) {
materials.preload();
var objLoader = new THREE.OBJLoader();
objLoader.setMaterials(materials);
objLoader.setPath('/examples/3d-obj-loader/assets/');
objLoader.load('r2-d2.obj', function (object) {
scene.add(object);
object.position.y -= 60;
});
});
var animate = function () {
requestAnimationFrame( animate );
controls.update();
renderer.render(scene, camera);
};
animate();
This should give me an image of r2-d2 model being rendered but i see a blank screen
I would really appreciate help in understanding what i am missing.
For some reason I am not able to change the color of a cube when a person mouses over it. I distilled the code down to the most barebones I could.
http://jsfiddle.net/pgd3d5rf/
<script>
var container;
var scene, camera, renderer, mouse, raycaster;
var grid_items = [];
init();
grid();
render();
function init() {
container = document.createElement( 'div' );
document.body.appendChild( container );
scene = new THREE.Scene();
raycaster = new THREE.Raycaster();
mouse = new THREE.Vector2();
camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 1, 10000 );
camera.position.set( 500, 800, 1300 );
camera.lookAt( new THREE.Vector3() );
// Lights
var ambientLight = new THREE.AmbientLight( 0x606060 );
scene.add( ambientLight );
var directionalLight = new THREE.DirectionalLight( 0xffffff );
directionalLight.position.x = Math.random() - 0.5;
directionalLight.position.y = Math.random() - 0.5;
directionalLight.position.z = Math.random() - 0.5;
directionalLight.position.normalize();
scene.add( directionalLight );
var directionalLight = new THREE.DirectionalLight( 0x808080 );
directionalLight.position.x = Math.random() - 0.5;
directionalLight.position.y = Math.random() - 0.5;
directionalLight.position.z = Math.random() - 0.5;
directionalLight.position.normalize();
scene.add( directionalLight );
renderer = new THREE.CanvasRenderer();
renderer.setClearColor( 0xf0f0f0 );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild(renderer.domElement);
window.addEventListener('mousemove', onDocumentMouseMove, false );
}
function grid(){
var geometry = new THREE.BoxGeometry(100, 100, 100);
var material = new THREE.MeshBasicMaterial({ color: 0x0000ff });
var cube = new THREE.Mesh(geometry, material);
scene.add(cube);
grid_items.push(cube);
}
function onDocumentMouseMove(event) {
mouse.x = (event.clientX / renderer.domElement.width) * 2 - 1;
mouse.y = - (event.clientY / renderer.domElement.height) * 2 + 1;
console.log(mouse.x+"-"+mouse.y);
raycaster.setFromCamera(mouse, camera);
var intersects = raycaster.intersectObjects(grid_items);
if (intersects.length > 0) {
for (var i = 0; i < intersects.length; i++) {
console.log("OBJECT "+intersects[i])
intersects[i].object.material.color.set(0xff0000);
}
}
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
render();
}
function render() {
renderer.render( scene, camera );
}
You need to re-render after changing the color. So add a call to render(); just after you changed the colors:
if (intersects.length > 0) {
for (var i = 0; i < intersects.length; i++) {
console.log("OBJECT "+intersects[i]);
intersects[i].object.material.color.set(0xff0000);
}
render();
}
Updated fiddle: http://jsfiddle.net/pgd3d5rf/1/
With the CanvasRenderer() your fiddle is not working but if I change it to WebGLRenderer() then if you add a render() call at the end of your onDocumentMouseMove() function it should work.
I have a program that used to work, but I am now getting the "undefined is not a function" error from within the three.js file. The error is pointing to line 10466 of the uncompressed library, and this line is within the declaration of THREE.PerspectiveCamera. Where is the problem? Thanks!
var assets = {};
var modelLoader = new THREE.JSONLoader(true);
modelLoader.load("assets/horse.js", onLoadedAssets);
var loading = setTimeout(function() {
console.log("loading...");
}, 1000);
var scene, camera, renderer, controls;
var horse, box;
function init() {
scene = new THREE.Scene();
var w = window.innerWidth,
h = window.innerHeight;
camera = THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.y = 0;
camera.target = new THREE.Vector3(0, 0, 0);
var light1 = new THREE.DirectionalLight(0xefefff, 2);
light1.position.set(1, 1, 1).normalize();
scene.add(light1);
var light2 = new THREE.DirectionalLight(0xffefef, 2);
light2.position.set(-1, -1, -1).normalize();
scene.add(light2);
renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
window.addEventListener('resize', onWindowResize, false);
box = new Box(500, 500, 500);
horse = new Horse();
}
function animate() {
requestAnimationFrame(animate);
render();
}
var prevTime = Date.now();
function render() {
camera.position.x = 560 + Math.random() * 40;
camera.position.z = 560 + Math.random() * 40;
camera.lookAt(camera.target);
if (horse.animation) {
var time = Date.now();
horse.animation.update(time - prevTime);
prevTime = time;
}
renderer.render(scene, camera);
}
function onLoadedAssets(geometry) {
clearTimeout(loading);
console.log("loaded assets.")
geometry.computeFaceNormals();
geometry.computeVertexNormals();
var material = new THREE.MeshLambertMaterial({
color: 0x606060,
morphTargets: true
});
var mesh = new THREE.Mesh(geometry, material);
mesh.scale.set(1, 1, 1);
var animation = new THREE.MorphAnimation(mesh);
animation.play();
animation.isPlaying = false;
assets["horse"] = {
mesh: mesh,
animation: animation
};
init();
animate();
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(w, h);
}
function Horse() {
var self;
self = assets["horse"];
scene.add(self.mesh);
self.startMoving = function() {
self.animation.isPlaying = true;
};
self.stopMoving = function() {
self.animation.isPlaying = false;
};
return self;
}
function Box(xidth, yidth, zidth) {
var self = this;
var geometry = new THREE.BoxGeometry(xidth, yidth, zidth);
var material = new THREE.MeshBasicMaterial({
color: 0x666666,
opacity: 0.4,
transparent: true
});
var cube = new THREE.Mesh(geometry, material);
scene.add(cube);
self.geometry = geometry;
self.cube = cube;
}
your error seems to be in this line
camera = THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.1, 1000);
Try putting a new before the THREE...
camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.1, 1000);