Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature Request]: Render STL thumbnails #351

Open
3 tasks done
CJones-Optics opened this issue Aug 21, 2024 · 24 comments
Open
3 tasks done

[Feature Request]: Render STL thumbnails #351

CJones-Optics opened this issue Aug 21, 2024 · 24 comments
Labels
Priority: Medium An issue that shouldn't be be saved for last Type: Enhancement New feature or request Type: UI/UX User interface and/or user experience
Milestone

Comments

@CJones-Optics
Copy link

Checklist

  • I am using an up-to-date version.
  • I have read the documentation.
  • I have searched existing issues.

Description

It would be awesome eventually to get thumbnails for STL files. The tagging system works great for a 3D printing workflow. (And I imagine other CAD workflows)

Solution

I found a github repo for rendering STL file thumbnails for use in Windows or Gnome like DE: REPO

Some kind of fork of this could be used. It is all written in rust which I am no expert in.

Alternatives

Issue #97 may provide an equivalent method of getting STL files. I am not sure which implmenetation would be easier.

I don't know any Rust, and am not very good at software in general lmao. I might have a play with the repo and see if I can implement it, but opening the issue in case anyone with more experiance wants to tackle it.,

@CJones-Optics CJones-Optics added the Type: Enhancement New feature or request label Aug 21, 2024
@thibmaek
Copy link

Could act similar to manyfold for example. TagStudio would be a great alternative to manage a large library of 3D printing files (STL, OBJ, 3MF, SCAD, F3D) without the complexity of selfhosting or resource heavy usage of manyfold.

