JSFiddle - React, Tailwind, and code Playground
by Paul West
HTML
<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
<script>
function ProfiledContourGeometry(profileShape, contour, contourClosed) {
contourClosed = contourClosed !== undefined ? contourClosed : true;
let profileGeometry = new THREE.ShapeBufferGeometry(profileShape);
profileGeometry.rotateX(Math.PI * .5);
let profile = profileGeometry.attributes.position;
let profilePoints = new Float32Array(profile.count * contour.length * 3);
for (let i = 0; i < contour.length; i++) {
let v1 = new THREE.Vector2().subVectors(contour[i - 1 < 0 ? contour.length - 1 : i - 1], contour[i]);
let v2 = new THREE.Vector2().subVectors(contour[i + 1 == contour.length ? 0 : i + 1], contour[i]);
let angle = v2.angle() - v1.angle();
let halfAngle = angle * .5;
let hA = halfAngle;
let tA = v2.angle() + Math.PI * .5;
if (!contourClosed){
if (i == 0 || i == contour.length - 1) {hA = Math.PI * .5;}
if (i == contour.length - 1) {tA = v1.angle() - Math.PI * .5;}
}
let shift = Math.tan(hA - Math.PI * .5);
console.log(shift);
let shiftMatrix = new THREE.Matrix4().set(
1, 0, 0, 0, -shift, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
);
let tempAngle = tA;
let rotationMatrix = new THREE.Matrix4().set(
Math.cos(tempAngle), -Math.sin(tempAngle), 0, 0,
Math.sin(tempAngle), Math.cos(tempAngle), 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
);
let translationMatrix = new THREE.Matrix4().set(
1, 0, 0, contour[i].x,
0, 1, 0, contour[i].y,
0, 0, 1, 0,
0, 0, 0, 1,
);
let cloneProfile = profile.clone();
shiftMatrix.applyToBufferAttribute(cloneProfile);
rotationMatrix.applyToBufferAttribute(cloneProfile);
translationMatrix.applyToBufferAttribute(cloneProfile);
...
CSS
body {
overflow: hidden;
margin: 0;
}
JavaScript
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(5, 5, 10);
var renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var controls = new THREE.OrbitControls(camera, renderer.domElement);
var light = new THREE.DirectionalLight(0xffffff, .75);
light.position.setScalar(10);
scene.add(light);
scene.add(new THREE.AmbientLight(0xffffff, .25));
var helper = new THREE.GridHelper(20, 20);
//helper.geometry.rotateX(Math.PI * -.5);
scene.add(helper);
var profileShape1 = new THREE.Shape();
profileShape1.moveTo(0, 0);
profileShape1.lineTo(0, 1);
profileShape1.absarc(1, 1, .5, Math.PI, Math.PI * 1.5);
profileShape1.lineTo(1, 0);
var contour1 = [
new THREE.Vector2(0, 0),
new THREE.Vector2(1, 1),
new THREE.Vector2(2, 1),
new THREE.Vector2(2, 0),
new THREE.Vector2(1, -1)
];
var geometry1 = ProfiledContourGeometry(profileShape1, contour1, false);
geometry1.rotateX(-Math.PI * .5);
var fullProfile1 = new THREE.Mesh(geometry1, new THREE.MeshLambertMaterial({
color: "red",
wireframe: false
}));
scene.add(fullProfile1);
var profileShape2 = new THREE.Shape();
profileShape2.absarc(0, 0, 1, 0, Math.PI * 2);
var contour2 = [
new THREE.Vector2(-4, 0),
new THREE.Vector2(0, 5),
new THREE.Vector2(5, 5),
new THREE.Vector2(5, 0)
]
var geometry2 = ProfiledContourGeometry(profileShape2, contour2, false);
var fullProfile2 = new THREE.Mesh(geometry2, new THREE.MeshBasicMaterial({
color: "aqua",
wireframe: true
}));
fullProfile2.position.set(-7, 1, -5);
scene.add(fullProfile2);
var geometry2 = ProfiledContourGeometry(profileShape2, contour2, true);
var fullProfile2 = new THREE.Mesh(geometry2, new THREE.MeshBasicMaterial({
color: "yellow",
wireframe: true
}));
fullProfile2.position.set(7, 1, -5);
scene.add(fullProfile2);
render();
function render() {
...