add belt mode for support painting
This commit is contained in:
parent
c5e4bac1cb
commit
eb660aa20b
2 changed files with 94 additions and 4 deletions
|
|
@ -17,6 +17,11 @@
|
|||
* support regions. For multi-material coloring or other uses, set
|
||||
* options.onlyDownwardFacing = false to paint all surfaces.
|
||||
*
|
||||
* BELT PRINTER MODE:
|
||||
* For belt printers, surfaces need support when facing "down the belt slope" rather
|
||||
* than straight down. Set options.beltMode = true and provide options.beltAngle (in radians)
|
||||
* to paint surfaces that face down the angled belt direction.
|
||||
*
|
||||
* PAINT POINT DATA STRUCTURE:
|
||||
* ---------------------------
|
||||
* Paint points must be an array of objects with this structure:
|
||||
|
|
@ -79,6 +84,9 @@ import { THREE } from '../../ext/three.js';
|
|||
* @param {THREE.Color} [paintColor] - Color for painted regions (default: light blue)
|
||||
* @param {Object} [options] - Optional configuration
|
||||
* @param {boolean} [options.onlyDownwardFacing=true] - Only paint on downward-facing surfaces (z-normal < 0)
|
||||
* @param {boolean} [options.beltMode=false] - Enable belt printer mode (paints surfaces facing down belt slope)
|
||||
* @param {number} [options.beltAngle=0] - Belt angle in radians (only used if beltMode is true)
|
||||
* @param {number} [options.supportAngle=45] - Support angle in degrees (cone around down direction)
|
||||
* @returns {THREE.Material} The modified material
|
||||
*/
|
||||
function addPaintOverlaySimple(material, paintPoints, paintColor = new THREE.Color(0x4488ff), options = {}) {
|
||||
|
|
@ -89,6 +97,10 @@ function addPaintOverlaySimple(material, paintPoints, paintColor = new THREE.Col
|
|||
|
||||
// Default: only paint downward-facing surfaces (for support painting)
|
||||
const onlyDownwardFacing = options.onlyDownwardFacing !== undefined ? options.onlyDownwardFacing : true;
|
||||
const beltMode = options.beltMode || false;
|
||||
const beltAngle = options.beltAngle || 0;
|
||||
const supportAngle = options.supportAngle || 45;
|
||||
const supportThreshold = Math.cos((90 - supportAngle) * Math.PI / 180);
|
||||
|
||||
// Store initial paint points reference
|
||||
material.userData.paintPoints = paintPoints;
|
||||
|
|
@ -119,6 +131,9 @@ function addPaintOverlaySimple(material, paintPoints, paintColor = new THREE.Col
|
|||
shader.uniforms.paintCount = { value: validPoints.length };
|
||||
shader.uniforms.paintColor = { value: paintColor };
|
||||
shader.uniforms.onlyDownwardFacing = { value: onlyDownwardFacing };
|
||||
shader.uniforms.beltMode = { value: beltMode };
|
||||
shader.uniforms.beltAngle = { value: beltAngle };
|
||||
shader.uniforms.supportThreshold = { value: supportThreshold };
|
||||
|
||||
// Pass model position from vertex shader to fragment shader
|
||||
// Paint points are in widget/model space, so we compare against transformed (model space)
|
||||
|
|
@ -143,6 +158,9 @@ function addPaintOverlaySimple(material, paintPoints, paintColor = new THREE.Col
|
|||
uniform int paintCount;
|
||||
uniform vec3 paintColor;
|
||||
uniform bool onlyDownwardFacing;
|
||||
uniform bool beltMode;
|
||||
uniform float beltAngle;
|
||||
uniform float supportThreshold;
|
||||
` + shader.fragmentShader;
|
||||
|
||||
shader.fragmentShader = shader.fragmentShader.replace(
|
||||
|
|
@ -156,7 +174,20 @@ function addPaintOverlaySimple(material, paintPoints, paintColor = new THREE.Col
|
|||
vec3 worldNormal = normalize(cross(posDx, posDy));
|
||||
|
||||
// Only paint downward-facing surfaces if option is enabled
|
||||
bool shouldPaint = !onlyDownwardFacing || worldNormal.z < -0.001;
|
||||
bool shouldPaint;
|
||||
if (beltMode) {
|
||||
// Belt mode: mesh is rotated, check if normal points toward world down
|
||||
// World down (0,0,-1) appears as (0, -sin(θ), -cos(θ)) in rotated mesh space
|
||||
// Dot product: normal · (0, -sin(θ), -cos(θ)) = -sin(θ)*ny - cos(θ)*nz
|
||||
float sinAngle = sin(beltAngle);
|
||||
float cosAngle = cos(beltAngle);
|
||||
float rotatedZ = worldNormal.y * sinAngle + worldNormal.z * cosAngle;
|
||||
// Check if within support angle cone from down direction (rotatedZ < -threshold)
|
||||
shouldPaint = !onlyDownwardFacing || rotatedZ < -supportThreshold;
|
||||
} else {
|
||||
// Normal mode: check if normal points downward within support angle cone
|
||||
shouldPaint = !onlyDownwardFacing || worldNormal.z < -supportThreshold;
|
||||
}
|
||||
if (shouldPaint) {
|
||||
// Check if this fragment is within any paint sphere
|
||||
bool painted = false;
|
||||
|
|
@ -206,6 +237,9 @@ function addPaintOverlaySimple(material, paintPoints, paintColor = new THREE.Col
|
|||
* @param {THREE.Color} [paintColor] - Color for painted regions (default: light blue)
|
||||
* @param {Object} [options] - Optional configuration
|
||||
* @param {boolean} [options.onlyDownwardFacing=true] - Only paint on downward-facing surfaces (z-normal < 0)
|
||||
* @param {boolean} [options.beltMode=false] - Enable belt printer mode (paints surfaces facing down belt slope)
|
||||
* @param {number} [options.beltAngle=0] - Belt angle in radians (only used if beltMode is true)
|
||||
* @param {number} [options.supportAngle=45] - Support angle in degrees (cone around down direction)
|
||||
* @returns {THREE.Material} The modified material
|
||||
*/
|
||||
function addPaintOverlayTexture(material, paintPoints, paintColor = new THREE.Color(0x4488ff), options = {}) {
|
||||
|
|
@ -216,6 +250,10 @@ function addPaintOverlayTexture(material, paintPoints, paintColor = new THREE.Co
|
|||
|
||||
// Default: only paint downward-facing surfaces (for support painting)
|
||||
const onlyDownwardFacing = options.onlyDownwardFacing !== undefined ? options.onlyDownwardFacing : true;
|
||||
const beltMode = options.beltMode || false;
|
||||
const beltAngle = options.beltAngle || 0;
|
||||
const supportAngle = options.supportAngle || 45;
|
||||
const supportThreshold = Math.cos((90 - supportAngle) * Math.PI / 180);
|
||||
|
||||
// Store initial paint points reference
|
||||
material.userData.paintPoints = paintPoints;
|
||||
|
|
@ -264,6 +302,9 @@ function addPaintOverlayTexture(material, paintPoints, paintColor = new THREE.Co
|
|||
shader.uniforms.paintTexSize = { value: new THREE.Vector2(texWidth, texHeight) };
|
||||
shader.uniforms.paintColor = { value: paintColor };
|
||||
shader.uniforms.onlyDownwardFacing = { value: onlyDownwardFacing };
|
||||
shader.uniforms.beltMode = { value: beltMode };
|
||||
shader.uniforms.beltAngle = { value: beltAngle };
|
||||
shader.uniforms.supportThreshold = { value: supportThreshold };
|
||||
|
||||
// Pass model position from vertex shader to fragment shader
|
||||
// Paint points are in widget/model space, so we compare against transformed (model space)
|
||||
|
|
@ -289,6 +330,9 @@ function addPaintOverlayTexture(material, paintPoints, paintColor = new THREE.Co
|
|||
uniform vec2 paintTexSize;
|
||||
uniform vec3 paintColor;
|
||||
uniform bool onlyDownwardFacing;
|
||||
uniform bool beltMode;
|
||||
uniform float beltAngle;
|
||||
uniform float supportThreshold;
|
||||
` + shader.fragmentShader;
|
||||
|
||||
shader.fragmentShader = shader.fragmentShader.replace(
|
||||
|
|
@ -302,7 +346,20 @@ function addPaintOverlayTexture(material, paintPoints, paintColor = new THREE.Co
|
|||
vec3 worldNormal = normalize(cross(posDx, posDy));
|
||||
|
||||
// Only paint downward-facing surfaces if option is enabled
|
||||
bool shouldPaint = !onlyDownwardFacing || worldNormal.z < -0.001;
|
||||
bool shouldPaint;
|
||||
if (beltMode) {
|
||||
// Belt mode: mesh is rotated, check if normal points toward world down
|
||||
// World down (0,0,-1) appears as (0, -sin(θ), -cos(θ)) in rotated mesh space
|
||||
// Dot product: normal · (0, -sin(θ), -cos(θ)) = -sin(θ)*ny - cos(θ)*nz
|
||||
float sinAngle = sin(beltAngle);
|
||||
float cosAngle = cos(beltAngle);
|
||||
float rotatedZ = worldNormal.y * sinAngle + worldNormal.z * cosAngle;
|
||||
// Check if within support angle cone from down direction (rotatedZ < -threshold)
|
||||
shouldPaint = !onlyDownwardFacing || rotatedZ < -supportThreshold;
|
||||
} else {
|
||||
// Normal mode: check if normal points downward within support angle cone
|
||||
shouldPaint = !onlyDownwardFacing || worldNormal.z < -supportThreshold;
|
||||
}
|
||||
if (shouldPaint) {
|
||||
bool painted = false;
|
||||
|
||||
|
|
|
|||
|
|
@ -267,7 +267,30 @@ function supportStart({ remove } = { remove: false }) {
|
|||
return api.widgets.meshes();
|
||||
};
|
||||
api.feature.on_mouse_drag = ({ int }) => {
|
||||
if (int?.length && int[0].face.normal.z < 0) {
|
||||
// Calculate if surface needs support based on belt mode or normal mode
|
||||
let needsSupport = false;
|
||||
if (int?.length) {
|
||||
const settings = api.conf.get();
|
||||
const normal = int[0].face.normal;
|
||||
|
||||
// Get support angle threshold (how steep before needing support)
|
||||
const supportAngle = settings.process.sliceSupportAngle || 45;
|
||||
const supportThreshold = Math.cos((90 - supportAngle) * Math.PI / 180);
|
||||
|
||||
if (settings.device.bedBelt) {
|
||||
// Belt mode: check if surface will face downward after belt rotation
|
||||
// After rotating by angle θ around X: nz' = ny*sin(θ) + nz*cos(θ)
|
||||
// We want nz' < -threshold (within cone of support angle from down)
|
||||
const angle = (settings.process.sliceAngle || 45) * Math.PI / 180;
|
||||
const rotatedZ = normal.y * Math.sin(angle) + normal.z * Math.cos(angle);
|
||||
needsSupport = rotatedZ < -supportThreshold;
|
||||
} else {
|
||||
// Normal mode: check if normal points downward within support angle cone
|
||||
needsSupport = normal.z < -supportThreshold;
|
||||
}
|
||||
}
|
||||
|
||||
if (needsSupport) {
|
||||
supportUpdate(int[0].point, down.widget, remove);
|
||||
}
|
||||
return [ down.widget.mesh ];
|
||||
|
|
@ -279,6 +302,12 @@ function supportStart({ remove } = { remove: false }) {
|
|||
const scheme = colorSchemeRegistry.getScheme(mode, theme);
|
||||
const paintColor = scheme.operations?.paint?.overlay ?? 0x4488ff;
|
||||
|
||||
// Get belt configuration for paint constraint
|
||||
const settings = api.conf.get();
|
||||
const isBelt = settings.device.bedBelt;
|
||||
const beltAngle = isBelt ? (settings.process.sliceAngle || 45) : 0;
|
||||
const supportAngle = settings.process.sliceSupportAngle || 45;
|
||||
|
||||
api.widgets.each(w => {
|
||||
// Use pushVisualState to track the paint operation
|
||||
w.pushVisualState('paint', {
|
||||
|
|
@ -295,7 +324,11 @@ function supportStart({ remove } = { remove: false }) {
|
|||
if (!w.anno.paint) {
|
||||
w.anno.paint = [];
|
||||
}
|
||||
addPaintOverlayTexture(mat, w.anno.paint, new THREE.Color(paintColor));
|
||||
addPaintOverlayTexture(mat, w.anno.paint, new THREE.Color(paintColor), {
|
||||
beltMode: isBelt,
|
||||
beltAngle: beltAngle * Math.PI / 180, // Convert to radians
|
||||
supportAngle: settings.process.sliceSupportAngle || 45
|
||||
});
|
||||
})
|
||||
api.space.update();
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue