Displacement map in three.js - javascript

I'm currently using a black and white image as a bump map for my model. The model is an .obj file with the associated .mtl file for UV mapping. This is the code I use:
// Load material file
var mtlLoader = new THREE.MTLLoader();
mtlLoader.setPath('/models/');
mtlLoader.load('model.mtl', function (materials) {
materials.preload();
// Load obj file
var objLoader = new THREE.OBJLoader();
objLoader.setMaterials(materials);
objLoader.setPath('/models/');
objLoader.load('model.obj', function (group) {
var geometry = group.children[0].geometry;
model = new THREE.Mesh(geometry, otherModel.material.clone());
scene.add(model);
render();
callback();
});
});
At a latter time I add the bump map when I need it:
model.material.bumpMap = new THREE.Texture(canvas);
model.material.bumpScale = 0.8;
model.material.bumpMap.format = THREE.RGBFormat;
model.material.bumpMap.wrapS = mapRingModel.material.bumpMap.wrapT = THREE.RepeatWrapping;
model.material.bumpMap.minFilter = THREE.LinearFilter;
model.material.bumpMap.needsUpdate = true;
model.material.needsUpdate = true;
This works as expected but now I would like to use my texture as a displacement map instead of a bump map so I changed my code to:
model.material.displacementMap = new THREE.Texture(canvas);
model.material.displacementScale = 0.8;
model.material.displacementMap.format = THREE.RGBFormat;
model.material.displacementMap.wrapS = model.material.displacementMap.wrapT = THREE.RepeatWrapping;
model.material.displacementMap.minFilter = THREE.LinearFilter;
model.material.displacementMap.needsUpdate = true;
model.material.needsUpdate = true;
With the same texture applied the displacement is no applied at all. Is there anything I need to change on my UV mapping or texture to work as the bump map but with displacement?

