THREE.JS | Delaunator.JS THREE.BufferGeometry UV mapping - three.js

That's really weird, but I couldn't find any solution for uv mapping Delaunator.JS outputs.
Let's say I have a very basic set of points defined by:
for(var z = -512; z <= 512; z += 256){
for(var x = -512; x <= 512; x += 256){
points.push(new THREE.Vector3(x, 0, z));
}
}
points.push(new THREE.Vector3(512, 0, -384));
points.push(new THREE.Vector3(128, 0, 512));
points.push(new THREE.Vector3(384, 0, 512));
While, subdivision points go after, I need to process these points through Delaunator.JS in order to to build be able to generate a THREE.BufferGeometry plane.
Them I'm trying to generate UV map by:
for(var i = 0; i < indexDelaunay.triangles.length; i += 3){
var a = new THREE.Vector3(points[indexDelaunay.triangles[i]].x, points[indexDelaunay.triangles[i]].y, points[indexDelaunay.triangles[i]].z);
var b = new THREE.Vector3(points[indexDelaunay.triangles[i + 2]].x, points[indexDelaunay.triangles[i + 1]].y, points[indexDelaunay.triangles[i + 1]].z);
var c = new THREE.Vector3(points[indexDelaunay.triangles[i + 1]].x, points[indexDelaunay.triangles[i + 2]].y, points[indexDelaunay.triangles[i + 2]].z);
a.x = remapFloat(a.x, -512, 512, 0, 1);
a.z = remapFloat(a.z, -512, 512, 1, 0);
b.x = remapFloat(b.x, -512, 512, 0, 1);
b.z = remapFloat(b.z, -512, 512, 1, 0);
c.x = remapFloat(c.x, -512, 512, 0, 1);
c.z = remapFloat(c.z, -512, 512, 1, 0);
var mm = {min: {x: Number.POSITIVE_INFINITY, z: Number.POSITIVE_INFINITY}, max: {x: Number.NEGATIVE_INFINITY, z: Number.NEGATIVE_INFINITY} }
mm.min.x = Math.min(mm.min.x, a.x, b.x, c.x);
mm.min.z = Math.min(mm.min.z, a.z, b.z, c.z);
mm.max.x = Math.max(mm.max.x, a.x, b.x, c.x);
mm.max.z = Math.max(mm.max.z, a.z, b.z, c.z);
quad_uvs.push(mm.min.x, mm.min.z, mm.max.x, mm.max.z);
}
uvs = new Float32Array(quad_uvs);
geometry.setAttribute( 'uv', new THREE.BufferAttribute( uvs, 2 ) );
The output is glitchy, meaning that I'm doing something wrong:
The output should be like this:
The code is attached.
var texture = "data:image/jpeg;base64,/9j/4QSsRXhpZgAATU0AKgAAAAgABwESAAMAAAABAAEAAAEaAAUAAAABAAAAYgEbAAUAAAABAAAAagEoAAMAAAABAAIAAAExAAIAAAAfAAAAcgEyAAIAAAAUAAAAkYdpAAQAAAABAAAAqAAAANQACvyAAAAnEAAK/IAAACcQQWRvYmUgUGhvdG9zaG9wIDIxLjEgKFdpbmRvd3MpADIwMjA6MDg6MjMgMTc6NTM6MjMAAAAAAAOgAQADAAAAAQABAACgAgAEAAAAAQAAAICgAwAEAAAAAQAAAIAAAAAAAAAABgEDAAMAAAABAAYAAAEaAAUAAAABAAABIgEbAAUAAAABAAABKgEoAAMAAAABAAIAAAIBAAQAAAABAAABMgICAAQAAAABAAADcgAAAAAAAABIAAAAAQAAAEgAAAAB/9j/7QAMQWRvYmVfQ00AAf/uAA5BZG9iZQBkgAAAAAH/2wCEAAwICAgJCAwJCQwRCwoLERUPDAwPFRgTExUTExgRDAwMDAwMEQwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwBDQsLDQ4NEA4OEBQODg4UFA4ODg4UEQwMDAwMEREMDAwMDAwRDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDP/AABEIAIAAgAMBIgACEQEDEQH/3QAEAAj/xAE/AAABBQEBAQEBAQAAAAAAAAADAAECBAUGBwgJCgsBAAEFAQEBAQEBAAAAAAAAAAEAAgMEBQYHCAkKCxAAAQQBAwIEAgUHBggFAwwzAQACEQMEIRIxBUFRYRMicYEyBhSRobFCIyQVUsFiMzRygtFDByWSU/Dh8WNzNRaisoMmRJNUZEXCo3Q2F9JV4mXys4TD03Xj80YnlKSFtJXE1OT0pbXF1eX1VmZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3EQACAgECBAQDBAUGBwcGBTUBAAIRAyExEgRBUWFxIhMFMoGRFKGxQiPBUtHwMyRi4XKCkkNTFWNzNPElBhaisoMHJjXC0kSTVKMXZEVVNnRl4vKzhMPTdePzRpSkhbSVxNTk9KW1xdXl9VZmdoaWprbG1ub2JzdHV2d3h5ent8f/2gAMAwEAAhEDEQA/AKCSSS7R9CUkkkkp9BSSSXFvnqkkkklN9JJJeYN1SSSSSmgkkkvT2kpJJJJT/9Cgkkku0fQlJJJJKfQUkklxb56pJJJJTfSSSXmDdUkkkkpoJJJL09pKSSSSU//R7JJJJJSkkkklOekkktp8wUkkkkp0Ekklivp6kkkklPgKSSSSlJJJJKf/0uySSSSUpJJJJTnpJJLafMFJJJJKdBJJJYr6epJJJJT4CkkkkpSSSSSn/9Ogkkku0fQlJJJJKfQUkklxb56pJJJJTfSSSXmDdUkkkkpoJJJL09pKSSSSU//UoJJJLtH0JSSSSSn0FJJJcW+eqSSSSU30kkl5g3VJJJJKaCSSS9PaSkkkklP/1eySSSSUpJJJJTnpJJLafMFJJJJKdBJJJYr6epJJJJT4CkkkkpSSSSSn/9bskkkklKSSSSU56SSS2nzBSSSSSnQSSSWK+nqSSSSU+ApJJJKUkkkkp//Z/+0M6lBob3Rvc2hvcCAzLjAAOEJJTQQlAAAAAAAQAAAAAAAAAAAAAAAAAAAAADhCSU0EOgAAAAABFQAAABAAAAABAAAAAAALcHJpbnRPdXRwdXQAAAAFAAAAAFBzdFNib29sAQAAAABJbnRlZW51bQAAAABJbnRlAAAAAENscm0AAAAPcHJpbnRTaXh0ZWVuQml0Ym9vbAAAAAALcHJpbnRlck5hbWVURVhUAAAAGQBCAHIAbwB0AGgAZQByACAASABMAC0ANQAyADUAMABEAE4AIABzAGUAcgBpAGUAcwAAAAAAD3ByaW50UHJvb2ZTZXR1cE9iamMAAAAMAFAAcgBvAG8AZgAgAFMAZQB0AHUAcAAAAAAACnByb29mU2V0dXAAAAABAAAAAEJsdG5lbnVtAAAADGJ1aWx0aW5Qcm9vZgAAAAlwcm9vZkNNWUsAOEJJTQQ7AAAAAAItAAAAEAAAAAEAAAAAABJwcmludE91dHB1dE9wdGlvbnMAAAAXAAAAAENwdG5ib29sAAAAAABDbGJyYm9vbAAAAAAAUmdzTWJvb2wAAAAAAENybkNib29sAAAAAABDbnRDYm9vbAAAAAAATGJsc2Jvb2wAAAAAAE5ndHZib29sAAAAAABFbWxEYm9vbAAAAAAASW50cmJvb2wAAAAAAEJja2dPYmpjAAAAAQAAAAAAAFJHQkMAAAADAAAAAFJkICBkb3ViQG/gAAAAAAAAAAAAR3JuIGRvdWJAb+AAAAAAAAAAAABCbCAgZG91YkBv4AAAAAAAAAAAAEJyZFRVbnRGI1JsdAAAAAAAAAAAAAAAAEJsZCBVbnRGI1JsdAAAAAAAAAAAAAAAAFJzbHRVbnRGI1B4bEBSAAAAAAAAAAAACnZlY3RvckRhdGFib29sAQAAAABQZ1BzZW51bQAAAABQZ1BzAAAAAFBnUEMAAAAATGVmdFVudEYjUmx0AAAAAAAAAAAAAAAAVG9wIFVudEYjUmx0AAAAAAAAAAAAAAAAU2NsIFVudEYjUHJjQFkAAAAAAAAAAAAQY3JvcFdoZW5QcmludGluZ2Jvb2wAAAAADmNyb3BSZWN0Qm90dG9tbG9uZwAAAAAAAAAMY3JvcFJlY3RMZWZ0bG9uZwAAAAAAAAANY3JvcFJlY3RSaWdodGxvbmcAAAAAAAAAC2Nyb3BSZWN0VG9wbG9uZwAAAAAAOEJJTQPtAAAAAAAQAEgAAAABAAIASAAAAAEAAjhCSU0EJgAAAAAADgAAAAAAAAAAAAA/gAAAOEJJTQQNAAAAAAAEAAAAWjhCSU0EGQAAAAAABAAAAB44QklNA/MAAAAAAAkAAAAAAAAAAAEAOEJJTScQAAAAAAAKAAEAAAAAAAAAAjhCSU0D9QAAAAAASAAvZmYAAQBsZmYABgAAAAAAAQAvZmYAAQChmZoABgAAAAAAAQAyAAAAAQBaAAAABgAAAAAAAQA1AAAAAQAtAAAABgAAAAAAAThCSU0D+AAAAAAAcAAA/////////////////////////////wPoAAAAAP////////////////////////////8D6AAAAAD/////////////////////////////A+gAAAAA/////////////////////////////wPoAAA4QklNBAAAAAAAAAIAADhCSU0EAgAAAAAAEgAAAAAAAAAAAAAAAAAAAAAAADhCSU0EMAAAAAAACQEBAQEBAQEBAQA4QklNBC0AAAAAAAYAAQAAAAE4QklNBAgAAAAAABAAAAABAAACQAAAAkAAAAAAOEJJTQQeAAAAAAAEAAAAADhCSU0EGgAAAAADSQAAAAYAAAAAAAAAAAAAAIAAAACAAAAACgBVAG4AdABpAHQAbABlAGQALQAxAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAACAAAAAgAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAA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AAUBAQABAQD/4Q37aHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/PiA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJBZG9iZSBYTVAgQ29yZSA2LjAtYzAwMiA3OS4xNjQzNjAsIDIwMjAvMDIvMTMtMDE6MDc6MjIgICAgICAgICI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0RXZ0PSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VFdmVudCMiIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bXA6Q3JlYXRvclRvb2w9IkFkb2JlIFBob3Rvc2hvcCAyMS4xIChXaW5kb3dzKSIgeG1wOkNyZWF0ZURhdGU9IjIwMjAtMDgtMjNUMTc6NTM6MjMrMDM6MDAiIHhtcDpNZXRhZGF0YURhdGU9IjIwMjAtMDgtMjNUMTc6NTM6MjMrMDM6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDIwLTA4LTIzVDE3OjUzOjIzKzAzOjAwIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjkxMDFhNmY5LWE4NTEtNDQ0NS04MDE5LWNkODFhY2NmNTBkMiIgeG1wTU06RG9jdW1lbnRJRD0iYWRvYmU6ZG9jaWQ6cGhvdG9zaG9wOjdmMDY3NDAyLWFlNjgtYmI0Yi05YzYyLTIzYTQ4OThmNWRlYyIgeG1wTU06T3JpZ2luYWxEb2N1bWVudElEPSJ4bXAuZGlkOjE3MzdmMWE2LWM2MWItZGQ0Ni1hNzdlLTcwZWM4YTlhZWE2NiIgZGM6Zm9ybWF0PSJpbWFnZS9qcGVnIiBwaG90b3Nob3A6Q29sb3JNb2RlPSIzIiBwaG90b3Nob3A6SUNDUHJvZmlsZT0ic1JHQiBJRUM2MTk2Ni0yLjEiPiA8eG1wTU06SGlzdG9yeT4gPHJkZjpTZXE+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJjcmVhdGVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOjE3MzdmMWE2LWM2MWItZGQ0Ni1hNzdlLTcwZWM4YTlhZWE2NiIgc3RFdnQ6d2hlbj0iMjAyMC0wOC0yM1QxNzo1MzoyMyswMzowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIDIxLjEgKFdpbmRvd3MpIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJzYXZlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDo5MTAxYTZmOS1hODUxLTQ0NDUtODAxOS1jZDgxYWNjZjUwZDIiIHN0RXZ0OndoZW49IjIwMjAtMDgtMjNUMTc6NTM6MjMrMDM6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCAyMS4xIChXaW5kb3dzKSIgc3RFdnQ6Y2hhbmdlZD0iLyIvPiA8L3JkZjpTZXE+IDwveG1wTU06SGlzdG9yeT4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPD94cGFja2V0IGVuZD0idyI/Pv/iDFhJQ0NfUFJP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";
var renderer, scene, camera, controls, loader, terrain, glsl, uniforms, root, tree;
renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(0xDEDEDE);
document.body.appendChild(renderer.domElement);
scene = new THREE.Scene();
loader = new THREE.TextureLoader();
loader.crossOrigin = "";
camera = new THREE.PerspectiveCamera(35, window.innerWidth / window.innerHeight, 1, 51200);
camera.position.set(-3072, 2048, -3072);
controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.05;
controls.screenSpacePanning = false;
controls.minDistance = 8;
controls.maxDistance = 10240;
controls.maxPolarAngle = Math.PI / 2;
//simple pseudo quadtree
var points = [], indices = [], quad_uvs = [], groups = [], materials = [];
for(var z = -512; z <= 512; z += 256){
for(var x = -512; x <= 512; x += 256){
points.push(new THREE.Vector3(x, 0, z));
}
}
points.push(new THREE.Vector3(512, 0, -384));
points.push(new THREE.Vector3(128, 0, 512));
points.push(new THREE.Vector3(384, 0, 512));
//delaunay
var geometry = new THREE.BufferGeometry().setFromPoints(points);
var indexDelaunay = Delaunator.from(points.map(v => { return [v.x, v.z]; }) );
var meshIndex = [], quad_uvs = [];
for(var i = 0; i < indexDelaunay.triangles.length; i++){ meshIndex.push(indexDelaunay.triangles[i]); }
for(var i = 0; i < indexDelaunay.triangles.length; i += 3){
var a = new THREE.Vector3(points[indexDelaunay.triangles[i]].x, points[indexDelaunay.triangles[i]].y, points[indexDelaunay.triangles[i]].z);
var b = new THREE.Vector3(points[indexDelaunay.triangles[i + 2]].x, points[indexDelaunay.triangles[i + 1]].y, points[indexDelaunay.triangles[i + 1]].z);
var c = new THREE.Vector3(points[indexDelaunay.triangles[i + 1]].x, points[indexDelaunay.triangles[i + 2]].y, points[indexDelaunay.triangles[i + 2]].z);
a.x = remapFloat(a.x, -512, 512, 0, 1);
a.z = remapFloat(a.z, -512, 512, 1, 0);
b.x = remapFloat(b.x, -512, 512, 0, 1);
b.z = remapFloat(b.z, -512, 512, 1, 0);
c.x = remapFloat(c.x, -512, 512, 0, 1);
c.z = remapFloat(c.z, -512, 512, 1, 0);
var mm = {min: {x: Number.POSITIVE_INFINITY, z: Number.POSITIVE_INFINITY}, max: {x: Number.NEGATIVE_INFINITY, z: Number.NEGATIVE_INFINITY} }
mm.min.x = Math.min(mm.min.x, a.x, b.x, c.x);
mm.min.z = Math.min(mm.min.z, a.z, b.z, c.z);
mm.max.x = Math.max(mm.max.x, a.x, b.x, c.x);
mm.max.z = Math.max(mm.max.z, a.z, b.z, c.z);
quad_uvs.push(mm.min.x, mm.min.z, mm.max.x, mm.max.z);
}
uvs = new Float32Array(quad_uvs);
geometry.setAttribute( 'uv', new THREE.BufferAttribute( uvs, 2 ) );
geometry.setIndex(meshIndex);
geometry.computeVertexNormals();
var plane = new THREE.Mesh(geometry, new THREE.MeshBasicMaterial({ map: new THREE.TextureLoader().load(texture)}));
scene.add(plane);
animate();
function animate(){
controls.update();
renderer.render(scene, camera);
requestAnimationFrame(animate);
}
function remapFloat(v_, min0_, max0_, min1_, max1_) { return min1_ + (v_ - min0_) / (max0_ - min0_) * (max1_ - min1_); }
body { margin: 0; }
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>GLSL Intersection</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<script src="https://unpkg.com/three#0.116.0/build/three.min.js"></script>
<script src="https://unpkg.com/three#0.116.0/examples/js/controls/OrbitControls.js"></script>
<script src="https://cdn.jsdelivr.net/npm/delaunator#4.0.1/delaunator.min.js"></script>
</head>
<body>
</body>
</html>

