参考文章:Canvas绘制光源效果
<canvas id="canvas" :class="['compound-canvas']" ref="compound-canvas" width="200" height="200"></canvas>
// 向量差运算
function sub(v1, v2) {
return [
v1[0] - v2[0],
v1[1] - v2[1],
v1[2] - v2[2],
];
}
// 向量点乘运算
function dot(v1, v2) {
return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2];
}
// 求向量的单位化向量
function normalize(v) {
const len = Math.sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
return [
v[0] / len,
v[1] / len,
v[2] / len,
];
}
const pointLight = {
position: [100, 100, 40],
color: { r: 255, g: 255, b: 255 },
};
const plane = {
center: [100, 100, 0],
width: 200,
height: 200,
normal: [0, 0, 1],
color: { r: 255, g: 215, b: 0 },
};
const ctx = this.$refs['compound-canvas'].getContext('2d');
const imageData = ctx.createImageData(200, 200);
for (let x = 0; x < imageData.width; x += 1) {
for (let y = 0; y < imageData.height; y += 1) {
const index = y * imageData.width + x;
const point = [x, y, 0];
const normal = [0, 0, 1];
const reverseLightDirection = normalize(sub(pointLight.position, point));
const light = dot(reverseLightDirection, normal);
imageData.data[index * 4] = Math.min((pointLight.color.r + plane.color.r) * light, 255);
imageData.data[index * 4 + 1] = Math.min((pointLight.color.g + plane.color.g) * light, 255);
imageData.data[index * 4 + 2] = Math.min((pointLight.color.b + plane.color.b) * light, 255);
imageData.data[index * 4 + 3] = 255;
}
}
ctx.putImageData(imageData, 0, 0);