I don't see anything wrong with your code. Are you sure it's not working?
Try upping the value of displacementScale.
While bumpScale is from 0 - 1. DisplacementScale can be anything as it is .. umm...scene scale.
below is an example of both working together with canvas as texture (draw in boxes to see), click "run code snippet"
var camera, scene, renderer, mesh, material, stats;
var drawStartPos = {x:0, y:0};
init();
setupCanvasDrawing();
animate();
function init() {
// Renderer.
renderer = new THREE.WebGLRenderer();
//renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
// Add renderer to page
document.getElementById('threejs-container').appendChild(renderer.domElement);
// Create camera.
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.z = 400;
// Create scene.
scene = new THREE.Scene();
// Create material
material = new THREE.MeshPhongMaterial();
// Create cube and add to scene.
var geometry = new THREE.BoxGeometry(200, 200, 200, 50, 50, 50);
mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
// Create ambient light and add to scene.
var light = new THREE.AmbientLight(0x404040); // soft white light
scene.add(light);
// Create directional light and add to scene.
var directionalLight = new THREE.DirectionalLight(0xffffff);
directionalLight.position.set(1, 1, 1).normalize();
scene.add(directionalLight);
// Add listener for window resize.
window.addEventListener('resize', onWindowResize, false);
// Add stats to page.
stats = new Stats();
document.body.appendChild( stats.dom );
}
function setupCanvasDrawing() {
// get canvas and context
var drawingCanvas = document.getElementById('drawing-canvas');
var drawingCanvas2 = document.getElementById('drawing-canvas-2');
var drawingContext = drawingCanvas.getContext('2d');
var drawingContext2 = drawingCanvas2.getContext('2d');
// draw white background
drawingContext.fillStyle = "#FFFFFF";
drawingContext.fillRect(0,0,128,128);
drawingContext2.fillStyle = "#000000";
drawingContext2.fillRect(0,0,128,128);
// set canvas as bumpmap
material.bumpMap = new THREE.Texture(drawingCanvas);
material.displacementMap = new THREE.Texture(drawingCanvas2);
material.displacementScale = 30;
// set the variable to keep track of when to draw
var paint = false;
var paint2 = false;
// add canvas event listeners
drawingCanvas.addEventListener('mousedown', function(e){
paint = true
drawStartPos = {x:e.offsetX, y:e.offsetY};
});
drawingCanvas.addEventListener('mousemove', function(e){
if(paint){
draw(drawingContext, 0, e.offsetX, e.offsetY);
}
});
drawingCanvas.addEventListener('mouseup', function(e){
paint = false;
});
drawingCanvas.addEventListener('mouseleave', function(e){
paint = false;
});
drawingCanvas2.addEventListener('mousedown', function(e){
paint2 = true
drawStartPos = {x:e.offsetX, y:e.offsetY};
});
drawingCanvas2.addEventListener('mousemove', function(e){
if(paint2){
draw(drawingContext2, 1, e.offsetX, e.offsetY);
}
});
drawingCanvas2.addEventListener('mouseup', function(e){
paint2 = false;
});
drawingCanvas2.addEventListener('mouseleave', function(e){
paint2 = false;
});
}
// Draw function
function draw(drawContext, type, x, y) {
drawContext.moveTo(drawStartPos.x, drawStartPos.y);
if(type){
// is displacement
drawContext.strokeStyle = '#ffffff';
}else{
// is bump
drawContext.strokeStyle = '#000000';
}
drawContext.lineTo(x,y);
drawContext.stroke();
drawStartPos = {x:x, y:y};
material.bumpMap.needsUpdate = true;
material.displacementMap.needsUpdate = true;
}
function animate() {
requestAnimationFrame(animate);
mesh.rotation.x += 0.005;
mesh.rotation.y += 0.01;
renderer.render(scene, camera);
stats.update();
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
body {
padding: 0;
margin: 0;
}
#drawing-canvas {
position: absolute;
background-color: #000;
top: 0px;
right: 0px;
z-index: 3;
}
#drawing-canvas-2 {
position: absolute;
background-color: #000;
top: 128px;
right: 0px;
z-index: 3;
border: solid 1px #ffffff;
}
#threejs-container {
position: absolute;
left: 0px;
top: 0px;
width: 100%;
height: 100%;
z-index: 1;
}
<script src="https://rawgit.com/mrdoob/three.js/r83/build/three.min.js"></script>
<script src="https://cdn.rawgit.com/mrdoob/stats.js/r17/build/stats.min.js"></script>
<canvas id="drawing-canvas" height="128" width="128"></canvas>
<canvas id="drawing-canvas-2" height="128" width="128"></canvas>
<div id="threejs-container"></div>

Related

ThreeJS and PhysiJS "Class constructor cannot be invoked without 'new'