I was wrong by generating quad_uvs via triangles. The solution is simpler.
for(var j = 0; j < points.length; j++){
var qx = remapFloat(points[j].x, -512, 512, 1, 0);
var qz = remapFloat(points[j].z, -512, 512, 0, 1);
quad_uvs.push(...[qx, qz]);
}
var texture = "data:image/jpeg;base64,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bnRGI1JsdAAAAAAAAAAAAAAAAEJsZCBVbnRGI1JsdAAAAAAAAAAAAAAAAFJzbHRVbnRGI1B4bEBSAAAAAAAAAAAACnZlY3RvckRhdGFib29sAQAAAABQZ1BzZW51bQAAAABQZ1BzAAAAAFBnUEMAAAAATGVmdFVudEYjUmx0AAAAAAAAAAAAAAAAVG9wIFVudEYjUmx0AAAAAAAAAAAAAAAAU2NsIFVudEYjUHJjQFkAAAAAAAAAAAAQY3JvcFdoZW5QcmludGluZ2Jvb2wAAAAADmNyb3BSZWN0Qm90dG9tbG9uZwAAAAAAAAAMY3JvcFJlY3RMZWZ0bG9uZwAAAAAAAAANY3JvcFJlY3RSaWdodGxvbmcAAAAAAAAAC2Nyb3BSZWN0VG9wbG9uZwAAAAAAOEJJTQPtAAAAAAAQAEgAAAABAAIASAAAAAEAAjhCSU0EJgAAAAAADgAAAAAAAAAAAAA/gAAAOEJJTQQNAAAAAAAEAAAAWjhCSU0EGQAAAAAABAAAAB44QklNA/MAAAAAAAkAAAAAAAAAAAEAOEJJTScQAAAAAAAKAAEAAAAAAAAAAjhCSU0D9QAAAAAASAAvZmYAAQBsZmYABgAAAAAAAQAvZmYAAQChmZoABgAAAAAAAQAyAAAAAQBaAAAABgAAAAAAAQA1AAAAAQAtAAAABgAAAAAAAThCSU0D+AAAAAAAcAAA/////////////////////////////wPoAAAAAP////////////////////////////8D6AAAAAD/////////////////////////////A+gAAAAA/////////////////////////////wPoAAA4QklNBAAAAAAAAAIAADhCSU0EAgAAAAAAEgAAAAAAAAAAAAAAAAAAAAAAADhCSU0EMAAAAAAACQEBAQEBAQEBAQA4QklNBC0AAAAAAAYAAQAAAAE4QklNBAgAAAAAABAAAAABAAACQAAAAkAAAAAAOEJJTQQeAAAAAAAEAAAAADhCSU0EGgAAAAADSQAAAAYAAAAAAAAAAAAAAIAAAACAAAAACgBVAG4AdABpAHQAbABlAGQALQAxAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAACAAAAAgAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAA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AAUBAQABAQD/4Q37aHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/PiA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJBZG9iZSBYTVAgQ29yZSA2LjAtYzAwMiA3OS4xNjQzNjAsIDIwMjAvMDIvMTMtMDE6MDc6MjIgICAgICAgICI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0RXZ0PSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VFdmVudCMiIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bXA6Q3JlYXRvclRvb2w9IkFkb2JlIFBob3Rvc2hvcCAyMS4xIChXaW5kb3dzKSIgeG1wOkNyZWF0ZURhdGU9IjIwMjAtMDgtMjNUMTc6NTM6MjMrMDM6MDAiIHhtcDpNZXRhZGF0YURhdGU9IjIwMjAtMDgtMjNUMTc6NTM6MjMrMDM6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDIwLTA4LTIzVDE3OjUzOjIzKzAzOjAwIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjkxMDFhNmY5LWE4NTEtNDQ0NS04MDE5LWNkODFhY2NmNTBkMiIgeG1wTU06RG9jdW1lbnRJRD0iYWRvYmU6ZG9jaWQ6cGhvdG9zaG9wOjdmMDY3NDAyLWFlNjgtYmI0Yi05YzYyLTIzYTQ4OThmNWRlYyIgeG1wTU06T3JpZ2luYWxEb2N1bWVudElEPSJ4bXAuZGlkOjE3MzdmMWE2LWM2MWItZGQ0Ni1hNzdlLTcwZWM4YTlhZWE2NiIgZGM6Zm9ybWF0PSJpbWFnZS9qcGVnIiBwaG90b3Nob3A6Q29sb3JNb2RlPSIzIiBwaG90b3Nob3A6SUNDUHJvZmlsZT0ic1JHQiBJRUM2MTk2Ni0yLjEiPiA8eG1wTU06SGlzdG9yeT4gPHJkZjpTZXE+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJjcmVhdGVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOjE3MzdmMWE2LWM2MWItZGQ0Ni1hNzdlLTcwZWM4YTlhZWE2NiIgc3RFdnQ6d2hlbj0iMjAyMC0wOC0yM1QxNzo1MzoyMyswMzowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIDIxLjEgKFdpbmRvd3MpIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJzYXZlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDo5MTAxYTZmOS1hODUxLTQ0NDUtODAxOS1jZDgxYWNjZjUwZDIiIHN0RXZ0OndoZW49IjIwMjAtMDgtMjNUMTc6NTM6MjMrMDM6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCAyMS4xIChXaW5kb3dzKSIgc3RFdnQ6Y2hhbmdlZD0iLyIvPiA8L3JkZjpTZXE+IDwveG1wTU06SGlzdG9yeT4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPD94cGFja2V0IGVuZD0idyI/Pv/iDFhJQ0NfUFJP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";
var renderer, scene, camera, controls, loader, terrain, glsl, uniforms, root, tree;
renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(0xDEDEDE);
document.body.appendChild(renderer.domElement);
scene = new THREE.Scene();
loader = new THREE.TextureLoader();
loader.crossOrigin = "";
camera = new THREE.PerspectiveCamera(35, window.innerWidth / window.innerHeight, 1, 51200);
camera.position.set(-3072, 2048, -3072);
controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.05;
controls.screenSpacePanning = false;
controls.minDistance = 8;
controls.maxDistance = 10240;
controls.maxPolarAngle = Math.PI / 2;
//simple pseudo quadtree
var points = [], indices = [], quad_uvs = [], groups = [], materials = [];
for(var z = -512; z <= 512; z += 256){
for(var x = -512; x <= 512; x += 256){
points.push(new THREE.Vector3(x, 0, z));
}
}
points.push(new THREE.Vector3(512, 0, -384));
points.push(new THREE.Vector3(128, 0, 512));
points.push(new THREE.Vector3(384, 0, 512));
//delaunay
var geometry = new THREE.BufferGeometry().setFromPoints(points);
var indexDelaunay = Delaunator.from(points.map(v => { return [v.x, v.z]; }) );
var meshIndex = [], quad_uvs = [];
for(var i = 0; i < indexDelaunay.triangles.length; i++){ meshIndex.push(indexDelaunay.triangles[i]); }
for(var j = 0; j < points.length; j++){
var qx = remapFloat(points[j].x, -512, 512, 1, 0);
var qz = remapFloat(points[j].z, -512, 512, 0, 1);
quad_uvs.push(...[qx, qz]);
}
uvs = new Float32Array(quad_uvs);
geometry.setAttribute( 'uv', new THREE.BufferAttribute( uvs, 2 ) );
geometry.setIndex(meshIndex);
geometry.computeVertexNormals();
var plane = new THREE.Mesh(geometry, new THREE.MeshBasicMaterial({ map: new THREE.TextureLoader().load(texture)}));
scene.add(plane);
animate();
function animate(){
controls.update();
renderer.render(scene, camera);
requestAnimationFrame(animate);
}
function remapFloat(v_, min0_, max0_, min1_, max1_) { return min1_ + (v_ - min0_) / (max0_ - min0_) * (max1_ - min1_); }
body { margin: 0; }
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>GLSL Intersection</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<script src="https://unpkg.com/three#0.116.0/build/three.min.js"></script>
<script src="https://unpkg.com/three#0.116.0/examples/js/controls/OrbitControls.js"></script>
<script src="https://cdn.jsdelivr.net/npm/delaunator#4.0.1/delaunator.min.js"></script>
</head>
<body>
</body>
</html>