macOS renders STL thumbs natively, is there no way to tap into QuickLook (what's used for the thumbnail) here?
image

@CyanVoxel CyanVoxel added the Type: UI/UX User interface and/or user experience label Aug 22, 2024
@JonatanNevo
Copy link

I found a python library that handles rendering of 3D objects and scenes, open3d
The issue is that it does not support python 3.12 yet

@CyanVoxel what python version is the project pinned to? if we can use 3.11 I can add the STL implementation (and potentially more 3D file formats as well)

@CyanVoxel
Copy link
Member

I found a python library that handles rendering of 3D objects and scenes, open3d The issue is that it does not support python 3.12 yet

@CyanVoxel what python version is the project pinned to? if we can use 3.11 I can add the STL implementation (and potentially more 3D file formats as well)

It's pinned to 3.11 and 3.12, with 3.12 being the sticking point - I'm also aware open3d and have been hoping to use it for rendering here once they finally bring support for 3.12. I believe isl-org/Open3D#6433 is the issue over there to watch for, with isl-org/Open3D#6717 being a PR for it that looks to be pretty far along. I've been keeping tabs on it every now and again for a while, but fingers crossed that 3.12 support isn't too far off

@JonatanNevo
Copy link

I have been looking into rendering it myself using OpenGL support in QT like this repo but that requires the usage of QWindow instead of QWidget for the PreviewPanel

I don't know QT enough to know the ramifications of such a change, and if it's even possible.

@CyanVoxel
Copy link
Member

I have been looking into rendering it myself using OpenGL support in QT like this repo but that requires the usage of QWindow instead of QWidget for the PreviewPanel

I don't know QT enough to know the ramifications of such a change, and if it's even possible.

I'm also unfortunately not familiar enough with Qt to know the consequences off hand, but I feel it would either be a quick "well this doesn't work it's a separate window" or "okay this'll work I just need to shuffle around some object types". It's up to you if you wanna take a stab at it or just wait for open3d to roll around to 3.12. I couldn't exactly tell you the pros and cons of either implementation, but I feel open3d would be easier to implement for and expand upon.

@JonatanNevo
Copy link

I'll take a stab at it,
Using OpenGL with QT can allow advanced stuff such as interactive preview (rotating the model and such) which, from what I saw, will be harder using open3d

@rfletchr
Copy link

It shouldn't be an issue. You should be able to take their QGLControllerWidget from engine.py and add it to a layout.

https://github.com/alonrubintec/3DViewer/blob/d30bc2da629944b715a7823515fab56fda5b7391/engine.py#L28

I would add though that PySide has a module called QT3D which provides all the APIs for doing this stuff without adding a requirement on a third party project.

https://doc.qt.io/qt-6/qt3d-simple-cpp-example.html

@rfletchr
Copy link

Heres the python version of the above example.

# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause

"""PySide6 port of the qt3d/simple-cpp example from Qt v5.x"""

import sys
from PySide6.QtCore import (Property, QObject, QPropertyAnimation, Signal)
from PySide6.QtGui import (QGuiApplication, QMatrix4x4, QQuaternion, QVector3D)
from PySide6.Qt3DCore import (Qt3DCore)
from PySide6.Qt3DExtras import (Qt3DExtras)


class OrbitTransformController(QObject):
    def __init__(self, parent):
        super().__init__(parent)
        self._target = None
        self._matrix = QMatrix4x4()
        self._radius = 1
        self._angle = 0

    def setTarget(self, t):
        self._target = t

    def getTarget(self):
        return self._target

    def setRadius(self, radius):
        if self._radius != radius:
            self._radius = radius
            self.updateMatrix()
            self.radiusChanged.emit()

    def getRadius(self):
        return self._radius

    def setAngle(self, angle):
        if self._angle != angle:
            self._angle = angle
            self.updateMatrix()
            self.angleChanged.emit()

    def getAngle(self):
        return self._angle

    def updateMatrix(self):
        self._matrix.setToIdentity()
        self._matrix.rotate(self._angle, QVector3D(0, 1, 0))
        self._matrix.translate(self._radius, 0, 0)
        if self._target is not None:
            self._target.setMatrix(self._matrix)

    angleChanged = Signal()
    radiusChanged = Signal()
    angle = Property(float, getAngle, setAngle, notify=angleChanged)
    radius = Property(float, getRadius, setRadius, notify=radiusChanged)


class Window(Qt3DExtras.Qt3DWindow):
    def __init__(self):
        super().__init__()

        # Camera
        self.camera().lens().setPerspectiveProjection(45, 16 / 9, 0.1, 1000)
        self.camera().setPosition(QVector3D(0, 0, 40))
        self.camera().setViewCenter(QVector3D(0, 0, 0))

        # For camera controls
        self.createScene()
        self.camController = Qt3DExtras.QOrbitCameraController(self.rootEntity)
        self.camController.setLinearSpeed(50)
        self.camController.setLookSpeed(180)
        self.camController.setCamera(self.camera())

        self.setRootEntity(self.rootEntity)

    def createScene(self):
        # Root entity
        self.rootEntity = Qt3DCore.QEntity()

        # Material
        self.material = Qt3DExtras.QPhongMaterial(self.rootEntity)

        # Torus
        self.torusEntity = Qt3DCore.QEntity(self.rootEntity)
        self.torusMesh = Qt3DExtras.QTorusMesh()
        self.torusMesh.setRadius(5)
        self.torusMesh.setMinorRadius(1)
        self.torusMesh.setRings(100)
        self.torusMesh.setSlices(20)

        self.torusTransform = Qt3DCore.QTransform()
        self.torusTransform.setScale3D(QVector3D(1.5, 1, 0.5))
        self.torusTransform.setRotation(QQuaternion.fromAxisAndAngle(QVector3D(1, 0, 0), 45))

        self.torusEntity.addComponent(self.torusMesh)
        self.torusEntity.addComponent(self.torusTransform)
        self.torusEntity.addComponent(self.material)

        # Sphere
        self.sphereEntity = Qt3DCore.QEntity(self.rootEntity)
        self.sphereMesh = Qt3DExtras.QSphereMesh()
        self.sphereMesh.setRadius(3)

        self.sphereTransform = Qt3DCore.QTransform()
        self.controller = OrbitTransformController(self.sphereTransform)
        self.controller.setTarget(self.sphereTransform)
        self.controller.setRadius(20)

        self.sphereRotateTransformAnimation = QPropertyAnimation(self.sphereTransform)
        self.sphereRotateTransformAnimation.setTargetObject(self.controller)
        self.sphereRotateTransformAnimation.setPropertyName(b"angle")
        self.sphereRotateTransformAnimation.setStartValue(0)
        self.sphereRotateTransformAnimation.setEndValue(360)
        self.sphereRotateTransformAnimation.setDuration(10000)
        self.sphereRotateTransformAnimation.setLoopCount(-1)
        self.sphereRotateTransformAnimation.start()

        self.sphereEntity.addComponent(self.sphereMesh)
        self.sphereEntity.addComponent(self.sphereTransform)
        self.sphereEntity.addComponent(self.material)


if __name__ == '__main__':
    app = QGuiApplication(sys.argv)
    view = Window()
    view.show()
    sys.exit(app.exec())

If you want to generate thumbnails you'd probably need to find something which supports rendering to an off-screen surface QT has QOffscreenSurface but I'm not sure if QT3D can write to it.

@JonatanNevo
Copy link

JonatanNevo commented Aug 27, 2024

Thanks @rfletchr.
I'm planning on working on it on the weekend when ill have some time.

There are two things I want to tackle here.
One is to generate the static images for the thumbnails and one is to generate an interactive preview for the selected file (something basic like arcball)

@rfletchr
Copy link

rfletchr commented Sep 3, 2024

@JonatanNevo the example code I posted does everything you need for the interactive preview, did you have any luck getting it to write to an offscreen surface?

@JonatanNevo
Copy link

@rfletchr life happened and it seems like I won't have time to work on this in the foreseeable future
Feel free to take over, I'll try to help if I can

@rfletchr
Copy link

rfletchr commented Sep 3, 2024

@JonatanNevo I'm in a similar position myself. I use allot of QT in my work life though so I try to offer little bits and pieces when I can to try and save people hassle. I've held off of writing code for this project though as its code style doesn't run with mine and I know I'd just keep trying to change things and cause more trouble than good ;)