I'm trying to implement PhysiJS to my ThreeJS project.
To simplify I have downloaded this project from the web:
https://rawgit.com/mmmovania/Physijs_Tutorials/master/MultipleBoxes.html
My project setup is available here:
https://drive.google.com/drive/folders/1lO-8YQtWkOPDhsEpk1LzuPajoPjsBnyo?usp=sharing
Problem
When I have downloaded all the files (html, js) I tried to run it.
When it's run from my computer I receive an error.
I'm still very new to JavaScript I kind of understand what the problem is but not sure how to solve it. What am I missing? It's the exact same project on my PC as it is on the web.
Here's the error:
**three.js:34977 THREE.Quaternion: .inverse() has been renamed to invert().
Quaternion.inverse # three.js:34977
physi.js:391 Uncaught TypeError: Class constructor Scene cannot be invoked without 'new'
at new window.Physijs.Physijs.Scene (physi.js:391)
at init (MultipleBoxes.html:71)
at MultipleBoxes.html:51**
Change init() to window.onload = init(); to give the script files a chance to load completely before you init().
'use strict';
var initScene, render, renderer, scene, camera, box, floor;
var container;
var camera, scene, controls, renderer;
var mouseX = 0,
mouseY = 0;
var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;
var clock;
var NUM_BOXES = 10;
// always wait for all scripts to load before doing assignments
window.onload = function() {
init();
animate();
}
function init() {
// initialize your script and set assignments
Physijs.scripts.worker = 'js/physijs_worker.js';
Physijs.scripts.ammo = 'ammo.js';
clock = new THREE.Clock();
container = document.createElement('div');
document.body.appendChild(container);
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 10000);
camera.position.z = 20;
camera.position.y = 5;
controls = new THREE.OrbitControls(camera);
// scene
//scene = new THREE.Scene();
scene = new Physijs.Scene;
scene.setGravity(new THREE.Vector3(0, -10, 0));
//floor
floor = new Physijs.BoxMesh(
new THREE.CubeGeometry(20, 0.1, 20),
new THREE.MeshPhongMaterial({
color: 0xffffff
}),
0 //mass
);
floor.receiveShadow = true;
floor.position.set(0, 0, 0);
scene.add(floor);
var loader = new THREE.ImageLoader(manager);
var crateTexture = new THREE.Texture();
loader.load('textures/crate.jpg', function(image) {
crateTexture.image = image;
crateTexture.needsUpdate = true;
});
// Box
var boxGeometry = new THREE.CubeGeometry(1, 1, 1);
var boxMaterial = new THREE.MeshPhongMaterial({
color: 0xffffff,
map: crateTexture
});
for (var i = 0; i < NUM_BOXES; ++i) {
var box = new Physijs.BoxMesh(boxGeometry, boxMaterial);
box.castShadow = true;
box.position.y = 10 + 2 * i;
scene.add(box);
}
var manager = new THREE.LoadingManager();
manager.onProgress = function(item, loaded, total) {
console.log(item, loaded, total);
};
var ambientLight = new THREE.AmbientLight(0x707070);
scene.add(ambientLight);
var light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(-10, 18, 5);
light.castShadow = true;
var d = 14;
light.shadow.camera.left = -d;
light.shadow.camera.right = d;
light.shadow.camera.top = d;
light.shadow.camera.bottom = -d;
light.shadow.camera.near = 2;
light.shadow.camera.far = 50;
light.shadow.mapSize.x = 1024;
light.shadow.mapSize.y = 1024;
scene.add(light);
//
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
container.appendChild(renderer.domElement);
container.appendChild(renderer.domElement);
document.addEventListener('mousemove', onDocumentMouseMove, false);
window.addEventListener('resize', onWindowResize, false);
}
function onWindowResize() {
windowHalfX = window.innerWidth / 2;
windowHalfY = window.innerHeight / 2;
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
function onDocumentMouseMove(event) {
mouseX = (event.clientX - windowHalfX) / 2;
mouseY = (event.clientY - windowHalfY) / 2;
}
//
function animate() {
requestAnimationFrame(animate);
render();
}
function render() {
var deltaTime = clock.getDelta();
controls.update(deltaTime);
scene.simulate(); // run physics
camera.lookAt(scene.position);
renderer.render(scene, camera);
}
body {
font-family: Monospace;
background-color: #000;
color: #fff;
margin: 0px;
overflow: hidden;
}
#info {
color: #fff;
position: absolute;
top: 10px;
width: 100%;
text-align: center;
z-index: 100;
display: block;
}
#info a,
.button {
color: #f00;
font-weight: bold;
text-decoration: underline;
cursor: pointer
}
<!DOCTYPE html>
<html lang="en">
<head>
<title>Physijs + THREE.js = Multiple Boxes Demo</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<style>
/* moved to separate box for stackoverflow answer
(see CSS box)
*/
</style>
</head>
<body>
<script src="js/three.js"></script>
<script type="text/javascript" src="js/physi.js"></script>
<script src="js/controls/OrbitControls.js"></script>
<script>
/* moved to javascript box */
</script>
</body>
</html>

Render Multiple Boxes together in THREE.js

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>

THREE.js TrackballControls how to change center of rotation not to be in center of canvas?

