如何用JavaScript实现圆形的平面阴影效果(基于p5.js)
实现圆形的平面投射阴影(p5.js)
你已经完成了切线计算的核心部分,只需要将切线向外延伸到屏幕边界,再构建出阴影的封闭区域即可。以下是修改后的完整方案:
关键调整点
- 修复代码语法错误:
noStroke;→noStroke(); - 计算切线延伸方向,将切点处的切线向外延伸至屏幕边缘,得到阴影的两个端点
- 重新构建阴影路径:连接两个切点和对应的延伸端点,形成完整的阴影区域
修改后的完整代码
function setup() { createCanvas(windowWidth, windowHeight); } function draw() { background("#9B009D"); const circleCenterX = width / 2; const circleCenterY = height / 2; const circleRadius = 200; // 先绘制圆形,确保阴影在圆形下方 fill("#FF7000"); noStroke(); ellipse(circleCenterX, circleCenterY, circleRadius * 2); // 鼠标作为光源绘制阴影和切线 if (mouseX !== 0 || mouseY !== 0) { drawShadow(mouseX, mouseY, circleCenterX, circleCenterY, circleRadius); } } function drawShadow(lightX, lightY, centerX, centerY, radius) { const dx = lightX - centerX; const dy = lightY - centerY; const directDistance = sqrt(dx * dx + dy * dy); // 光源在圆内时不绘制阴影 if (directDistance < radius) { return; } // 计算切线相关角度 const angleToCenter = atan2(dy, dx); const angleFromTangent = acos(radius / directDistance); const angle1 = angleToCenter + angleFromTangent; const angle2 = angleToCenter - angleFromTangent; // 计算圆上的两个切点 const tanPoint1X = centerX + radius * cos(angle1); const tanPoint1Y = centerY + radius * sin(angle1); const tanPoint2X = centerX + radius * cos(angle2); const tanPoint2Y = centerY + radius * sin(angle2); // 计算切线延伸方向(从光源指向切点,向外延伸) const dir1X = tanPoint1X - lightX; const dir1Y = tanPoint1Y - lightY; const dir2X = tanPoint2X - lightX; const dir2Y = tanPoint2Y - lightY; // 延伸切线到屏幕外(取屏幕对角线2倍长度确保超出边界) const extendLength = sqrt(width*width + height*height) * 2; const shadowEnd1X = tanPoint1X + dir1X / sqrt(dir1X*dir1X + dir1Y*dir1Y) * extendLength; const shadowEnd1Y = tanPoint1Y + dir1Y / sqrt(dir1X*dir1X + dir1Y*dir1Y) * extendLength; const shadowEnd2X = tanPoint2X + dir2X / sqrt(dir2X*dir2X + dir2Y*dir2Y) * extendLength; const shadowEnd2Y = tanPoint2Y + dir2Y / sqrt(dir2X*dir2X + dir2Y*dir2Y) * extendLength; // 绘制切线(可选,用于调试) stroke(255); line(lightX, lightY, tanPoint1X, tanPoint1Y); line(lightX, lightY, tanPoint2X, tanPoint2Y); // 绘制半透明阴影区域 noStroke(); fill(0, 0, 0, 100); beginShape(); vertex(tanPoint1X, tanPoint1Y); vertex(shadowEnd1X, shadowEnd1Y); vertex(shadowEnd2X, shadowEnd2Y); vertex(tanPoint2X, tanPoint2Y); endShape(CLOSE); } function mouseMoved() { redraw(); }
代码说明
- 切线延伸逻辑:通过计算切点到光源的方向向量,归一化后乘以足够大的长度,确保延伸线能覆盖整个屏幕范围。
- 阴影区域构建:阴影是一个四边形,由两个切点和两个延伸端点组成,半透明黑色填充模拟真实阴影效果。
- 可扩展性:修改
circleCenterX、circleCenterY变量即可移动圆形,鼠标位置直接对应光源位置,拖动鼠标就能看到阴影实时变化。
内容的提问来源于stack exchange,提问作者Sophie Tooke
相关产品推荐
相关产品推荐