@JonatanNevo
Copy link

Then hopefully someone else picks this up, or I will in a few months when I'll have the time :)

@svgPhoenix
Copy link

open3d now supports python 3.12. I don't need to be able to rotate the models in TagStudio, I just need to be able to see them at all. Without stl/3mf support, I cannot use TagStudio at all, and I badly need it to organize all the models on my NAS lol

@seakrueger
Copy link
Collaborator

While Open3D did merge 3.12 support, they have not yet published a release that supports that version yet. Hopefully, it happens soon but until then, we'll have to wait

@svgPhoenix
Copy link

oh my bad not checking if that had been released but I mostly wanted to give my 2c that implementing something is a lot more important than a fancy feature (manipulating 3d objects) that I see as probably being beyond the scope of this app.

@calculuschild
Copy link

I will throw in my 2 cents here as well.

In terms of static 2D thumbnails, I have been using headless Blender via Python to generate 2D thumbnails of my STLs for a while; I tend to like the more polished look over the generic monotone output from manyfold, stl-thumb, etc. Not sure if that could be an alternative or optional plugin somehow. I can share my script and associated .blend files for that if anyone wishes.

An interactive preview would also be awesome, but definitely wouldn't need any fancy shading capabilities from Blender.

@CyanVoxel CyanVoxel added Priority: Medium An issue that shouldn't be be saved for last Status: Blocked This issue or pull request is awaiting the outcome of another issue or pull request labels Dec 21, 2024
@CyanVoxel CyanVoxel moved this to 🍀 Backlog in TagStudio Development Dec 21, 2024
@trebory6
Copy link

trebory6 commented Jan 8, 2025

Just wanted to chime in that I'd also love to see this happen!

I've been following the development for a while, and I think this would be absolutely PERFECT for organizing my STL library for 3D Printing.

@CyanVoxel
Copy link
Member

Looks like (as of 8 hours ago!) Open3D finally released a build with Python 3.12 support, so we can start looking into using that for this!

@CyanVoxel CyanVoxel removed the Status: Blocked This issue or pull request is awaiting the outcome of another issue or pull request label Jan 8, 2025
@CyanVoxel CyanVoxel added this to the Alpha v9.6 milestone Jan 8, 2025
@CyanVoxel CyanVoxel moved this from 🍀 Backlog to 🛠 Ready for Development in TagStudio Development Jan 8, 2025
@JonatanNevo
Copy link

Nice!
I'll try taking a look at it later today

@trebory6
Copy link

trebory6 commented Jan 8, 2025

Looks like (as of 8 hours ago!) Open3D finally released a build with Python 3.12 support, so we can start looking into using that for this!

Woah, what a coincidence! Totally didn't plan that. Awesome.

@JonatanNevo
Copy link

@CyanVoxel is there some persistent cache system?
It take quite a while to render all the images, especially because open3d does not really like multithreading so I need to render it one at a time

@JonatanNevo
Copy link

I made a quick and dirty poc, the angle is way off and it takes a lot of time to render but you can see the WIP pr here:
#693

@CyanVoxel
Copy link
Member

@CyanVoxel is there some persistent cache system? It take quite a while to render all the images, especially because open3d does not really like multithreading so I need to render it one at a time

Not at the moment, but that's the next system for v9.5 I'll be developing now that I'm not as tied up with #655

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Priority: Medium An issue that shouldn't be be saved for last Type: Enhancement New feature or request Type: UI/UX User interface and/or user experience
Projects
Status: 🛠 Ready for Development
Development

No branches or pull requests

9 participants