Related

Uncaught TypeError: Cannot read property 'ROTATE' of undefined

I have tried to run the fiddle where I got the error Cannot read property 'ROTATE' of undefined where I upgraded the three JS version to R107 where the error remains the same.
Is there any other changes or update should I have to go with.
Kindly, help me out with the issue.Heres the fiddle https://jsfiddle.net/0z3z6y7w/80/
var scene, camera, myMesh, myGeo, dummy;
var objects = [];
var controls;
var width = window.innerWidth,
height = (window.innerHeight * 60 / 100);
var objectWidth = 12;
$(document).ready(function (){
Load();
});
function Load() {
scene = new THREE.Scene();
scene.fog = new THREE.Fog(0xBBE0FB, 500, 10000);
// create a camera, which defines where we're looking at.
camera = new THREE.PerspectiveCamera(45, width / height, 0.1, 1000);
var light, materials;
scene.add(new THREE.AmbientLight(0x666666));
light = new THREE.DirectionalLight(0xdfebff, 1.75);
light.position.set(50, 200, 100);
light.position.multiplyScalar(1.3);
light.castShadow = true;
light.shadow.mapSize.width = 1024;
light.shadow.mapSize.height = 1024;
var d = 300;
light.shadow.camera.left = -d;
light.shadow.camera.right = d;
light.shadow.camera.top = d;
light.shadow.camera.bottom = -d;
light.shadow.camera.far = 1000;
scene.add(light);
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(width, height);
renderer.setClearColor(scene.fog.color);
renderer.gammaInput = true;
renderer.gammaOutput = true;
renderer.shadowMap.enabled = true;
// create a cube and add to scene
controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.maxPolarAngle = Math.PI * 0.5;
controls.rotateSpeed = 1.0;
controls.zoomSpeed = 1.2;
controls.panSpeed = 0.8;
controls.noZoom = false;
controls.noPan = false;
controls.staticMoving = true;
controls.dynamicDampingFactor = 0.3;
dummy = new THREE.Object3D();
dummy.position.x = 50;
dummy.position.z = 50;
scene.add( dummy );
myGeo = CreateObject();
var materials = [
new THREE.MeshPhongMaterial({ color: 0x6a4bea, side: THREE.DoubleSide }), // right
new THREE.MeshPhongMaterial({ color: 0xe28c8c, }), // back
new THREE.MeshPhongMaterial({ color: 0x6ff791, }), // left
new THREE.MeshPhongMaterial({ color: 0xf4fc00, }), // front
new THREE.MeshPhongMaterial({ color: 0x0c0c0c, }), // top
];
$.each(myGeo.faces, function(i, face){
if(i >= 0 && i <= 3){
// right
face.materialIndex = 0;
}else if(i >= 4 && i <= 7){
// right
face.materialIndex = 1;
}else if(i >= 8 && i <= 11){
// right
face.materialIndex = 2;
}else if(i >= 12 && i <= 15){
// right
face.materialIndex = 3;
}else {
face.materialIndex = 4;
}
});
myGeo.materials = materials;
myMesh = new THREE.Mesh(myGeo, new THREE.MeshFaceMaterial(myGeo.materials));
myMesh.name = 'myMesh';
myMesh.geometry.computeBoundingSphere();
scene.add(myMesh);
camera.position.x = -63.34568752955681;
camera.position.y = 21.686809575802087;
camera.position.z = 11.969556739130862;
camera.lookAt(scene.position);
// add the output of the renderer to the html element
$('#design-screen').append(renderer.domElement);
// call the render function
render();
}
function render() {
controls.update();
renderer.render(scene, camera);
requestAnimationFrame(render);
}
$('#btnLeft').on('click', function(e){
RotateBuilding('left');
});
$('#btnRight').on('click', function(e){
RotateBuilding('right');
});
$('#btnFront').on('click', function(e){
RotateBuilding('front');
});
$('#btnBack').on('click', function(e){
RotateBuilding('back');
});
function RotateBuilding(toShowSide){
var selectedFace;
$.each(myGeo.faces, function(i, fc){
if(fc.side == toShowSide){
selectedFace = fc;
return false;
}
});
var vector = selectedFace.normal.clone();
var center = myMesh.geometry.boundingSphere.center.clone();
var camPos = new THREE.Vector3().addVectors(center, vector.setLength(50));
camera.position.copy(camPos);
controls.target.copy(center);
//scene.remove(myMesh);
//dummy.add( myMesh );
//rotateAroundWorldAxis(dummy, vector, Math.PI/2);
// rotateAroundObjectAxis(dummy, vector, Math.PI/2);
}
function rotateAroundObjectAxis( object, axis, radians ) {
var rotationMatrix = new THREE.Matrix4();
rotationMatrix.makeRotationAxis( axis.normalize(), radians );
object.matrix.multiply( rotationMatrix ); // post-multiply
object.rotation.setFromRotationMatrix(object.matrix);
}
function rotateAroundWorldAxis( object, axis, radians ) {
var rotationMatrix = new THREE.Matrix4();
rotationMatrix.makeRotationAxis( axis.normalize(), radians );
rotationMatrix.multiply( object.matrix );
object.matrix = rotationMatrix;
object.rotation.setFromRotationMatrix( object.matrix );
}
function CreateObject() {
var geo = new THREE.Geometry();
geo.verticesNeedUpdate = true;
geo.uvsNeedUpdate = true;
geo.dynamic = true;
geo.vertices.push(new THREE.Vector3(-objectWidth, -4.8, 6)); //0
geo.vertices.push(new THREE.Vector3(objectWidth, 2.5, 6)); //1 // back
geo.vertices.push(new THREE.Vector3(-objectWidth, 2.5, 6)); //2
geo.vertices.push(new THREE.Vector3(objectWidth, -4.8, 6)); //3 // back
geo.vertices.push(new THREE.Vector3(objectWidth, 0, -6)); //4 // back
geo.vertices.push(new THREE.Vector3(objectWidth, -4.8, -6)); //5 // back
geo.vertices.push(new THREE.Vector3(-objectWidth, 0, -6)); //6
geo.vertices.push(new THREE.Vector3(-objectWidth, -4.8, -6)); //7
geo.faces.push(new THREE.Face3(0, 1, 2));
geo.faces[geo.faces.length - 1].side = "right";
//geo.faces.push(new THREE.Face3(0, 2, 1));
//geo.faces[geo.faces.length - 1].side = "right";
geo.faces.push(new THREE.Face3(0, 3, 1));
geo.faces[geo.faces.length - 1].side = "right";
//geo.faces.push(new THREE.Face3(0, 1, 3));
//geo.faces[geo.faces.length - 1].side = "right";
//geo.faces.push(new THREE.Face3(3, 4, 5));
//geo.faces[geo.faces.length - 1].side = "back";
geo.faces.push(new THREE.Face3(3, 5, 4));
geo.faces[geo.faces.length - 1].side = "back";
//geo.faces.push(new THREE.Face3(3, 1, 4));
//geo.faces[geo.faces.length - 1].side = "back";
geo.faces.push(new THREE.Face3(3, 4, 1));
geo.faces[geo.faces.length - 1].side = "back";
//geo.faces.push(new THREE.Face3(5, 6, 7));
//geo.faces[geo.faces.length - 1].side = "left";
geo.faces.push(new THREE.Face3(5, 7, 6));
geo.faces[geo.faces.length - 1].side = "left";
geo.faces.push(new THREE.Face3(5, 6, 4));
geo.faces[geo.faces.length - 1].side = "left";
//geo.faces.push(new THREE.Face3(5, 4, 6));
//geo.faces[geo.faces.length - 1].side = "left";
geo.faces.push(new THREE.Face3(7, 2, 6));
geo.faces[geo.faces.length - 1].side = "front";
//geo.faces.push(new THREE.Face3(7, 6, 2));
//geo.faces[geo.faces.length - 1].side = "front";
geo.faces.push(new THREE.Face3(7, 0, 2));
geo.faces[geo.faces.length - 1].side = "front";
//geo.faces.push(new THREE.Face3(7, 2, 0));
//geo.faces[geo.faces.length - 1].side = "front";
geo.faces.push(new THREE.Face3(6, 1, 4));
geo.faces.push(new THREE.Face3(6, 2, 1));
//geo.faces.push(new THREE.Face3(6, 4, 1));
//geo.faces.push(new THREE.Face3(6, 1, 2));
geo.computeFaceNormals();
return geo;
}
That happens because you use a version of three.js (R87) which does not match to the latest versions of DragControls and OrbitControls (R108). You always have to ensure that all files are from the same release. Here is the fixed fiddle:
http://jsfiddle.net/sqeLtkn1/1

