mirror of
https://github.com/yeicor-3d/yet-another-cad-viewer.git
synced 2025-12-19 22:24:17 +01:00
lots of fixes and finding new problems
This commit is contained in:
@@ -53,11 +53,30 @@ function centerCamera() {
|
|||||||
let selectionEnabled = ref(false);
|
let selectionEnabled = ref(false);
|
||||||
let selectedMaterials: Array<Material> = []
|
let selectedMaterials: Array<Material> = []
|
||||||
let hasListener = false;
|
let hasListener = false;
|
||||||
|
let ignoreClickFrom: [number, number] | null = null;
|
||||||
|
let selectionMoveListener = (event: MouseEvent) => {
|
||||||
|
if (!selectionEnabled.value) return;
|
||||||
|
ignoreClickFrom = [event.clientX, event.clientY];
|
||||||
|
};
|
||||||
|
|
||||||
let selectionListener = (event: MouseEvent) => {
|
let selectionListener = (event: MouseEvent) => {
|
||||||
if (!selectionEnabled.value) return;
|
if (!selectionEnabled.value) {
|
||||||
|
ignoreClickFrom = undefined;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (ignoreClickFrom) {
|
||||||
|
let [x, y] = ignoreClickFrom;
|
||||||
|
if (Math.abs(event.clientX - x) > 5 || Math.abs(event.clientY - y) > 5) {
|
||||||
|
ignoreClickFrom = undefined;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ignoreClickFrom = undefined;
|
||||||
|
}
|
||||||
let viewer: ModelViewerElement = props.refSData.viewer;
|
let viewer: ModelViewerElement = props.refSData.viewer;
|
||||||
|
// FIXME: Clicking near edges does not work...
|
||||||
|
// FIXME: Clicking with ORTHO camera does not work...
|
||||||
const material = viewer.materialFromPoint(event.clientX, event.clientY);
|
const material = viewer.materialFromPoint(event.clientX, event.clientY);
|
||||||
|
console.log(material)
|
||||||
if (material === null) return;
|
if (material === null) return;
|
||||||
const wasSelected = selectedMaterials.find((m) => m === material) !== undefined;
|
const wasSelected = selectedMaterials.find((m) => m === material) !== undefined;
|
||||||
if (wasSelected) {
|
if (wasSelected) {
|
||||||
@@ -85,7 +104,8 @@ function toggleSelection() {
|
|||||||
selectionEnabled.value = !selectionEnabled.value;
|
selectionEnabled.value = !selectionEnabled.value;
|
||||||
if (selectionEnabled.value) {
|
if (selectionEnabled.value) {
|
||||||
if (!hasListener) {
|
if (!hasListener) {
|
||||||
viewer.addEventListener('click', selectionListener);
|
viewer.addEventListener('mouseup', selectionListener);
|
||||||
|
viewer.addEventListener('mousedown', selectionMoveListener); // Avoid clicking when dragging
|
||||||
hasListener = true;
|
hasListener = true;
|
||||||
}
|
}
|
||||||
for (let material of selectedMaterials) {
|
for (let material of selectedMaterials) {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {settings} from "../misc/settings";
|
import {settings} from "../misc/settings";
|
||||||
import {ModelViewerElement, RGBA} from '@google/model-viewer';
|
import {ModelViewerElement} from '@google/model-viewer';
|
||||||
import {onMounted, ref} from "vue";
|
import {onMounted, ref} from "vue";
|
||||||
import {$scene} from "@google/model-viewer/lib/model-viewer-base";
|
import {$scene} from "@google/model-viewer/lib/model-viewer-base";
|
||||||
import type {ModelScene} from "@google/model-viewer/lib/three-components/ModelScene";
|
import type {ModelScene} from "@google/model-viewer/lib/three-components/ModelScene";
|
||||||
@@ -33,12 +33,13 @@ onMounted(() => {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<model-viewer ref="viewer"
|
<model-viewer ref="viewer"
|
||||||
style="width: 100%; height: 100%" :src="props.src" alt="The 3D model(s)" camera-controls
|
style="width: 100%; height: 100%" :src="props.src" alt="The 3D model(s)" camera-controls camera-orbit="30deg 75deg auto"
|
||||||
camera-orbit="30deg 75deg auto"
|
max-camera-orbit="Infinity 180deg auto" min-camera-orbit="-Infinity 0deg 1%" disable-tap
|
||||||
max-camera-orbit="Infinity 180deg auto" min-camera-orbit="-Infinity 0deg auto" disable-tap
|
|
||||||
:exposure="settings.exposure" :shadow-intensity="settings.shadowIntensity" interaction-prompt="none"
|
:exposure="settings.exposure" :shadow-intensity="settings.shadowIntensity" interaction-prompt="none"
|
||||||
:autoplay="settings.autoplay" :ar="settings.arModes.length > 0" :ar-modes="settings.arModes"
|
:autoplay="settings.autoplay" :ar="settings.arModes.length > 0" :ar-modes="settings.arModes"
|
||||||
:skybox-image="settings.background" :environment-image="settings.background"></model-viewer>
|
:skybox-image="settings.background" :environment-image="settings.background">
|
||||||
|
<slot></slot> <!-- Controls, annotations, etc. -->
|
||||||
|
</model-viewer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import importlib.metadata
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from pygltflib import *
|
from pygltflib import *
|
||||||
|
|
||||||
@@ -10,6 +12,8 @@ class GLTFMgr:
|
|||||||
"""A utility class to build our GLTF2 objects easily and incrementally"""
|
"""A utility class to build our GLTF2 objects easily and incrementally"""
|
||||||
|
|
||||||
gltf: GLTF2 = GLTF2(
|
gltf: GLTF2 = GLTF2(
|
||||||
|
asset=Asset(generator=f"yacv_server@{importlib.metadata.version('yacv_server')}"),
|
||||||
|
scene=0,
|
||||||
scenes=[Scene(nodes=[0])],
|
scenes=[Scene(nodes=[0])],
|
||||||
nodes=[Node(mesh=0)],
|
nodes=[Node(mesh=0)],
|
||||||
meshes=[Mesh(primitives=[])],
|
meshes=[Mesh(primitives=[])],
|
||||||
@@ -19,16 +23,6 @@ class GLTFMgr:
|
|||||||
samplers=[Sampler(magFilter=NEAREST)],
|
samplers=[Sampler(magFilter=NEAREST)],
|
||||||
textures=[Texture(source=0, sampler=0)],
|
textures=[Texture(source=0, sampler=0)],
|
||||||
images=[Image(bufferView=0, mimeType='image/png')],
|
images=[Image(bufferView=0, mimeType='image/png')],
|
||||||
materials=[
|
|
||||||
Material(name="face", alphaCutoff=None, pbrMetallicRoughness=PbrMetallicRoughness(
|
|
||||||
baseColorTexture=TextureInfo(index=0), baseColorFactor=[1, 1, 0.5, 1])),
|
|
||||||
Material(name="edge", alphaCutoff=None, pbrMetallicRoughness=PbrMetallicRoughness(
|
|
||||||
baseColorFactor=[0, 0, 0.5, 1])),
|
|
||||||
Material(name="vertex", alphaCutoff=None, pbrMetallicRoughness=PbrMetallicRoughness(
|
|
||||||
baseColorFactor=[0.5, 0.5, 0.5, 1])),
|
|
||||||
# Material(name="selected", alphaCutoff=None, pbrMetallicRoughness=PbrMetallicRoughness(
|
|
||||||
# baseColorTexture=TextureInfo(index=0), baseColorFactor=[1, 0, 0, 1])),
|
|
||||||
],
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@@ -40,24 +34,41 @@ class GLTFMgr:
|
|||||||
vertices = np.array([[v[0], v[1], v[2]] for v in vertices_raw], dtype=np.float32)
|
vertices = np.array([[v[0], v[1], v[2]] for v in vertices_raw], dtype=np.float32)
|
||||||
indices = np.array([[i[0], i[1], i[2]] for i in indices_raw], dtype=np.uint32)
|
indices = np.array([[i[0], i[1], i[2]] for i in indices_raw], dtype=np.uint32)
|
||||||
tex_coord = np.array([[t[0], t[1]] for t in tex_coord_raw], dtype=np.float32)
|
tex_coord = np.array([[t[0], t[1]] for t in tex_coord_raw], dtype=np.float32)
|
||||||
self._add_any(vertices, indices, tex_coord, mode=TRIANGLES, material=0)
|
self._add_any(vertices, indices, tex_coord, mode=TRIANGLES, material="face")
|
||||||
|
|
||||||
def add_edge(self, vertices_raw: List[Tuple[float, float, float]]):
|
def add_edge(self, vertices_raw: List[Tuple[float, float, float]]):
|
||||||
"""Add an edge to the GLTF as a new primitive of the unique mesh"""
|
"""Add an edge to the GLTF as a new primitive of the unique mesh"""
|
||||||
vertices = np.array([[v[0], v[1], v[2]] for v in vertices_raw], dtype=np.float32)
|
vertices = np.array([[v[0], v[1], v[2]] for v in vertices_raw], dtype=np.float32)
|
||||||
indices = np.array(list(map(lambda i: [i, i + 1], range(len(vertices) - 1))), dtype=np.uint32)
|
indices = np.array(list(map(lambda i: [i, i + 1], range(len(vertices) - 1))), dtype=np.uint32)
|
||||||
tex_coord = np.array([])
|
tex_coord = np.array([])
|
||||||
self._add_any(vertices, indices, tex_coord, mode=LINE_STRIP, material=1)
|
self._add_any(vertices, indices, tex_coord, mode=LINE_STRIP, material="edge")
|
||||||
|
|
||||||
def add_vertex(self, vertex: Tuple[float, float, float]):
|
def add_vertex(self, vertex: Tuple[float, float, float]):
|
||||||
"""Add a vertex to the GLTF as a new primitive of the unique mesh"""
|
"""Add a vertex to the GLTF as a new primitive of the unique mesh"""
|
||||||
vertices = np.array([[vertex[0], vertex[1], vertex[2]]])
|
vertices = np.array([[vertex[0], vertex[1], vertex[2]]])
|
||||||
indices = np.array([[0]], dtype=np.uint32)
|
indices = np.array([[0]], dtype=np.uint32)
|
||||||
tex_coord = np.array([], dtype=np.float32)
|
tex_coord = np.array([], dtype=np.float32)
|
||||||
self._add_any(vertices, indices, tex_coord, mode=POINTS, material=2)
|
self._add_any(vertices, indices, tex_coord, mode=POINTS, material="vertex")
|
||||||
|
|
||||||
|
def add_material(self, kind: str) -> int:
|
||||||
|
"""It is important to use a different material for each primitive to be able to change them at runtime"""
|
||||||
|
new_material: Material
|
||||||
|
if kind == "face":
|
||||||
|
new_material = Material(name="face", alphaCutoff=None, pbrMetallicRoughness=PbrMetallicRoughness(
|
||||||
|
baseColorTexture=TextureInfo(index=0), baseColorFactor=[1, 1, 0.5, 1]))
|
||||||
|
elif kind == "edge":
|
||||||
|
new_material = Material(name="edge", alphaCutoff=None, pbrMetallicRoughness=PbrMetallicRoughness(
|
||||||
|
baseColorFactor=[0, 0, 0.5, 1]))
|
||||||
|
elif kind == "vertex":
|
||||||
|
new_material = Material(name="vertex", alphaCutoff=None, pbrMetallicRoughness=PbrMetallicRoughness(
|
||||||
|
baseColorFactor=[0.5, 0.5, 0.5, 1]))
|
||||||
|
else:
|
||||||
|
raise ValueError(f"Unknown material kind {kind}")
|
||||||
|
self.gltf.materials.append(new_material)
|
||||||
|
return len(self.gltf.materials) - 1
|
||||||
|
|
||||||
def _add_any(self, vertices: np.ndarray, indices: np.ndarray, tex_coord: np.ndarray, mode: int = TRIANGLES,
|
def _add_any(self, vertices: np.ndarray, indices: np.ndarray, tex_coord: np.ndarray, mode: int = TRIANGLES,
|
||||||
material: int = 0):
|
material: str = "face"):
|
||||||
assert vertices.ndim == 2
|
assert vertices.ndim == 2
|
||||||
assert vertices.shape[1] == 3
|
assert vertices.shape[1] == 3
|
||||||
vertices = vertices.astype(np.float32)
|
vertices = vertices.astype(np.float32)
|
||||||
@@ -86,7 +97,7 @@ class GLTFMgr:
|
|||||||
if len(tex_coord) > 0 else Attributes(POSITION=accessor_base + 1),
|
if len(tex_coord) > 0 else Attributes(POSITION=accessor_base + 1),
|
||||||
indices=accessor_base,
|
indices=accessor_base,
|
||||||
mode=mode,
|
mode=mode,
|
||||||
material=material,
|
material=self.add_material(material),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ if __name__ == "__main__":
|
|||||||
|
|
||||||
# Add the CAD part of the logo to the server
|
# Add the CAD part of the logo to the server
|
||||||
obj = build_logo()
|
obj = build_logo()
|
||||||
Shape(obj).export_stl(os.path.join(ASSETS_DIR, 'logo.stl'))
|
# DEBUG: Shape(obj).export_stl(os.path.join(ASSETS_DIR, 'logo.stl'))
|
||||||
show_object(obj, 'logo')
|
show_object(obj, 'logo')
|
||||||
|
|
||||||
# Save the complete logo to a single GLB file
|
# Save the complete logo to a single GLB file
|
||||||
|
|||||||
@@ -21,11 +21,11 @@ from gltf import GLTFMgr
|
|||||||
|
|
||||||
def tessellate(
|
def tessellate(
|
||||||
ocp_shape: TopoDS_Shape,
|
ocp_shape: TopoDS_Shape,
|
||||||
tolerance: float = 1e-3,
|
tolerance: float = 0.1,
|
||||||
angular_tolerance: float = 0.1,
|
angular_tolerance: float = 0.1,
|
||||||
faces: bool = True,
|
faces: bool = True,
|
||||||
edges: bool = True,
|
edges: bool = True,
|
||||||
vertices: bool = True,
|
vertices: bool = False,
|
||||||
) -> GLTF2:
|
) -> GLTF2:
|
||||||
"""Tessellate a whole shape into a list of triangle vertices and a list of triangle indices."""
|
"""Tessellate a whole shape into a list of triangle vertices and a list of triangle indices."""
|
||||||
mgr = GLTFMgr()
|
mgr = GLTFMgr()
|
||||||
|
|||||||
Reference in New Issue
Block a user