Render Multiple Boxes together in THREE.js - javascript

I am trying to render multiple boxes together in a structure as in the pic I am providing. I want to test the limitations of GPU as I add more, so then later I will try and optimize. I am using THREE.js, which is written in JavaScript. If possible I would like to implement this task with a three dimensional array. I think this would be the most efficient way. Not sure how to do so in JavaScript though.
[Box group1

Try it like so:
let renderer, scene, camera;
init();
animate();
function init() {
// renderer
renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);
document.body.appendChild(renderer.domElement);
// scene
scene = new THREE.Scene();
// camera
camera = new THREE.PerspectiveCamera(40, window.innerWidth / window.innerHeight, 1, 10000);
camera.position.set(40, 40, 40);
camera.lookAt(0, 10, 0);
// geometry
const geometry = new THREE.BoxGeometry();
const edgesGeometry = new THREE.EdgesGeometry(geometry);
// material
const material = new THREE.MeshBasicMaterial({
color: 0xffff00,
});
const edgesMaterial = new THREE.LineBasicMaterial({
color: 0x000000
});
// positions
for (let x = -10; x < 10; x++) {
for (let y = 0; y < 20; y++) {
for (let z = -10; z < 10; z++) {
// mesh
const mesh = new THREE.Mesh(geometry, material);
mesh.scale.multiplyScalar(0.9);
mesh.position.set(x, y, z);
scene.add(mesh);
const lines = new THREE.LineSegments(edgesGeometry, edgesMaterial);
mesh.add(lines);
}
}
}
}
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
body {
margin: 0px;
}
<script src="https://cdn.jsdelivr.net/npm/three#0.130.1/build/three.min.js"></script>

Related

drag the object group in XY plane only in three.js