Three.js particles

I've been trying to generate a particle system recently and I've been struggling to get it to work as it's based from an outdated version of three.js, it isn't appearing in the scene and I'm not sure why. It's probably obvious to why but I'm not that good at this.
var particleCount = 1800,
particles = new THREE.Geometry(),
pMaterial = new THREE.PointsMaterial({
size: 20,
map: THREE.TextureLoader("x.png"),
blending: THREE.AdditiveBlending,
transparent: true
});
var particleCount = 500,
particleSystem;
init();
render();
function init() {
for (var p = 0; p < particleCount; p++) {
(pX = Math.random() * 500 - 250),
(pY = Math.random() * 500 - 250),
(pZ = Math.random() * 500 - 250),
(particle = new THREE.Vector3(new THREE.Vector3(pX, pY, pZ)));
particle.velocity = new THREE.Vector3(0, Math.random(), 0);
particles.vertices.push(particle);
}
particleSystem = new THREE.Points(particles, pMaterial);
particleSystem.sortParticles = true;
scene.add(particleSystem);
particleSystem.position.set(0, 0, 0);
particleSystem.scale.set(100, 100, 100);
}
function update() {
particleSystem.rotation.y += 0.01;
pCount = particleCount;
while (pCount--) {
particle = particles.vertices[pCount];
if (particle.y < -200) {
particle.y = 200;
particle.velocity.y = 0;
}
particle.velocity.y -= Math.random() * 0.1;
particle.add(particle.velocity);
}
particleSystem.geometry.__dirtyVertices = true;
renderer.render(scene, camera);
}
I might be missing a few things as this is a few lines I had to pick out from a few hundred.
(I'm new here so please don't bully me for awful structure.)
Thanks in advance for anyone who responds.
map: THREE.TextureLoader("x.png"), should be map: new THREE.TextureLoader().load("x.png"),
particle = new THREE.Vector3(new THREE.Vector3(pX, pY, pZ)); should be particle = new THREE.Vector3(pX, pY, pZ);
particleSystem.geometry.__dirtyVertices = true; is outdated, you have to use particleSystem.geometry.verticesNeedUpdate = true;
Add depthTest: false to points material
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(0, 0, 400);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var particleCount = 1800,
particles = new THREE.Geometry(),
pMaterial = new THREE.PointsMaterial({
size: 20,
map: new THREE.TextureLoader().load("https://threejs.org/examples/textures/sprites/circle.png"),
blending: THREE.AdditiveBlending,
transparent: true,
depthTest: false
});
var particleCount = 500,
particleSystem;
for (var p = 0; p < particleCount; p++) {
pX = Math.random() * 500 - 250,
pY = Math.random() * 500 - 250,
pZ = Math.random() * 500 - 250,
particle = new THREE.Vector3(pX, pY, pZ);
particle.velocity = new THREE.Vector3(0, Math.random(), 0);
particles.vertices.push(particle);
}
particleSystem = new THREE.Points(particles, pMaterial);
scene.add(particleSystem);
function update() {
particleSystem.rotation.y += 0.01;
pCount = particleCount;
while (pCount--) {
particle = particles.vertices[pCount];
if (particle.y < -200) {
particle.y = 200;
particle.velocity.y = 0;
}
particle.velocity.y -= Math.random() * .1;
particle.add(particle.velocity);
}
particleSystem.geometry.verticesNeedUpdate = true;
}
renderer.setAnimationLoop(() => {
update();
renderer.render(scene, camera);
});
body {
overflow: hidden;
margin: 0;
}
<script src="https://threejs.org/build/three.js"></script>

