<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js webgl - animation - groups</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<link type="text/css" rel="stylesheet" href="main.css">
</head>
<body>
<script type="importmap">
{
"imports": {
"three": "../build/three.module.js",
"three/addons/": "./jsm/"
}
}
</script>
<button type="button" id="draw-line" style="position: absolute;top:0;left:0;">draw freehand</button>
<script type="module">
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
let isDraw = false;
let startPoint = null;
let line = null;
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
scene.add( new THREE.AxesHelper( 20 ) );
scene.background = new THREE.Color( "#ffffff" );
document.body.appendChild(renderer.domElement);
const controls = new OrbitControls(camera, renderer.domElement);
let freehandPoints = [];
camera.position.set( 0, 0, 5 );
function animate() {
requestAnimationFrame(animate);
controls.update();
renderer.render(scene, camera);
}
animate();
function createStrokeGeometry({linewidth}){
const geometry = new THREE.BufferGeometry();
const indices = [];
const vertices = [];
for (let i = 1; i < freehandPoints.length; i++) {
const direction = new THREE.Vector3().subVectors(freehandPoints[i - 1], freehandPoints[i]).normalize();
const leftDirection = new THREE.Vector3().crossVectors(camera.getWorldDirection(new THREE.Vector3()), direction).normalize();
const halfThickness = linewidth / 2;
const points = [
new THREE.Vector3().addScaledVector(leftDirection, halfThickness).add(freehandPoints[i]),
new THREE.Vector3().addScaledVector(leftDirection, -halfThickness).add(freehandPoints[i]),
new THREE.Vector3().addScaledVector(leftDirection, -halfThickness).add(freehandPoints[i - 1]),
new THREE.Vector3().addScaledVector(leftDirection, halfThickness).add(freehandPoints[i - 1])
];
vertices.push(
points[0].x, points[0].y, points[0].z,
points[1].x, points[1].y, points[1].z,
points[2].x, points[2].y, points[2].z,
points[3].x, points[3].y, points[3].z
);
const t = 4 * (i - 1);
indices.push(t, t + 1, t + 2, t, t + 2, t + 3)
}
geometry.setAttribute('position', new THREE.BufferAttribute(new Float32Array(vertices), 3));
geometry.setIndex(new THREE.BufferAttribute(new Uint32Array(indices), 1));
return geometry;
}
function createStroke({start,end,linewidth}){
if(line){
scene.remove(line);
}
const length = freehandPoints.length;
if(length==0){
freehandPoints = [start.clone()];
}
freehandPoints.push(end.clone());
line = new THREE.Mesh( createStrokeGeometry({linewidth}), new THREE.MeshBasicMaterial( { color: "#FF0000", side: THREE.DoubleSide } ) );
scene.add(line);
}
function getMousePosition(clientX, clientY) {
const rect = renderer.domElement.getBoundingClientRect();
const x = ((clientX - rect.left) / rect.width) * 2 - 1;
const y = -((clientY - rect.top) / rect.height) * 2 + 1;
const mouseVector = new THREE.Vector3(x, y, 0.5);
mouseVector.unproject(camera);
return mouseVector;
}
window.addEventListener('mousedown', ()=>{
freehandPoints = [];
startPoint = getMousePosition(event.clientX, event.clientY);
createStroke({start:startPoint.clone(),end:startPoint.clone(),linewidth:0.06});
});
window.addEventListener('mouseup', ()=>{
startPoint = null;
});
window.addEventListener('mousemove', ()=>{
if (isDraw===true&&startPoint) {
const endPoint = getMousePosition(event.clientX, event.clientY);
createStroke({start:startPoint.clone(),end:endPoint.clone(),linewidth:0.06});
}
});
document.getElementById("draw-line").addEventListener("click",()=>{
isDraw = !isDraw;
controls.enabled = !isDraw;
if(isDraw===true){
document.getElementById("draw-line").innerText="end draw";
}else{
document.getElementById("draw-line").innerText="draw freehand";
}
});
</script>
</body>
</html>
I want to draw freehand. but the lines are broken. How to fix it?