为了实现该功能,这里将功能分成两部分。第一部分是控制点的拖动功能,第二部分是贝塞尔曲线的绘制功能。
控制点的拖动功能:鼠标按下选择点->鼠标移动修改点->鼠标松开释放点。选择点通过发生mousedown事件后遍历控制点数组,判断点击的位置是否和某个点的距离小于一定值,选择第一个满足条件的控制点,并向canvas绑定mousemove事件。修改点为鼠标移动时,将选择的点颜色的R分量改为1.0,即点变为红色,修改点的X和Y坐标为鼠标在画布中的坐标。释放点通过向canvas绑定mouseup事件,解绑mousemove即可。
贝塞尔曲线的绘制功能:直接套贝塞尔曲线的一般参数公式即可
实现的效果
初始状态 选中点并拖动
改变四个点位置
js代码
//获取上下文
const canvas = document.getElementById("my_Canvas");
gl = canvas.getContext("experimental-webgl");
//编写Shader代码,并编译
const vertCode = `
attribute vec3 coordinates;
attribute vec3 color;
varying vec3 vColor;
void main(void){
gl_Position = vec4(coordinates,1.0);
gl_PointSize = 10.0;
vColor = color;
}
`;
const vertShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertShader, vertCode);
gl.compileShader(vertShader);
const fragCode = `
precision mediump float;
varying vec3 vColor;
void main(void){
gl_FragColor = vec4(vColor, 1.0);
}
`;
const fragShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragShader, fragCode);
gl.compileShader(fragShader);
//创建并设置着色器程序
const shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertShader);
gl.attachShader(shaderProgram, fragShader);
gl.linkProgram(shaderProgram);
gl.useProgram(shaderProgram);
//定义控制点的顶点,索引
var vertices = new Float32Array([
-0.75, 0.0, 0.0,
-0.25, 0.0, 0,
0.25, 0.0, 0,
0.75, 0.0, 0.0,
]);
var indices = new Uint16Array([
0, 1, 2, 3,
]);
var colors = new Float32Array([
0.0, 0.0, 0.0,
0.0, 0.0, 0.0,
0.0, 0.0, 0.0,
0.0, 0.0, 0.0,
])
var choose = null;
//创建缓冲区并向缓冲区传入数据
const vertex_buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
const coord = gl.getAttribLocation(shaderProgram, "coordinates");
gl.vertexAttribPointer(coord, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(coord);
const index_Buffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index_Buffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
const color_buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, color_buffer);
gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW);
const color = gl.getAttribLocation(shaderProgram, "color");
gl.vertexAttribPointer(color, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(color);
//进行绘制初始图形
gl.clearColor(0.5, 0.5, 0.5, 1.0);
gl.enable(gl.DEPTH_TEST);
drawPoint()
drawBezier()
//传入控制点数据并绘制控制点
function drawPoint() {
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, color_buffer);
gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawElements(gl.POINTS, indices.length, gl.UNSIGNED_SHORT, 0);
}
//通过鼠标的坐标,计算出在[-1,1]区域的坐标,并判断选中了哪个控制点
function computePosition(clientX, clientY) {
const click_x = clientX;
const click_y = clientY;
const x = (click_x / canvas.width) * 2 - 1;
const y = 1 - (click_y / canvas.height) * 2;
for (let i = 0; i <= indices.length; i++) {
let pointX = vertices[i * 3];
let pointY = vertices[i * 3 + 1];
let absX = Math.abs(pointX - x);
let absY = Math.abs(pointY - y);
if (absX <= 0.1 && absY <= 0.1) {
return i;
}
}
return null;
}
//鼠标移动时就进行一次刷新画面
function move(event) {
let x = (event.clientX / canvas.width) * 2 - 1;
let y = 1 - (event.clientY / canvas.height) * 2;
vertices[choose * 3] = x;
vertices[choose * 3 + 1] = y;
colors[choose * 3] = 1.0
drawPoint();
drawBezier()
}
//鼠标按下时选中点
canvas.addEventListener('mousedown', function (e) {
choose = computePosition(e.clientX, e.clientY);
if (choose != null) {
canvas.addEventListener('mousemove', move)
}
})
//鼠标松开时释放选中的点
canvas.addEventListener('mouseup', function (event) {
canvas.removeEventListener('mousemove', move);
colors[choose * 3] = 0.0;
drawPoint();
drawBezier()
})
//通过控制点,绘制贝塞尔曲线
function drawBezier() {
let b_points = []
let b_indices = []
let cnt = 0;
for (let t = 0; t <= 1; t = t + 0.01) {
let x = (1 - t) ** 3 * vertices[0] + 3 * (1 - t) ** 2 * t * vertices[3] + 3 * (1 - t) * t ** 2 * vertices[6] + t ** 3 * vertices[9];
let y = (1 - t) ** 3 * vertices[1] + 3 * (1 - t) ** 2 * t * vertices[4] + 3 * (1 - t) * t ** 2 * vertices[7] + t ** 3 * vertices[10];
b_points.push(x, y, 0);
b_indices.push(cnt);
cnt++;
}
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(b_points), gl.STATIC_DRAW);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(b_indices), gl.STATIC_DRAW);
gl.drawElements(gl.LINE_STRIP, b_indices.length, gl.UNSIGNED_SHORT, 0);
}
标签:const,为例,BUFFER,0.0,曲线,贝塞尔,color,ARRAY,gl
From: https://blog.csdn.net/weixin_50780569/article/details/140908961