Reputation:
I'm trying to write a function that will take three vertices and return a random point anywhere on the bounded plane formed by those vertices. So the function would be something like this:
function randomPointOnPlane(vertex1, vertex2, vertex3) {
...
return THREE.Vector3( x, y, z ); // random point on bounded plane
}
My approach has been to try to solve the system of equations given by ax+by+cz+d=0 for each vertex defining the bounded the plane. I haven't gotten very far with this though! How should I go about this? Thanks
Upvotes: 0
Views: 2333
Reputation: 84709
To uniformly sample in a triangle, use this function:
function randomInTriangle(v1, v2, v3) {
var r1 = Math.random();
var r2 = Math.sqrt(Math.random());
var a = 1 - r2;
var b = r2 * (1 - r1);
var c = r1 * r2;
return (v1.clone().multiplyScalar(a)).add(v2.clone().multiplyScalar(b)).add(v3.clone().multiplyScalar(c));
function randomInTriangle(v1, v2, v3) {
var r1 = Math.random();
var r2 = Math.sqrt(Math.random());
var a = 1 - r2;
var b = r2 * (1 - r1);
var c = r1 * r2;
return (v1.clone().multiplyScalar(a)).add(v2.clone().multiplyScalar(b)).add(v3.clone().multiplyScalar(c));
}
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 5;
scene.add(camera);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var v0 = new THREE.Vector3(0, 0, 1);
var v1 = new THREE.Vector3(0, 1, 0);
var v2 = new THREE.Vector3(1, 0, 0);
var material = new THREE.PointsMaterial({
color: 0xff0000,
size: 0.05,
opacity: 1
});
var geometry = new THREE.Geometry();
for (var i = 0; i < 100; i++) {
var pt = randomInTriangle(v0, v1, v2);
geometry.vertices.push(pt);
}
var pointCloud = new THREE.Points(geometry, material);
scene.add(pointCloud);
function render() {
renderer.render(scene, camera);
pointCloud.rotation.x += 0.01;
pointCloud.rotation.y += 0.01;
requestAnimationFrame(render);
}
render();
<script src="https://threejs.org/build/three.min.js"></script>
Upvotes: 0
Reputation: 5036
//Heres an algo based on barycentric coordinates... https://adamswaab.wordpress.com/2009/12/11/random-point-in-a-triangle-barycentric-coordinates/
function randomPointInTriangle(vertex1, vertex2, vertex3) {
var edgeAB = vertex2.clone().sub(vertex1)
var edgeAC = vertex3.clone().sub(vertex1)
var r = Math.random();
var s = Math.random();
if (r + s >= 1) {
r = 1 - r
s = 1 - s
}
return edgeAB.multiplyScalar(r).add(edgeAC.multiplyScalar(s)).add(vertex1)
// random point in triangle
}
var renderer = new THREE.WebGLRenderer();
var w = 300;
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 sphereGeom = new THREE.SphereGeometry(0.1, 8, 8);
sphereGeom.verticesNeedUpdate = true;
sphereGeom.computeFaceNormals();
sphereGeom.computeVertexNormals();
function randomPointInTriangle(vertex1, vertex2, vertex3) {
var edgeAB = vertex2.clone().sub(vertex1)
var edgeAC = vertex3.clone().sub(vertex1)
var r = Math.random();
var s = Math.random();
if (r + s >= 1) {
r = 1 - r
s = 1 - s
}
return edgeAB.multiplyScalar(r).add(edgeAC.multiplyScalar(s)).add(vertex1)
// random point in triangle
}
var material = new THREE.MeshLambertMaterial({
color: 0x808080
});
var v0 = new THREE.Vector3(0, 0, -2)
var v1 = new THREE.Vector3(2, 0, 1)
var v2 = new THREE.Vector3(-2, 0, 1)
for (var i = 0; i < 500; i++) {
var mesh = new THREE.Mesh(sphereGeom, material);
mesh.position.copy(randomPointInTriangle(v0, v1, v2))
scene.add(mesh);
}
renderer.setClearColor(0xdddddd, 1);
(function animate() {
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>
Upvotes: 0
Reputation: 31086
I suggest the following workflow: Use Plane.setFromCoplanarPoints() to create a THREE.Plane
object from your three points. You can then create a random point in 3D space (e.g. via Math.random()
) and project this point on the plane via Plane.projectPoint(). This would be the result of your intended function.
Upvotes: 2