The objective is to drag the objects in the scene using mouse. zoom in and zoom out are working properly. while dragging the object is rotated, but not dragged. what is the issue here?
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 20000);
const renderer = new THREE.WebGLRenderer({
canvas: document.querySelector("#grid")
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(400, 400);
scene.background = new THREE.Color(0xffffff);
var controls = new THREE.OrbitControls(camera, renderer.domElement);
for (let i = 0; i < 3; i++) {
const geometry = new THREE.PlaneGeometry(9, 10);
const material = new THREE.MeshBasicMaterial({ color: 0x9c8af5, side: THREE.DoubleSide });
const cube = new THREE.Mesh(geometry, material);
cube.position.x = -i * 10.1;
scene.add(cube);
}
camera.position.set(0, 0, 100);
renderer.render(scene, camera);
render();
function render() {
requestAnimationFrame(render);
renderer.render(scene, camera);
}
<script src="https://threejs.org/build/three.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
<canvas id="grid" style="border: 1px solid black;">
</canvas>
here is a workaround. what have done is that :
created a transparent plane with width and height that of the window.
added all the created cubes to the plane
using the DragControls controls the dragging is enabled for the plane.
now if we drag the plane all the cubes will get dragged at the same unit.
note: if you want just to drag the individual cubes, just change the objects to cube in let controls = new THREE.DragControls(objects, camera, renderer.domElement);. also then we need to place this DragControls code inside the loop after creating the cube.
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 20000);
const renderer = new THREE.WebGLRenderer({
canvas: document.querySelector("#grid")
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(400, 400);
scene.background = new THREE.Color(0xffffff);
var objects = [];
var scenePlane = new THREE.PlaneGeometry( window.innerWidth, window.innerHeight);
const scenePlaneMaterial = new THREE.MeshBasicMaterial( { side: THREE.DoubleSide} );
scenePlaneMaterial.transparent = false;
const plane = new THREE.Mesh( scenePlane, scenePlaneMaterial );
objects.push(plane);
let controls = new THREE.DragControls(objects, camera, renderer.domElement);
for (let i = 0; i < 3; i++) {
const geometry = new THREE.PlaneGeometry(9, 10);
const material = new THREE.MeshBasicMaterial({ color: 0x9c8af5, side: THREE.DoubleSide });
const cube = new THREE.Mesh(geometry, material);
cube.position.x = -i * 10.1;
plane.add(cube);
}
scene.add(plane);
camera.position.set(0, 0, 100);
renderer.render(scene, camera);
render();
function render() {
requestAnimationFrame(render);
renderer.render(scene, camera);
}
<script src="https://threejs.org/build/three.js"></script>
<script src="https://threejs.org/examples/js/controls/DragControls.js"></script>
<canvas id="grid" style="border: 1px solid black;">
</canvas>
You should to take a look at :
https://threejs.org/docs/#examples/en/controls/DragControls
const controls = new DragControls( objects, camera, renderer.domElement );
objects must be an array containing your plane(s) (why did you call it a cube by the way if it's a PlaneGeometry ?).
You could try something like :
let objects = [];
let controls = new THREE.DragControls(objects, camera, renderer.domElement);
for (let i = 0; i < 3; i++) {
const geometry = new THREE.PlaneGeometry(9, 10);
const material = new THREE.MeshBasicMaterial({ color: 0x9c8af5, side: THREE.DoubleSide });
const cube = new THREE.Mesh(geometry, material);
cube.position.x = -i * 10.1;
objects.push(cube);
scene.add(cube);
}
But with your actual code, this will generate 3 plane with 10.1 space between each.

How can I detect the intersection of two sphere objects to avoid overlapping one another?

I am trying to create spheres and assign them a random color at the vertices of the rectangle (It can be other geometrical from like triangles or hexagons and so forth, for simplicity in this example I want to use a rectangle). http://jsfiddle.net/ElmerCC/ja6zL0k1/
let scene, camera, renderer;
let controls;
let widthWindow = window.innerWidth;
let heightWindow = window.innerHeight;
let aspect = widthWindow / heightWindow;
let mouse = new THREE.Vector2();
let raycaster = new THREE.Raycaster();
let intersect;
let elements = [];
let elementsNew = [];
init();
animate();
function init() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(75, aspect, 0.1, 10000);
camera.up.set(0, 0, 1);
camera.position.set(-500, -500, 400);
scene.add(camera);
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(widthWindow, heightWindow);
document.body.appendChild(renderer.domElement);
controls = new THREE.OrbitControls(camera, renderer.domElement);
let p = [];
p[0] = new THREE.Vector3(-100, -100, 0);
p[1] = new THREE.Vector3(100, -100, 0);
p[2] = new THREE.Vector3(100, 100, 0);
p[3] = new THREE.Vector3(-100, 100, 0);
//dibujar los nodos
for (let cont = 0; cont < 4; cont++) {
let obj = drawJoint(p[cont], 10, 0x666666, 0, true);
elements.push(obj);
scene.add(obj);
}
var geometry = new THREE.PlaneGeometry(200, 200);
var material = new THREE.MeshBasicMaterial({
color: 0x666666,
side: THREE.DoubleSide
});
var plane = new THREE.Mesh(geometry, material);
scene.add(plane);
//document.addEventListener("mousemove", moveMouse);
document.addEventListener("mousedown", downMouse);
}
function downMouse(event) {
event.preventDefault();
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
raycaster.setFromCamera(mouse, camera);
let intersected = raycaster.intersectObjects(elements);
if (intersected.length > 0) {
intersect = intersected[0].object;
let center = intersect.position;
let n = drawJoint(center, 15, Math.random() * 0xffffff, 1, true);
elementsNew.push(n);
scene.add(n);
}
}
function animate() {
requestAnimationFrame(animate);
render();
}
function render() {
controls.update();
renderer.render(scene, camera);
}
function drawJoint(
JtCenter,
JtRadius,
Jtcolor,
JtOpacity,
JtTransparency
) {
let JtMaterial = new THREE.MeshBasicMaterial({
color: Jtcolor,
opacity: JtOpacity,
transparent: JtTransparency
});
let JtGeom = new THREE.SphereGeometry(JtRadius, 10, 10);
let Joint = new THREE.Mesh(JtGeom, JtMaterial);
JtGeom .computeBoundingSphere();
Joint.position.copy(JtCenter);
return Joint;
}
How can I detect the intersection of two sphere objects to avoid overlapping one another?
Spheres are the easiest objects for which you can test intersection.
Note that a Sphere is a mathematical representation, and is different than a Mesh with sphere geometry. (You can still get the mathematical bounding sphere of a Mesh with the boundingSphere property.)
Here is how you'd check if two spheres touch/intersect (you can send this function two boundingSphere properties to check other non-sphere objects).
function spheresIntersect(sphere1, sphere1position, sphere2, sphere2position){
return sphere1position.distanceTo(sphere2position) <= (sphere1.radius + sphere2.radius)
}

three js shape from transparent image

Hi I'm trying to create a 3d model with the upper and lower sides of a transparent image shape, and the others of single color (yellow in this example)
var texture = new THREE.TextureLoader().load( 'img.png' );
var img = new THREE.MeshBasicMaterial( { map: texture } );
var geom = new THREE.BoxGeometry(25,25,1);
https://jsfiddle.net/k2aoh7um/
I'd like to get this:
how can I do that?
The only way, that I can imagine how to achieve this, is to use THREE.Shape() and THREE.ExtrudeBufferGeometry():
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(0, 1, 2);
var renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(0x101010);
document.body.appendChild(renderer.domElement);
var controls = new THREE.OrbitControls(camera, renderer.domElement);
var center = new THREE.Vector2();
var starLong = new THREE.Vector2(0, 1);
var starShort = new THREE.Vector2(0, 0.5).rotateAround(center, THREE.Math.degToRad(36));
var angle = THREE.Math.degToRad(72);
var points = [];
for (var i = 0; i < 5; i++) {
points.push(starLong.clone().rotateAround(center, angle * i));
points.push(starShort.clone().rotateAround(center, angle * i));
}
var path = new THREE.Shape(points);
var geom = new THREE.ExtrudeBufferGeometry(path, {
steps: 1,
amount: 0.0625,
bevelEnabled: false
});
geom.rotateX(-Math.PI * 0.5);
var star = new THREE.Mesh(geom, new THREE.MeshBasicMaterial({
color: "orange",
wireframe: true
}));
scene.add(star);
render();
function render() {
requestAnimationFrame(render);
renderer.render(scene, camera);
}
body {
overflow: hidden;
margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/92/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>

three.js pointLight changes from r.67 to r.68

The interaction between pointlight and a plane seems to have changed from r.67 to r.68
I'm trying to learn three.js, going through a book that is a year old.
I've stripped down the tutorial example to just a plane, a cube, and a pointlight and The "Shinyness" effect of the light on the plane goes away when i use r.68, which is the point of the light effect tutorial.
I'm guessing it must have something to do with the material reflectivity of planes now?
I didn't get any clues going through three.js github revision notes or history of the function sourcecode or similar current three.js examples, but my three.js rookie status is probably holding me back from knowing what to look for.
If someone could explain what changed and why it's not working I would love to turn this broken tutorial into a learning experience.
EDITED TO ADD FIDDLE EXAMPLES INSTEAD OF SOURCE
Here is r.68:
http://jsfiddle.net/nnu3qnq8/5/
Here is r.67:
http://jsfiddle.net/nnu3qnq8/4/
Code:
$(function () {
var stats = initStats();
// create a scene, that will hold all our elements such as objects, cameras and lights.
var scene = new THREE.Scene();
// create a camera, which defines where we're looking at.
var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
// create a render and set the size
var renderer = new THREE.WebGLRenderer();
renderer.setClearColorHex(0xEEEEEE, 1.0);
renderer.setSize(window.innerWidth, window.innerHeight);
// create the ground plane
var planeGeometry = new THREE.PlaneGeometry(60, 20, 1, 1);
var planeMaterial = new THREE.MeshLambertMaterial({color: 0xffffff});
var plane = new THREE.Mesh(planeGeometry, planeMaterial);
// rotate and position the plane
plane.rotation.x = -0.5 * Math.PI;
plane.position.x = 15
plane.position.y = 0
plane.position.z = 0
// add the plane to the scene
scene.add(plane);
// create a cube
var cubeGeometry = new THREE.BoxGeometry(4, 4, 4);
var cubeMaterial = new THREE.MeshLambertMaterial({color: 0xff7777});
var cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
cube.castShadow = true;
// position the cube
cube.position.x = -4;
cube.position.y = 3;
cube.position.z = 0;
// add the cube to the scene
scene.add(cube);
// position and point the camera to the center of the scene
camera.position.x = -25;
camera.position.y = 30;
camera.position.z = 25;
camera.lookAt(new THREE.Vector3(10, 0, 0));
// add subtle ambient lighting
var ambiColor = "#0c0c0c";
var ambientLight = new THREE.AmbientLight(ambiColor);
scene.add(ambientLight);
// add spotlight for the shadows
// add spotlight for the shadows
var spotLight = new THREE.SpotLight(0xffffff);
spotLight.position.set(-40, 60, -10);
spotLight.castShadow = true;
// scene.add( spotLight );
var pointColor = "#ccffcc";
var pointLight = new THREE.PointLight(pointColor);
pointLight.distance = 100;
pointLight.position = new THREE.Vector3(3, 5, 3);
scene.add(pointLight);
// add the output of the renderer to the html element
$("#WebGL-output").append(renderer.domElement);
// call the render function
var step = 0;
// used to determine the switch point for the light animation
var invert = 1;
var phase = 0;
var controls = new function () {
this.rotationSpeed = 0.03;
this.ambientColor = ambiColor;
this.pointColor = pointColor;
this.intensity = 1;
this.distance = 100;
}
var gui = new dat.GUI();
gui.addColor(controls, 'ambientColor').onChange(function (e) {
ambientLight.color = new THREE.Color(e);
});
gui.addColor(controls, 'pointColor').onChange(function (e) {
pointLight.color = new THREE.Color(e);
});
gui.add(controls, 'intensity', 0, 3).onChange(function (e) {
pointLight.intensity = e;
});
gui.add(controls, 'distance', 0, 100).onChange(function (e) {
pointLight.distance = e;
});
render();
function render() {
stats.update();
// move the light simulation
if (phase > 2 * Math.PI) {
invert = invert * -1;
phase -= 2 * Math.PI;
} else {
phase += controls.rotationSpeed;
}
pointLight.position.z = +(7 * (Math.sin(phase)));
pointLight.position.x = +(14 * (Math.cos(phase)));
if (invert < 0) {
var pivot = 14;
pointLight.position.x = (invert * (pointLight.position.x - pivot)) + pivot;
}
// render using requestAnimationFrame
requestAnimationFrame(render);
renderer.render(scene, camera);
}
function initStats() {
var stats = new Stats();
stats.setMode(0); // 0: fps, 1: ms
// Align top-left
stats.domElement.style.position = 'absolute';
stats.domElement.style.left = '0px';
stats.domElement.style.top = '0px';
$("#Stats-output").append(stats.domElement);
return stats;
}
});
You are using a pattern that is no longer supported.
pointLight.position = new THREE.Vector3( 3, 5, 3 );
Do not create a new object. Instead do this:
pointLight.position.set( 3, 5, 3 );
three.js r.68

ThreeJS - Intersection of a line and sphere

I have two objects on my scene: a red line and a sphere.
While camera rotating/zooming/moving, I need to check the following:
Does the line intersects with the sphere looking from the current position of the camera (please see images below)? Please use this JS fiddle that creates the scene on the images.
I know how to find the intersection between the current mouse position and objects on the scene (just like this example shows).
But how to do this in my case?
JS Fiddle Code:
/**
* PREPARE SCENE
*/
var mouse = {
x : 0,
y : 0
};
var projector = new THREE.Projector();
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75,
window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.x = -5;
camera.position.y = 5;
camera.position.z = 30;
var renderer = new THREE.WebGLRenderer({ alpha: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var controls = new THREE.TrackballControls(camera,
renderer.domElement);
controls.rotateSpeed = 3.0;
controls.zoomSpeed = 1.5;
controls.panSpeed = 1.0;
controls.staticMoving = true;
var grid = new THREE.GridHelper(20, 5);
scene.add(grid);
/**
* CREATE SPHERE
*/
var sphere = new THREE.Mesh(
new THREE.SphereGeometry(5, 10, 10),
new THREE.MeshNormalMaterial());
sphere.overdraw = true;
scene.add(sphere);
/**
* CREATE LINE
*/
var lineMaterial = new THREE.LineBasicMaterial({
color : 0xFF0000
});
var lineGeometry = new THREE.Geometry();
lineGeometry.vertices.push(new THREE.Vector3(8, 8, 8));
lineGeometry.vertices.push(new THREE.Vector3(8, 8, 20));
var line = new THREE.Line(lineGeometry, lineMaterial);
scene.add(line);
renderer.domElement.addEventListener('mousemove', render, false);
render();
function render(event) {
var mouse = {};
/*
* INTERSECTION
*/
if (event != null) {
//intersection job???
}
controls.update();
renderer.render(scene, camera);
}
So, I found the solution that is pretty simple (of course). See new JS Fiddle that checks intersection of the line and sphere and visualizes the ray for debugging.
The JS Fiddle code:
var camera, controls, scene, renderer;
init();
animate();
render();
function init() {
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 10000);
camera.position.z = 800;
controls = new THREE.TrackballControls(camera);
controls.rotateSpeed = 5.0;
controls.zoomSpeed = 1.2;
controls.panSpeed = 4;
controls.noZoom = false;
controls.noPan = false;
controls.staticMoving = true;
controls.addEventListener('change', render);
// world
scene = new THREE.Scene();
sceneTarget = new THREE.Scene();
var grid = new THREE.GridHelper(500, 50);
scene.add(grid);
/**
* CREATE LINE
*/
var lineMaterial = new THREE.LineBasicMaterial({
color : 0xFF0000
});
var lineGeometry = new THREE.Geometry();
lineGeometry.vertices.push(new THREE.Vector3(100, 200, 100));
lineGeometry.vertices.push(new THREE.Vector3(300, 200, 200));
var line = new THREE.Line(lineGeometry, lineMaterial);
sceneTarget.add(line);
/*
* CREARE SPHERE
*/
var sphere = new THREE.Mesh(new THREE.SphereGeometry(150, 100, 100), new THREE.MeshNormalMaterial());
sphere.overdraw = true;
scene.add(sphere);
// renderer
renderer = new THREE.WebGLRenderer({
alpha: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.autoClear = false;
renderer.setClearColor(0xffffff, 1);
document.body.appendChild(renderer.domElement);
}
function animate() {
requestAnimationFrame(animate);
controls.update();
}
function render() {
renderer.render(scene, camera);
renderer.render(sceneTarget, camera);
intersect();
}
function intersect() {
var direction = new THREE.Vector3(100, 200, 100);
var startPoint = camera.position.clone();
var directionVector = direction.sub( startPoint );
var ray = new THREE.Raycaster(startPoint, directionVector.clone(). normalize());
scene.updateMatrixWorld(); // required, since you haven't rendered yet
var rayIntersects = ray.intersectObjects(scene.children, true);
if (rayIntersects[0]) {
//inersection is found
console.log(rayIntersects[0]);
//visualize the ray for debugging
var material = new THREE.LineBasicMaterial({
color: 0x0000ff
});
var geometry = new THREE.Geometry();
geometry.vertices.push(new THREE.Vector3(ray.ray.origin.x, ray.ray.origin.y, ray.ray.origin.z));
geometry.vertices.push(new THREE.Vector3(100, 200, 100));
var line = new THREE.Line(geometry, material);
sceneTarget.add( line );
}
}

Categories

Resources