How can I rotate texture inside a plane?

have pb with rotate texture, i read this question
Three.js Rotate Texture and there guys propose rotate in canvas, and it work good if you have rectangle, but i have pb with polygon, so after rotating i will have black area in some corner, so that solution is not for me, so maybe who know how i can rotate texture by threejs???
//Here's some code showing texture rotation/repeat/offset/center/etc.
var renderer = new THREE.WebGLRenderer();
var w = 600;
var h = 200;
renderer.setSize(w, h);
document.body.appendChild(renderer.domElement);
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(
45, // Field of view
w / h, // Aspect ratio
0.1, // Near
10000 // Far
);
camera.position.set(15, 10, 15);
camera.lookAt(scene.position);
controls = new THREE.OrbitControls(camera, renderer.domElement);
var light = new THREE.PointLight(0xFFFF00);
light.position.set(20, 20, 20);
scene.add(light);
var light1 = new THREE.AmbientLight(0x808080);
light1.position.set(20, 20, 20);
scene.add(light1);
var light2 = new THREE.PointLight(0x00FFFF);
light2.position.set(-20, 20, -20);
scene.add(light2);
var light3 = new THREE.PointLight(0xFF00FF);
light3.position.set(-20, -20, -20);
scene.add(light3);
var planeGeom = new THREE.PlaneGeometry(40, 40);
var canvas = document.createElement('canvas');
canvas.width = canvas.height = 64;
var ctx = canvas.getContext('2d');
ctx.fillStyle = 'rgba(256,0,0,0.95)'
ctx.fillRect(0, 0, 32, 32);
ctx.fillRect(32, 32, 32, 32);
var srnd = (rng) => (Math.random() - 0.5) * 2 * rng
for (var i = 0; i < 300; i++) {
ctx.fillStyle = `rgba(${srnd(256)|0}, ${srnd(256)|0}, ${srnd(256)|0}, ${srnd(1)})`
ctx.fillRect(srnd(60) | 0, srnd(60) | 0, 5, 5);
}
ctx.fillStyle = 'rgba(256,256,0,0.95)'
ctx.fillText("TEST", 2, 10);
ctx.fillText("WOOO", 32, 45);
var tex = new THREE.Texture(canvas)
tex.magFilter = THREE.NearestFilter;
tex.wrapS = tex.wrapT = THREE.RepeatWrapping;
tex.magFilter = tex.minFilter = THREE.NearestFilter;
tex.needsUpdate = true;
var material = new THREE.MeshLambertMaterial({
color: 0x808080,
map: tex,
transparent: true,
side: THREE.DoubleSide
});
var mesh = new THREE.Mesh(planeGeom, material);
scene.add(mesh);
renderer.setClearColor(0xdddddd, 1);
tex.repeat.x = tex.repeat.y = 2;
//fun effect
for (var i = 1; i < 10; i++) {
var m;
scene.add(m = mesh.clone());
m.position.z += i * 1.1;
}
(function animate() {
var tm = performance.now() * 0.0001
tex.rotation = Math.sin(tm) * Math.PI
//tex.offset.x = tex.offset.y = -2;
//tex.offset.x = Math.sin(tex.rotation) * -0.5;
//tex.offset.y = Math.cos(tex.rotation) * -0.5;
tex.repeat.x = tex.repeat.y = Math.sin(tex.rotation * 1.5) * 3;
tex.center.x = 0.5;
tex.center.y = 0.5;
requestAnimationFrame(animate);
controls.update();
renderer.render(scene, camera);
})();
<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://cdn.rawgit.com/mrdoob/three.js/master/examples/js/controls/OrbitControls.js"></script>

