Skip to content

Commit

Permalink
Merge pull request #283 from xyz-tools/feature/disable-clipping-when-…
Browse files Browse the repository at this point in the history
…minmaxlayer-not-set

Fix: disable clipping when min/max layer not set
  • Loading branch information
remcoder authored Jan 27, 2025
2 parents ec9bbb6 + 5f8d392 commit 4467614
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 75 deletions.
37 changes: 23 additions & 14 deletions demo/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -72,26 +72,35 @@ <h1 class="text-center m-3 mb-5">GCode Preview
<div class="panel" v-cloak v-show="activeTab == 'layers'">
<section>
<div class="controls">
<label :class="{'has-text-grey' : settings.singleLayerMode}" >Start layer <output id="start-layer-value" >{{settings.startLayer}}</output></label>&nbsp;
<label>
Start Layer
<input type="checkbox" v-model="settings.enableStartLayer" />
</label>
<label :class="{'has-text-grey' : !settings.enableStartLayer}" ><output id="start-layer-value" >{{settings.startLayer}}</output></label>&nbsp;
<input
type="range"
min="1"
:max="settings.maxLayer"
id="start-layer"
v-model="settings.startLayer"
:disabled="settings.singleLayerMode"
type="range"
min="1"
:max="settings.maxLayer"
id="start-layer"
v-model="settings.startLayer"
:disabled="!settings.enableStartLayer"
/>
</div>
<div class="controls">
<label>End layer <output id="end-layer-value" >{{settings.endLayer}}</output></label>&nbsp;
<label>
End Layer
<input type="checkbox" v-model="settings.enableEndLayer" />
</label>
<label :class="{'has-text-grey' : !settings.enableEndLayer}"> <output id="end-layer-value" >{{settings.endLayer}}</output></label>&nbsp;
<!-- HACK: extra :value binding to ensure the value is set after the max is updated -->
<input
v-model="settings.endLayer"
type="range"
min="1"
:max="settings.maxLayer"
id="end-layer"
:value="settings.endLayer"
v-model="settings.endLayer"
type="range"
min="1"
:max="settings.maxLayer"
id="end-layer"
:value="settings.endLayer"
:disabled="!settings.enableEndLayer"
/>
</div>
<div class="controls">
Expand Down
7 changes: 5 additions & 2 deletions demo/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,11 @@ export const app = (window.app = createApp({
layerCount.value = countLayers;
const colors = extrusionColor instanceof Array ? extrusionColor : [extrusionColor];
const currentSettings = {
startLayer: 1,
enableStartLayer: false,
maxLayer: countLayers,
endLayer: countLayers,
enableEndLayer: false,
singleLayerMode,
renderTravel,
travelColor: '#' + travelColor.getHexString(),
Expand Down Expand Up @@ -222,8 +225,8 @@ export const app = (window.app = createApp({
});

watchEffect(() => {
preview.startLayer = +settings.value.startLayer;
preview.endLayer = +settings.value.endLayer;
preview.startLayer = settings.value.enableStartLayer ? +settings.value.startLayer : undefined;
preview.endLayer = settings.value.enableEndLayer ? +settings.value.endLayer : undefined;
});

watchEffect(() => {
Expand Down
150 changes: 91 additions & 59 deletions src/webgl-preview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ import {
Scene,
ShaderMaterial,
Vector3,
WebGLRenderer
WebGLRenderer,
MathUtils
} from 'three';

/**
Expand Down Expand Up @@ -402,77 +403,114 @@ export class WebGLPreview {
* Gets the current start layer (1-based index)
* @returns Start layer number
*/
get startLayer(): number {
get startLayer(): number | undefined {
return this._startLayer;
}

/**
* Sets the start layer (1-based index)
* @param value - Layer number to start rendering from
*/
set startLayer(value: number) {
if (this.countLayers > 1 && value > 0) {
this._startLayer = value;
if (value <= this.countLayers) {
const layer = this.job.layers[value - 1];
this.materials.forEach((material) => {
material.uniforms.clipMinY.value = layer.z;
});
this.updateLineClipping();
} else {
this.materials.forEach((material) => {
material.uniforms.clipMinY.value = -Infinity;
});
this.updateLineClipping();
}
set startLayer(value: number | undefined) {
if (typeof value === 'number') {
this._startLayer = MathUtils.clamp(value, 1, this.countLayers);
} else {
this._startLayer = undefined;
}

this.updateClippingPlanes();
}

private updateLineClipping() {
if (this._startLayer && this._endLayer) {
const minZ = this.job.layers[this._startLayer - 1]?.z || 0;
const maxZ = this.job.layers[this._endLayer - 1]?.z || 0;
/**
* Updates the clipping planes for the 3D preview based on the start and end layers.
*
* This method calculates the minimum and maximum Z values from the specified start and end layers.
* If the start layer is not defined, the minimum Z value defaults to 0.
* If the end layer is not defined, the maximum Z value defaults to Infinity.
*
* It then updates the clipping planes for shader materials and line clipping using these Z values.
*
* @private
*/
private updateClippingPlanes() {
const minZ = !this._startLayer ? 0 : this.job.layers[this._startLayer - 1]?.z ?? 0;

this.scene.traverse((obj) => {
if (obj instanceof LineSegments2) {
const material = obj.material as LineMaterial;
material.clippingPlanes = [new Plane(new Vector3(0, 1, 0), -minZ), new Plane(new Vector3(0, -1, 0), maxZ)];
}
});
}
const maxZ = !this._endLayer ? Infinity : this.job.layers[this._endLayer - 1]?.z ?? Infinity;

this.updateClippingPlanesForShaderMaterials(minZ, maxZ);
this.updateLineClipping(minZ, maxZ);
}

/**
* Updates the clipping planes for all shader materials in the scene.
* This method sets the min and max Z values for the clipping planes in the shader materials.
*
* @param minZ - The minimum Z value for the clipping plane.
* @param maxZ - The maximum Z value for the clipping plane
*/

private updateClippingPlanesForShaderMaterials(minZ: number, maxZ: number) {
this.materials.forEach((material) => {
material.uniforms.clipMinY.value = minZ;
material.uniforms.clipMaxY.value = maxZ;
});
}

/**
* Applies clipping planes to the specified material based on the minimum and maximum Z values.
*
* This method creates clipping planes for the top and bottom of the specified Z range,
* then applies them to the material's clippingPlanes property.
*
* @param material - Shader material to apply clipping planes to
* @param minZ - The minimum Z value for the clipping plane.
* @param maxZ - The maximum Z value for the clipping plane.
*/
private applyMinMaxClippingPlanes(material: Material, minZ: number, maxZ: number) {
material.clippingPlanes = [new Plane(new Vector3(0, 1, 0), -minZ), new Plane(new Vector3(0, -1, 0), maxZ)];
}

/**
* Updates the clipping planes for all `LineSegments2` objects in the scene.
* This method filters the scene's children to find instances of `LineSegments2`,
* then applies the clipping planes to their materials.
*
* @param minZ - The minimum Z value for the clipping plane.
* @param maxZ - The maximum Z value for the clipping plane.
*/
private updateLineClipping(minZ: number, maxZ: number) {
this.scene.traverse((obj) => {
if (obj instanceof LineSegments2) {
const material = obj.material as LineMaterial;
this.applyMinMaxClippingPlanes(material, minZ, maxZ);
}
});
}

/**
* Gets the current end layer (1-based index)
* @returns End layer number
*/
get endLayer(): number {
get endLayer(): number | undefined {
return this._endLayer;
}

/**
* Sets the end layer (1-based index)
* @param value - Layer number to end rendering at
*/
set endLayer(value: number) {
if (this.countLayers > 1 && value > 0) {
this._endLayer = value;
if (this._singleLayerMode === true) {
this.startLayer = this._endLayer - 1;
}
if (value <= this.countLayers) {
const layer = this.job.layers[value - 1];
this.materials.forEach((material) => {
material.uniforms.clipMaxY.value = layer.z;
});
this.updateLineClipping();
} else {
this.materials.forEach((material) => {
material.uniforms.clipMaxY.value = Infinity;
});
this.updateLineClipping();
}
set endLayer(value: number | undefined) {
if (typeof value === 'number') {
this._endLayer = MathUtils.clamp(value, 1, this.countLayers);
} else {
this._endLayer = undefined;
}

if (this._singleLayerMode === true) {
this.startLayer = this._endLayer - 1;
}

this.updateClippingPlanes();
}

/**
Expand Down Expand Up @@ -778,15 +816,16 @@ export class WebGLPreview {
* @param color - Color to use for the lines
*/
private renderPathsAsLines(paths: Path[], color: Color): void {
const minZ = this.job.layers[this._startLayer - 1]?.z ?? 0;
const maxZ = this.job.layers[this._endLayer - 1]?.z ?? Infinity;

const material = new LineMaterial({
color: Number(color.getHex()),
linewidth: this.lineWidth,
clippingPlanes: [
new Plane(new Vector3(0, 1, 0), this._startLayer ? -this.job.layers[this._startLayer - 1].z : 0),
new Plane(new Vector3(0, -1, 0), this._endLayer ? this.job.layers[this._endLayer - 1].z : 0)
]
linewidth: this.lineWidth
});

this.applyMinMaxClippingPlanes(material, minZ, maxZ);

const lineVertices: number[] = [];

// lines need to be offset.
Expand Down Expand Up @@ -819,12 +858,6 @@ export class WebGLPreview {
const colorNumber = Number(color.getHex());
const geometries: BufferGeometry[] = [];

// const material = new MeshLambertMaterial({
// color: colorNumber,
// wireframe: this._wireframe,
// clippingPlanes: this.clippingPlanes
// });

const material = createColorMaterial(colorNumber, this.ambientLight, this.directionalLight, this.brightness);

this.materials.push(material);
Expand All @@ -840,7 +873,6 @@ export class WebGLPreview {

const batchedMesh = this.createBatchMesh(geometries, material);
this.disposables.push(material);
// this.disposables.push(batchedMesh);

this.group?.add(batchedMesh);
}
Expand Down

0 comments on commit 4467614

Please sign in to comment.