I'm starting in ThresJS and I want to make a 5 by 5 square with BoxGeometry or via a gridHelper.
I want to create this square and be able to fill each box with a different color or not. Here is my code but I think I make an error in because it is in out of memory error
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import Stats from 'three/examples/jsm/libs/stats.module';
import { GUI } from 'dat.gui';
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(40, window.innerWidth / window.innerHeight, 0.1, 100);
camera.position.set(8, 5, 8);
camera.lookAt(0, 0, 0);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
const controls = new OrbitControls(camera, renderer.domElement);
var cubes = [];
const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshBasicMaterial({
color: 0x00ff00,
wireframe: true
});
for (let i = 0; i < 5; i++) {
for (let j = 0; j < 5; i++) {
let cube = new THREE.Mesh(geometry, material);
cube.position.x = i;
cube.position.y = j;
cubes.push(cube)
scene.add(cube)
}
}
window.addEventListener('resize', onWindowResize, false);
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
render();
}
const stats = Stats();
document.body.appendChild(stats.dom);
const gui = new GUI();
const cubeFolder = gui.addFolder('Cube');
cubeFolder.open();
const cameraFolder = gui.addFolder('Camera');
cameraFolder.add(camera.position, 'z', 0, 10);
cameraFolder.open();
function main() {
requestAnimationFrame(main);
render();
stats.update();
}
function render() {
renderer.render(scene, camera);
}
main();
Is there something I don't see that would make this mistake.
I thank you in advance
I try make a square 5x5 with ThreeJS and via BoxGeometry, But i have error explain in my previous text.
Error : Out of memory
As I can see the problem is in this block of code:
for (let i = 0; i < 5; i++) {
for (let j = 0; j < 5; i++) {
let cube = new THREE.Mesh(geometry, material);
cube.position.x = i;
cube.position.y = j;
cubes.push(cube)
scene.add(cube)
}
}
So, in the inner loop there's incrementing of "i", instead of "j".
Just try to change this, worked out in the codesandbox just fine
Related
I am trying to simulate a rubik's cube with three.js and now my goal is to rotate the faces using keyboard keys. The first rotation is doing fine but the second rotation snaps right in and also it is rotating in the direction of the first one (if I start with up clockwise the bottom will rotate against clockwise and vice versa).
this is my code:
import * as THREE from 'three'
import { TrackballControls } from 'three/examples/jsm/controls/TrackballControls';
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
const renderer = new THREE.WebGLRenderer({canvas: document.querySelector("canvas.webgl")});
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
const geometry = new THREE.BoxGeometry(1, 1, 1);
const materials = [
new THREE.MeshBasicMaterial({color: 'white'}),
new THREE.MeshBasicMaterial({color: 'yellow'}),
new THREE.MeshBasicMaterial({color: 'red'}),
new THREE.MeshBasicMaterial({color: 'darkorange'}),
new THREE.MeshBasicMaterial({color: 'blue'}),
new THREE.MeshBasicMaterial({color: 'green'}),
];
for(let i = 0; i < geometry.groups.length; i++)
geometry.groups[i].materialIndex = i;
const cube = [];
for(let y = -1; y <= 1; y++){
for(let x = -1; x <= 1; x++){
for(let z = -1; z <= 1; z++){
const mesh = new THREE.Mesh(geometry, materials);
mesh.position.x = x;
mesh.position.y = y;
mesh.position.z = z;
cube.push(mesh);
scene.add(mesh);
}
}
}
const controls = new TrackballControls( camera, renderer.domElement );
controls.noPan = true;
controls.noZoom = true;
controls.rotateSpeed = 3;
camera.position.z = 7.5;
controls.update();
const turnSpeed = 2;
const face = new THREE.Group();
l
et indexes = [];
scene.add(face);
function resetFace(){
let tempQuaternion = new THREE.Quaternion();
for(let i = 0; i < indexes.length; i++){
cube[i].getWorldQuaternion(tempQuaternion);
scene.add(cube[i]);
cube[i].quaternion.copy(tempQuaternion);
}
indexes = [];
}
function getU(){
resetFace();
for(let i = 18; i < 27; i++){
face.add(cube[i]);
indexes.push(i);
}
}
function getB(){
resetFace();
for(let i = 0; i < 9; i++){
face.add(cube[i]);
indexes.push(i);
}
}
function B() {
requestAnimationFrame( B );
controls.update();
// rotate
if(face.rotation.y < THREE.MathUtils.degToRad(90))
face.rotation.y += THREE.MathUtils.degToRad(turnSpeed);
renderer.render( scene, camera );
}
function U() {
requestAnimationFrame( U );
controls.update();
// rotate
if(face.rotation.y > THREE.MathUtils.degToRad(-90))
face.rotation.y -= THREE.MathUtils.degToRad(turnSpeed);
renderer.render( scene, camera );
}
document.addEventListener("keydown", (event) => {
console.log("animation start");
if(event.code == "KeyA"){
getU();
U();
}
else if(event.code == "KeyB"){
getB();
B();
}
})
function animate(){
requestAnimationFrame( animate );
controls.update();
renderer.render( scene, camera );
}
animate();
And the result is this:
The purpose of the code is to make a faced sphere in three.js in the old version before version 125
// 1. the first step is Make a faceted cube
let geometry = new THREE.BoxGeometry(1, 1, 1, 64, 64, 64);
// 2. the second step is Normalize all vertices
for (var i in this.geometry.vertices) {
geometry.vertices[i].normalize().multiplyScalar(this.radius);
}
// geometry.makeGroups();
geometry.computeVertexNormals();
geometry.computeFaceNormals();
geometry.computeMorphNormals();
geometry.computeBoundingSphere();
geometry.computeBoundingBox();
// geometry.computeLineDistances();
geometry.verticesNeedUpdate = true;
geometry.elementsNeedUpdate = true;
geometry.uvsNeedUpdate = true;
geometry.normalsNeedUpdate = true;
// geometry.tangentsNeedUpdate = true;
geometry.colorsNeedUpdate = true;
geometry.lineDistancesNeedUpdate = true;
// geometry.buffersNeedUpdate = true;
geometry.groupsNeedUpdate = true;
After version 125, the geometry class is removed and have BuffererGeometry in place, how would I modify the code to make a sphere again?
You can transform a box into a sphere this way:
body{
overflow: hidden;
margin: 0;
}
<script type="module">
import * as THREE from "https://cdn.skypack.dev/three#0.133.1";
import {OrbitControls} from "https://cdn.skypack.dev/three#0.133.1/examples/jsm/controls/OrbitControls.js";
let scene = new THREE.Scene();
let camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight, 1, 1000);
camera.position.set(0, 0, 5);
let renderer = new THREE.WebGLRenderer();
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);
let controls = new OrbitControls(camera, renderer.domElement);
let g = new THREE.BoxGeometry(1, 1, 1, 64, 64, 64);
let pos = g.attributes.position;
let v3 = new THREE.Vector3();
let radius = 2;
for (let i = 0; i < pos.count; i++){
v3.fromBufferAttribute(pos, i).normalize().multiplyScalar(radius);
pos.setXYZ(i, v3.x, v3.y, v3.z);
}
g.computeVertexNormals();
let m = new THREE.MeshNormalMaterial({wireframe: true});
let o = new THREE.Mesh(g, m);
scene.add(o);
window.addEventListener("resize", () => {
camera.aspect = innerWidth / innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(innerWidth, innerHeihgt);
});
renderer.setAnimationLoop(() => {
renderer.render(scene, camera);
});
</script>
I have a THREE.ArrayCamera with 4 cameras and trying to make my object visible from only 1 camera. I saw I can use Layers, which work well when I have 1 camera and doesn’t work at all with Array cameras. Object isn’t visible inside all cameras, despite it has layer 1 and camera.cameras[2] has layer1 enabled. JSFIDDLE: https://jsfiddle.net/h7u02jLw/
mesh = new THREE.Mesh( geometryCylinder, materialCylinder );
mesh.castShadow = true;
mesh.receiveShadow = true;
scene.add( mesh );
mesh.layers.set(1);
camera.cameras[2].layers.enable(1);
light.layers.enable(1);
console.log(camera.cameras[2].layers.test(mesh.layers))
var material2 = new THREE.MeshPhongMaterial({color: 0x00FF00});
mesh2 = new THREE.Mesh( geometryCylinder, material2 );
mesh2.castShadow = true;
mesh2.receiveShadow = true;
scene.add( mesh2 );
The combination of ArrayCamera and Layers has only limited support.
To make the red cylinder render in only one view, it's not sufficient to just enabled the layer on the sub camera. All layers you are going to use have to be enabled on the array camera, too. The following code demonstrated this.
However, you immediately see a rendering issue since shadows are rendered on all views. That happens because the shadow map is updated only once per frame and the layer configuration of the array camera is evaluated. Since all layers are enabled, all views show the shadow of the red cylinder. Shadow maps per sub camera are not supported.
let camera, scene, renderer;
let mesh, mesh2;
const AMOUNT = 2;
init();
animate();
function init() {
const ASPECT_RATIO = window.innerWidth / window.innerHeight;
const WIDTH = (window.innerWidth / AMOUNT) * window.devicePixelRatio;
const HEIGHT = (window.innerHeight / AMOUNT) * window.devicePixelRatio;
const cameras = [];
for (let y = 0; y < AMOUNT; y++) {
for (let x = 0; x < AMOUNT; x++) {
const subcamera = new THREE.PerspectiveCamera(40, ASPECT_RATIO, 0.1, 10);
subcamera.viewport = new THREE.Vector4(Math.floor(x * WIDTH), Math.floor(y * HEIGHT), Math.ceil(WIDTH), Math.ceil(HEIGHT));
subcamera.position.x = (x / AMOUNT) - 0.5;
subcamera.position.y = 0.5 - (y / AMOUNT);
subcamera.position.z = 1.5;
subcamera.position.multiplyScalar(2);
subcamera.lookAt(0, 0, 0);
subcamera.updateMatrixWorld();
cameras.push(subcamera);
}
}
camera = new THREE.ArrayCamera(cameras);
camera.layers.enable(1);
camera.position.z = 3;
scene = new THREE.Scene();
scene.add(new THREE.AmbientLight(0x222244));
const light = new THREE.DirectionalLight();
light.position.set(0.5, 0.5, 1);
light.castShadow = true;
light.shadow.camera.zoom = 4; // tighter shadow map
scene.add(light);
const geometryBackground = new THREE.PlaneGeometry(100, 100);
const materialBackground = new THREE.MeshPhongMaterial({
color: 0x000066
});
const background = new THREE.Mesh(geometryBackground, materialBackground);
background.receiveShadow = true;
background.position.set(0, 0, -1);
scene.add(background);
const geometryCylinder = new THREE.CylinderGeometry(0.5, 0.5, 1, 32);
const materialCylinder = new THREE.MeshPhongMaterial({
color: 0xff0000
});
mesh = new THREE.Mesh(geometryCylinder, materialCylinder);
mesh.castShadow = true;
mesh.receiveShadow = true;
scene.add(mesh);
mesh.layers.set(1);
camera.cameras[2].layers.enable(1);
//light.layers.set(1);
var material2 = new THREE.MeshPhongMaterial({
color: 0x00FF00
});
mesh2 = new THREE.Mesh(geometryCylinder, material2);
mesh2.castShadow = true;
mesh2.receiveShadow = true;
scene.add(mesh2);
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
document.body.appendChild(renderer.domElement);
//
window.addEventListener('resize', onWindowResize);
}
function onWindowResize() {
const ASPECT_RATIO = window.innerWidth / window.innerHeight;
const WIDTH = (window.innerWidth / AMOUNT) * window.devicePixelRatio;
const HEIGHT = (window.innerHeight / AMOUNT) * window.devicePixelRatio;
camera.aspect = ASPECT_RATIO;
camera.updateProjectionMatrix();
for (let y = 0; y < AMOUNT; y++) {
for (let x = 0; x < AMOUNT; x++) {
const subcamera = camera.cameras[AMOUNT * y + x];
subcamera.viewport.set(
Math.floor(x * WIDTH),
Math.floor(y * HEIGHT),
Math.ceil(WIDTH),
Math.ceil(HEIGHT));
subcamera.aspect = ASPECT_RATIO;
subcamera.updateProjectionMatrix();
}
}
renderer.setSize(window.innerWidth, window.innerHeight);
}
function animate() {
mesh.rotation.x += 0.005;
mesh.rotation.z += 0.01;
renderer.render(scene, camera);
requestAnimationFrame(animate);
}
body {
margin: 0;
}
<script src="https://cdn.jsdelivr.net/npm/three#0.126.1/build/three.js"></script>
Working on some kind of fictional treasure map. I'm cutting a large displacement map intosmaller tiles as I don't yet how wide the final terrain is going to be -- right now it's 5*5, but it could be wider in the future
For some reasons, I am having issues projecting shadows on the displaced planes.
I don't know where the problem is coming from. Maybe it's the way I push meshes into an array through a function, i'm afraid i'm not doing this the right way.
I'd like to achieve the result using a directional light
Here is a c4d draft of what i'm trying to achieve
and here is what i'm able to do in the browser (didnt manage to tile them properly yet :^)
var renderer = new THREE.WebGLRenderer();
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
var material = [];
var texture = [];
var tile = [];
var planeRes = 128;
var planesize = 1;
var dim = 5;
var size = dim * dim;
var DispScale = 2;
var geometry = new THREE.PlaneBufferGeometry(planesize,planesize,planeRes, planeRes);
function tileGenerator(inc) {
if (inc < 10) {
texture[inc] = new THREE.TextureLoader().load('cut25lowres/image_part_00' + inc + '.jpg');
} else {
texture[inc] = new THREE.TextureLoader().load('cut25lowres/image_part_0' + inc + '.jpg');
}
material[inc] = new THREE.MeshPhongMaterial({
color: 0xffffff,
displacementMap: texture[inc],
side: THREE.DoubleSide,
receiveShadow : true,
castShadow : true
});
tile[inc] = new THREE.Mesh(geometry, material[inc]);
}
for (var i = 1; i < size + 1; i++) {
tileGenerator(i);
}
for (var i = 1; i < size + 1; i++) {
tile[i].position.set(-planesize * (i % dim)+1, 0, -planesize * Math.ceil(i / dim)+1 );
tile[i].rotation.x = Math.PI / 2 + Math.PI;
tile[i].rotation.z = Math.PI / 2;
scene.add(tile[i]);
}
var dirLight = new THREE.DirectionalLight( 0xffffff, 1 );
dirLight.castShadow = true;
dirLight.shadow.camera.near = 0.1;
dirLight.shadow.camera.far = 6;
dirLight.shadow.mapSize.set( 1024, 1024 );
var targetObject = new THREE.Object3D();
targetObject.position.x = -10;
targetObject.position.z = -10;
dirLight.position.y = 3;
scene.add(targetObject);
dirLight.target = targetObject;
scene.add( dirLight );
Edit : Here is a cleaner version without the array as it's not part of the problem
jsfiddle.net/clemtre/3y9tqc6j/34
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
var renderer = new THREE.WebGLRenderer();
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var controls = new THREE.OrbitControls(camera, renderer.domElement);
var scene = new THREE.Scene();
var heightmap = new THREE.TextureLoader().load('https://i.imgur.com/MVYhfd7.jpeg');
var geometry = new THREE.PlaneGeometry(20, 20, 100, 100);
var material = new THREE.MeshPhongMaterial({
color: 0xffffff,
displacementMap: heightmap,
displacementScale: 10
});
var light = new THREE.DirectionalLight(0xffffff);
light.position.set(0, 1, 1).normalize();
light.castShadow = true;
scene.add(light);
var plane = new THREE.Mesh(geometry, material);
plane.rotation.x = -Math.PI/2;
scene.add(plane);
camera.position.z = -20;
camera.position.y = 5;
controls.update();
var animate = function() {
requestAnimationFrame(animate);
controls.update();
renderer.render(scene, camera);
};
animate();
Many thanks!
I'm trying to set the camera to be 3 units away from a collection of points I would like this to be relative to the group of points since the points will change later on.
So far I can retrieve x,y,z coordinates from the database and are returned using djangos {{coord_x}} I will have to return the correct length, (I could do this on the python side - len()) for now the database query is limited to 20 rows. These points are brought into three.js using a for loop.
How do I set a camera relative to the objects? Do I need to calculate a bounding box?
<script>
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.001, 100000);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// allow resizing of the window
window.addEventListener('resize', function()
{
var width = window.innerWidth;
var height = window.innerHeight;
renderer.setSize(width, height);
camera.aspect = width / height;
camera.updateProjectionMatrix();
});
//Controls
controls = new THREE.OrbitControls(camera, renderer.domElement)
//create the shape
var geometry = new THREE.BoxGeometry(1, 1, 1);
var material = new THREE.MeshBasicMaterial({color: 0x007654, wireframe: false});
var cube = new THREE.Mesh(geometry, material);
scene.add(cube);
var numpoints = 20;
var dots = []; //If you want to use for other task
for (var i = 0 ; i < numpoints ; i++) {
var x = "{{coord_x}}";
var y = "{{coord_y}}";
var z = "{{coord_z}}";
// var x = Math.random() * (0 - 1) + 1
// var y = Math.random() * (0 - 1) + 1
// var z = Math.random() * (0 - 1) + 1
var dotGeometry = new THREE.Geometry();
dots.push(dotGeometry);
dotGeometry.vertices.push(new THREE.Vector3(x, y, z));
var dotMaterial = new THREE.PointsMaterial( { size: 3, sizeAttenuation: false, color: 0xFF0000 });
var dot = new THREE.Points( dotGeometry, dotMaterial);
scene.add(dot);
}
camera.position.z = 30
//game logic, allow rotation
var update = function()
{
//cube.rotation.x += 0.00;
//cube.rotation.y += 0.0025;
//dot.rotation.x += 0.00;
//dot.rotation.y += 0.005;
};
// draw scene
var render = function()
{
renderer.render(scene, camera);
};
// run game loop (update, render, repeat)
var GameLoop = function()
{
requestAnimationFrame(GameLoop);
update();
render();
};
GameLoop();
</script>
That's how you can work with THREE.Sphere() object to set the position of your camera:
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var controls = new THREE.OrbitControls(camera, renderer.domElement);
var geom = new THREE.Geometry();
for (let i = 0; i < 100; i++) {
geom.vertices.push(
new THREE.Vector3(
Math.random() - 0.5,
Math.random() - 0.5,
Math.random() - 0.5
).multiplyScalar(10)
);
}
var points = new THREE.Points(geom, new THREE.PointsMaterial({
size: 0.25,
color: "aqua"
}));
scene.add(points);
var sphere = new THREE.Sphere().setFromPoints(geom.vertices);
console.log(sphere);
camera.position.copy(sphere.center);
camera.position.z += sphere.radius / Math.sin(THREE.Math.degToRad(camera.fov / 2));
render();
function render() {
requestAnimationFrame(render);
renderer.render(scene, camera);
}
body {
overflow: hidden;
margin: 0;
}
<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>