I'm using TrackballControls in THREE.js. Center of rotation is always in center of canvas. How can I move center of rotation up? This is what I tried:
Move scene up (scene.translateY(1)) - not good, center of rotation is still in center of canvas
Move camera up (camera.position.y = 1) - not good, I am looking "up" but center of rotation is still at center of canvas
Change controls target (controls.target.y = 1) - not good, the whole scene just rotated so that target is in center of canvas.
window.addEventListener("DOMContentLoaded", function () {
var scene, camera, renderer, controls, sphere, red, blue, black;
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 3;
renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
geometry = new THREE.SphereGeometry(0.1);
material = new THREE.MeshBasicMaterial({
color: 0xff0000
});
sphere1 = new THREE.Mesh(geometry, material);
scene.add(sphere1);
geometry = new THREE.SphereGeometry(0.1);
material = new THREE.MeshBasicMaterial({
color: 0x00ff00
});
sphere2 = new THREE.Mesh(geometry, material);
scene.add(sphere2);
sphere2.position.x = 1;
geometry = new THREE.SphereGeometry(0.1);
material = new THREE.MeshBasicMaterial({
color: 0x0000ff
});
sphere3 = new THREE.Mesh(geometry, material);
scene.add(sphere3);
sphere3.position.y = 1;
controls = new THREE.TrackballControls(camera, renderer.domElement);
function loop() {
controls.update();
renderer.render(scene, camera);
requestAnimationFrame(loop);
}
// camera.position.y = 1;
// controls.target.y = 1;
// scene.position.y = 1;
loop();
})
canvas {
box-sizing: border-box;
border: 1px solid red;
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
<script src="https://rawgit.com/mrdoob/three.js/master/build/three.min.js"></script>
<script src="https://rawgit.com/mrdoob/three.js/master/examples/js/controls/TrackballControls.js"></script>
I want to rotate around red sphere and I want red sphere to be not in center of canvas but in upper third.
What you're describing is kind of complicated mathematically because the camera always "looks at" the target, which means it's always going to be in the center. You also can't just rotate the camera to look down a few degrees because TrackballControls rotates around the z-axis, which makes it harder to figure out where "down" is.
Maybe you could change the viewport of the renderer with renderer.setViewport()? This squeezes the scene into the dimensions you give it, so you can position it more accurately wherever you want. In the demo below, I'm rendering the scene 2 times, one taking up the full screen, the second time only 200px tall with this code:
// First render takes up the full screen
renderer.setViewport(0, 0, window.innerWidth, window.innerHeight);
renderer.render(scene, camera);
// Second render is only 100px tall
renderer.setViewport(0, 0, 100 * ratio, 100);
renderer.render(scene, camera);
if this approach works for you, make sure you set renderer.autoClear = false; so it doesn't clear the canvas on each render() call.
window.addEventListener("DOMContentLoaded", function () {
var scene, camera, renderer, controls, sphere, red, blue, black;
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 3;
renderer = new THREE.WebGLRenderer();
renderer.autoClear = false;
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
geometry = new THREE.SphereGeometry(0.1);
material = new THREE.MeshBasicMaterial({
color: 0xff0000
});
sphere1 = new THREE.Mesh(geometry, material);
scene.add(sphere1);
geometry = new THREE.SphereGeometry(0.1);
material = new THREE.MeshBasicMaterial({
color: 0x00ff00
});
sphere2 = new THREE.Mesh(geometry, material);
scene.add(sphere2);
sphere2.position.x = 1;
geometry = new THREE.SphereGeometry(0.1);
material = new THREE.MeshBasicMaterial({
color: 0x0000ff
});
sphere3 = new THREE.Mesh(geometry, material);
scene.add(sphere3);
sphere3.position.y = 1;
controls = new THREE.TrackballControls(camera, renderer.domElement);
var ratio = window.innerWidth / window.innerHeight;
function loop() {
controls.update();
// First render takes up the full screen
renderer.setViewport(0, 0, window.innerWidth, window.innerHeight);
renderer.render(scene, camera);
// Second render is only 100px tall
renderer.setViewport(0, 0, 100 * ratio, 100);
renderer.render(scene, camera);
requestAnimationFrame(loop);
}
// camera.position.y = 1;
// controls.target.y = 1;
// scene.position.y = 1;
loop();
})
canvas {
box-sizing: border-box;
border: 1px solid red;
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
<script src="https://rawgit.com/mrdoob/three.js/master/build/three.min.js"></script>
<script src="https://rawgit.com/mrdoob/three.js/master/examples/js/controls/TrackballControls.js"></script>

Importing Blender obj file with mtl to ThreeJS

I am trying to import an object file that I created in Blender to ThreeJS. My Blender project looks like this:
image
I exported it into a waveform, for importing into ThreeJS I used MTLLoader and OBJLoader, here is my code:
<script>
var container;
var camera, controls, scene, renderer, dragControls;
var lighting, ambient, keyLight, fillLight, backLight;
var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;
var keyboard = {};
var floor;
var objects = [];
var meshes = [];
var cameraParams = {speed: 0.1, turnSpeed: Math.PI * 0.5};
var raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector2(1, 1), INTERSECTED;
init();
animate();
function init() {
container = document.createElement('div');
document.body.appendChild(container);
camera = new THREE.PerspectiveCamera(45, window.innerWidth/window.innerHeight, 0.1, 1000);
camera.position.set(0, 7, 25);
scene = new THREE.Scene();
ambient = new THREE.AmbientLight(0xffffff, 1.0);
scene.add(ambient);
keyLight = new THREE.DirectionalLight(new THREE.Color('hsl(30, 100%, 75%)'), 1.0);
keyLight.position.set(-100, 0, 100);
fillLight = new THREE.DirectionalLight(new THREE.Color('hsl(240, 100%, 75%)'), 0.75);
fillLight.position.set(100, 0, 100);
backLight = new THREE.DirectionalLight(0xffffff, 1.0);
backLight.position.set(100, 0, -100).normalize();
scene.add(keyLight);
scene.add(fillLight);
scene.add(backLight);
// load model
loadMesh('road', function(obj){
obj.position.y = 0;
obj.scale.x = 1;
obj.scale.y = 1;
obj.scale.z = 1;
addMesh(obj);
});
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(new THREE.Color('hsl(0, 0%, 10%)'));
container.appendChild(renderer.domElement);
controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.25;
controls.enableZoom = false;
dragControls = new THREE.DragControls(objects, camera, renderer.domElement);
dragControls.addEventListener('dragstart', function (event) {
event.object.material.emissive.set(0xaaaaaa);
controls.enabled = false;
});
dragControls.addEventListener('dragend', function (event) {
event.object.material.emissive.set(0x000000);
controls.enabled = true;
});
window.addEventListener('resize', onWindowResize, false);
window.addEventListener('keydown', keyDownEvent, false);
window.addEventListener('keyup', keyUpEvent, false);
window.addEventListener('mousemove', onMouseMove, false);
}
function addMesh(mesh) {
meshes.push(mesh);
scene.add(mesh);
}
function loadMesh(name, callback) {
var objLoader = new THREE.OBJLoader();
var matLoader = new THREE.MTLLoader();
matLoader.setPath('assets/');
matLoader.load('ROAD2.mtl', function(materials) {
materials.preload();
objLoader.setMaterials(materials);
objLoader.setPath('assets/');
objLoader.load('ROAD2.obj', function (obj) {
callback(obj);
});
});
}
function onWindowResize() {
camera.aspect = window.innerWidth/window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
function keyDownEvent(event) {
keyboard[event.keyCode] = true;
}
function keyUpEvent(event) {
keyboard[event.keyCode] = false;
}
function onMouseMove(event) {
event.preventDefault();
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
}
function animate() {
requestAnimationFrame(animate);
if (keyboard[37]) { // left arrow key
camera.rotation.y += cameraParams.turnSpeed;
}
if (keyboard[39]) { // right arrow key
camera.rotation.y -= cameraParams.turnSpeed;
}
controls.update();
render();
}
function render() {
renderer.render(scene, camera);
}
</script>
My Blender scene rarely loads in my browser, when it does, it is without any textures. Most of the time my tab crashes before anything is able to load in because is eats up all my RAM (using Firefox and http-server to load the html). I am out of ideas about what the problem is, haven't been able to find anything on Google, most of the examples were of one object with materials and textures.
My file hierarchy looks like this in case it is important:
index.html
js/
DragControls1.js
MTLLoader.js
OBJLoader.js
OrbitControls.js
three.js
assets/
ROAD2.mtl
ROAD2.obj
cottage_textures.png
road_texture.png
Any help would be appreciated.
It seems that your scene has about 7'000'000 vertices, which is not a little but a little too much.
In Blender, try to do the export in several smaller objects. For example each one separately, the street, a tree, one of the houses, etc.
With this method, you can approach the limit of your scene.
Also, try to duplicate multiple objects in your scene in the code instead of doing it in Blender!
(In realtime 3D applications you should always try to use optimal 3D models (geometry, topology) and not oversized models with several million vertices)

Threejs drag points

I have to generate a huge number of objects that I can drag individually. Also these objects are limited to a plane form (e.g. rect or circle).
At first I worked with simple CircleGeometries, that are placed inside another geometrie (plane). Also dragging them is very easy but as expected the performance is very very poor for about 200000 of them.
I then decided to use points /particleSystem. The positioning inside a plane works very well but I can't get it managed to make the individual points of the particle system draggable. I found the interactive particles example in the threejs documentation but still have no clou, how to combine them with dragcontrols.
This is my code for creating the particle system and fill a plane with these points:
//Create a plane geometrie, that is later filled with points
var geometry2 = new THREE.CircleGeometry(30,32);
var material2 = new THREE.MeshBasicMaterial( {color: 0x666666, side: THREE.DoubleSide, wireframe:true} );
var mat1 = new THREE.MeshBasicMaterial( {color: 0x00ff00, wireframe:false} );
var plane1 = new THREE.Mesh(geometry2, material2);
geometries.push(plane1); //push to object for draggable elements
scene.add(plane1);
var positionsX;
positionsX = inGeometry.inGeometry(plane1.geometry, 200000); // get positions for points inside plane1
var geometry = new THREE.Geometry();
for (var i = 0; i < positionsX.length; i++) {
geometry.vertices.push(positionsX[i]); //add positions to vertices
}
console.log(geometry);
//Create Particle system
var material = new THREE.PointsMaterial({ size:0.02, color: 0xffffff });
particleSystem = new THREE.Points(geometry, material);
scene.add(particleSystem);
console.log(particleSystem);
var dragGeo = new DragControls(geometries, camera, container); //dragging
Can anybody please help?
Thanks
Just a rough example of how you can drag points:
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(1.25, 7, 7);
camera.lookAt(scene.position);
var renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var geometry = new THREE.PlaneBufferGeometry(10, 10, 10, 10);
geometry.rotateX(-Math.PI * 0.5);
var plane = new THREE.Mesh(geometry, new THREE.MeshBasicMaterial({
wireframe: true,
color: "red"
}));
scene.add(plane);
var points = new THREE.Points(geometry, new THREE.PointsMaterial({
size: 0.25,
color: "yellow"
}));
scene.add(points);
var raycaster = new THREE.Raycaster();
raycaster.params.Points.threshold = 0.25;
var mouse = new THREE.Vector2();
var intersects = null;
var plane = new THREE.Plane();
var planeNormal = new THREE.Vector3();
var currentIndex = null;
var planePoint = new THREE.Vector3();
var dragging = false;
window.addEventListener("mousedown", mouseDown, false);
window.addEventListener("mousemove", mouseMove, false);
window.addEventListener("mouseup", mouseUp, false);
function mouseDown(event) {
setRaycaster(event);
getIndex();
dragging = true;
}
function mouseMove(event) {
if (dragging && currentIndex !== null) {
setRaycaster(event);
raycaster.ray.intersectPlane(plane, planePoint);
geometry.attributes.position.setXYZ(currentIndex, planePoint.x, planePoint.y, planePoint.z);
geometry.attributes.position.needsUpdate = true;
}
}
function mouseUp(event) {
dragging = false;
currentIndex = null;
}
function getIndex() {
intersects = raycaster.intersectObject(points);
if (intersects.length === 0) {
currentIndex = null;
return;
}
currentIndex = intersects[0].index;
setPlane(intersects[0].point);
}
function setPlane(point) {
planeNormal.subVectors(camera.position, point).normalize();
plane.setFromNormalAndCoplanarPoint(planeNormal, point);
}
function setRaycaster(event) {
getMouse(event);
raycaster.setFromCamera(mouse, camera);
}
function getMouse(event) {
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
}
render();
function render() {
requestAnimationFrame(render);
renderer.render(scene, camera);
}
body {
overflow: hidden;
margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/91/three.min.js"></script>

Categories

Resources