Draw a curve using multi plane in A-Frame and Three.js

I'm creating a A-Frame Application (with Three.js) draw a road using THREE.CatmullRomCurve3.
The application's concept is draw a road which connects multi points, I want to draw the road with exact width (eg: a road with 3 meters width), I'm using THREE.PlaneGeometry to connect 2 points.
My result, and my code snippet
var scene, camera, renderer;
var cube;
var controls;
function initScene() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(80, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 30;
renderer = new THREE.WebGLRenderer({
alpha: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
controls = new THREE.OrbitControls(camera);
controls.update();
document.body.appendChild(renderer.domElement);
}
function render() {
requestAnimationFrame(render);
// required if controls.enableDamping or controls.autoRotate are set to true
controls.update();
renderer.render(scene, camera);
}
function drawRoadByLine() {
//Create a closed wavey loop
var curve = new THREE.CatmullRomCurve3([
new THREE.Vector3(-10, 0, 10),
new THREE.Vector3(-5, 5, 5),
new THREE.Vector3(0, 0, 0),
new THREE.Vector3(5, -5, 5),
new THREE.Vector3(10, 0, 10)
]);
var points = curve.getPoints(50);
var geometry = new THREE.BufferGeometry().setFromPoints(points);
var material = new THREE.LineBasicMaterial({
color: 0xff0000
});
// Create the final object to add to the scene
var curveObject = new THREE.Line(geometry, material);
scene.add(curveObject);
}
function drawRoadByPlane() {
//Create a closed wavey loop
var curve = new THREE.CatmullRomCurve3([
new THREE.Vector3(-10, 0, 10),
new THREE.Vector3(-5, 5, 5),
new THREE.Vector3(0, 0, 0),
new THREE.Vector3(5, -5, 5),
new THREE.Vector3(10, 0, 10)
]);
var points = curve.getPoints(50);
var group = new THREE.Group();
var currentPos;
var nextPos;
var distance;
var plane;
var rotationMatrix;
for (var i = 0; i < points.length - 1; i++) {
currentPos = new THREE.Vector3(points[i].x, points[i].y, points[i].z);
nextPos = new THREE.Vector3(points[i + 1].x, points[i + 1].y, points[i + 1].z);
distance = currentPos.distanceTo(nextPos);
plane = createPlane(distance);
plane.position.set(currentPos.x, currentPos.y, currentPos.z);
// rotationMatrix = getRotationMatrix(currentPos, nextPos);
// plane.applyMatrix(rotationMatrix);
group.add(plane);
}
scene.add(group);
}
function createPlane(distance, position) {
var geometry = new THREE.PlaneGeometry(1, distance);
// Dummy random color each plane, true color is red (0xff0000)
var color = Math.floor((Math.random() * 0xffffff) + 1);
var material = new THREE.MeshBasicMaterial({
color: color,
side: THREE.DoubleSide
});
var plane = new THREE.Mesh(geometry, material);
return plane;
}
function getRotationMatrix(v1, v2) {
var quaternion = new THREE.Quaternion();
quaternion.setFromUnitVectors(v1, v2);
var matrix = new THREE.Matrix4();
matrix.makeRotationFromQuaternion(quaternion);
return matrix;
}
initScene();
drawRoadByPlane();
render();
body {
margin: 0;
width: 100%;
height: 100%;
overflow: hidden;
background-color: #000000;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/94/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
My now issue is how to make the planes display continously (without space between 2 plane). I think I need rotate each plane, but I don't know to to calculate right rotation between 2 points.
Update:
I've just changed my solution to use THREE.Face3 instead of THREE.PlaneGeometry.
Here is my code snippet
var scene, camera, renderer;
var cube;
var controls;
function initScene() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(80, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 30;
renderer = new THREE.WebGLRenderer({ alpha: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.update();
}
function render() {
requestAnimationFrame(render);
renderer.render(scene, camera);
}
function draw() {
var dummyPoints = [
new THREE.Vector3(-10, 0, 10),
new THREE.Vector3(-5, 5, 5),
new THREE.Vector3(0, 0, 0),
new THREE.Vector3(5, -5, 5),
new THREE.Vector3(10, 0, 10)
];
//Create a closed wavey loop
var curve = new THREE.CatmullRomCurve3(dummyPoints);
var material = new THREE.MeshBasicMaterial({ vertexColors: THREE.FaceColors, side: THREE.DoubleSide });
//create a triangular geometry
var points = curve.getPoints(100);
var roadPoints = [];
var length = points.length;
for (var i = 0; i < length - 1; i++) {
roadPoints = roadPoints.concat(extractRoadPoint(points[i], points[i + 1]));
}
roadPoints = roadPoints.concat(extractRoadPoint(points[length - 1], points[length - 2]));
var geometry = new THREE.Geometry().setFromPoints(roadPoints);
// var face = new THREE.Face3(0, 1, 2);
//add the face to the geometry's faces array
// geometry.faces.push(face);
for (var i = 0; i < roadPoints.length - 2; i++) {
var face = new THREE.Face3(i, i + 1, i + 2);
geometry.faces.push(face);
face.color.set(new THREE.Color(Math.random() * 0xffffff - 1));
}
//the face normals and vertex normals can be calculated automatically if not supplied above
geometry.computeFaceNormals();
geometry.computeVertexNormals();
scene.add(new THREE.Mesh(geometry, material));
}
function extractRoadPoint(point1, point2) {
var result = [];
var vector = {
x: point2.x - point1.x,
y: point2.y - point1.y,
z: point2.z - point1.z,
}
var uOxz = {
x: 0,
y: 1,
z: 0
};
var vectorVertices = {
x: vector.y * uOxz.z - vector.z * uOxz.y,
y: vector.z * uOxz.x - vector.x * uOxz.z,
z: vector.x * uOxz.y - vector.y * uOxz.x,
};
var t = Math.sqrt(1 * 1 / (vectorVertices.x * vectorVertices.x + vectorVertices.y * vectorVertices.y + vectorVertices.z * vectorVertices.z));
var sidePoint11 = {
x: point1.x + vectorVertices.x * t,
y: point1.y + vectorVertices.y * t,
z: point1.z + vectorVertices.z * t,
}
var sidePoint12 = {
x: point1.x - vectorVertices.x * t,
y: point1.y - vectorVertices.y * t,
z: point1.z - vectorVertices.z * t,
}
var sidePoint21 = {
x: point2.x + vectorVertices.x * t,
y: point2.y + vectorVertices.y * t,
z: point2.z + vectorVertices.z * t,
}
var sidePoint22 = {
x: point2.x - vectorVertices.x * t,
y: point2.y - vectorVertices.y * t,
z: point2.z - vectorVertices.z * t,
}
return [sidePoint11, sidePoint12, sidePoint21, sidePoint22];
}
initScene();
draw();
render();
body {
margin: 0;
width: 100%;
height: 100%;
overflow: hidden;
background-color: #000000;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/110/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>

How to make transparent hole to object which has image texture in THREE.js?

I made a house with walls, ceiling and floor.
Now I am trying to make holes in walls for windows/doors.
But there is an issue in textures of the walls.
This is function to build wall:
function build_wall(start, end, materialFront, id){
var dx = end.x - start.x;
var dy = end.y - start.y;
var wall_length = Math.sqrt(dx*dx + dy*dy);
var centroid_x = start.x + dx/2;
var centroid_y = (start.y + dy/2) * -1;
var ry = Math.atan2(dy, dx);
var materialBack = new THREE.MeshLambertMaterial( { color: 0xd9d9d9, shading: THREE.FlatShading, side: THREE.BackSide} );
var materialTop = new THREE.MeshBasicMaterial({color: 0xb3b3b3, side: THREE.DoubleSide});
var materials = [materialFront, materialBack, materialTop];
var material = new THREE.MeshFaceMaterial(materials);
var rectShape = new THREE.Shape();
rectShape.moveTo( 0, 0 );
rectShape.lineTo( 0, wall_height );
rectShape.lineTo( wall_length, wall_height );
rectShape.lineTo( wall_length, 0 );
rectShape.lineTo( 0, 0 );
var windowHole = new THREE.Path();
windowHole.moveTo(20, 180);
windowHole.lineTo(20, 160);
windowHole.lineTo(40, 160);
windowHole.lineTo(40, 180);
rectShape.holes.push(windowHole);
var extrudeSettings = { amount: 5, bevelEnabled: true, bevelSegments: 0, steps: 1, bevelSize: 0, bevelThickness: 1 };
var wall = new THREE.ExtrudeGeometry( rectShape, extrudeSettings );
for ( var face in wall.faces ) {
if (wall.faces[ face ].normal.z > 0.9) wall.faces[ face ].materialIndex = 0;
else if (wall.faces[ face ].normal.z < -0.9) wall.faces[ face ].materialIndex = 1;
else wall.faces[ face ].materialIndex = 2;
}
var wall_mesh = new THREE.Mesh(wall, material);
wall_mesh.position.set( start.x, 0, -start.y );
wall_mesh.rotation.set(0, ry, 0);
wall_mesh.name = id;
wall_mesh.data = 'wall';
scene.add(wall_mesh);
}
and I am calling this function in init():
//------Add Walls
coordArray.push(coordArray[0]); //push the first corner to close loop
for(var i = 0; i < coordArray.length-1; i++){ //iterate over the coordinate array, pushing vertices to the geometry
var start_wall = coordArray[i];
var end_wall = coordArray[(i+1)];
if(!Rooms[r].wall_show || Rooms[r].wall_show[i] == 1){
var wallTexture = new THREE.TextureLoader().load( "images/room_" + r + "_wall_" + i + ".jpg" );
var wall_material = new THREE.MeshBasicMaterial({
map: wallTexture,
side: THREE.FrontSide,
overdraw: 0.5
});
build_wall( start_wall, end_wall, wall_material, scene_id);
}
//find tour boundary, find center target
if(start_wall.x > maxX) maxX = start_wall.x;
if(start_wall.y > maxY) maxY = start_wall.y;
if(start_wall.x < minX) minX = start_wall.x;
if(start_wall.y < minY) minY = start_wall.y;
}
The result is as following:
The screenshot of the result
Sorry, It was cuz I didn't adjust the UVs to the [ 0, 1 ] range.
var uvs = wall.faceVertexUvs[0];
for (var i = 0; i < uvs.length; i++) {
uv = uvs[i];
for (var j = 0; j < uv.length; j++) {
u = uv[j];
u.x = u.x / wall_length;
u.y = u.y/ wall_height;
}
}
var wall_mesh = new THREE.Mesh(wall, material);
wall_mesh.position.set( start.x, 0, -start.y );
wall_mesh.rotation.set(0, ry, 0);
wall_mesh.name = id;
wall_mesh.data = 'wall';
scene.add(wall_mesh);

Resources