首先来说,python想要搞点啥3D的玩意,是真麻烦。可以撤了。

少侠别走!

虽然很艰难,我还是找到一些体验不错的python库,可以拿来用。

首先,就是这里。前提是需要有conda。我直接装了个miniconda。

我当前使用的是igl。用过的都知道,就是好用。加载模型啊(试了一圈模型加载库,igl的下脚料的功能都那么好用),计算法线啊(人家可是用来做计算几何的库),就是好用!

然后PyGLM也可以装一下,python下的glm库。投影矩阵啊,3维空间变换啊,四元数啊,老好用。

还有moderngl,更简单,更方便的OpenGL使用方法。

界面的话,我直接用的PySide6,C++用Qt,Python可以无缝衔接一下当然好啦!

备注一下,关于PySide6其实有官方的示例代码,安装好了之后,就在${YourPythonDir}\Lib\site-packages\PySide6\examples,用vscode也好,用什么也好,直接用啥查啥,方便。之前查action连接槽,找了好久。。

上代码

代码没有别的含义,无非就是鼠标右键加载个模型,然后会显示出该模型特点视角下的法线图,ctrl+s保存一下。

第一次写费了点功夫,这也要查,那也要查,怎么给action链接槽,怎么加载obj模型,怎么添加uniform。折腾一遍之后,感觉还是浑身轻松。

import sys
from typing import List
import glm
import igl
import numpy as np
import moderngl as mgl
from PySide6.QtCore import Qt, Slot
from PySide6.QtGui import QKeyEvent, QContextMenuEvent, QAction, QImage, QSurfaceFormat
from PySide6.QtOpenGLWidgets import QOpenGLWidget
from PySide6.QtWidgets import QMenu, QFileDialog, QApplication vertex_shader = """
#version 330
in vec3 position;
in vec3 normal;
out vec3 vColor;
uniform mat4 uProjMat;
uniform mat4 uViewMat;
void main() {
vColor = vec3((normal + 1.0) * 0.5);
gl_Position = uProjMat * uViewMat * vec4(position, 1);
}
""" fragment_shader = """
#version 330
in vec3 vColor;
out vec4 fColor;
void main() {
fColor = vec4(vColor, 1);
}
""" class MyGLWidget(QOpenGLWidget):
vao = None
menu = None
loadAction = None def __init__(self, parent, *args, **kwargs):
super().__init__(parent, *args, **kwargs)
self.loadAction = QAction("Load Obj Model")
self.loadAction.triggered.connect(self.slotLoadModel)
self.menu = QMenu()
self.menu.addAction(self.loadAction) def initializeGL(self) -> None:
print("~~~~~ initialize GL ~~~~~")
gl = mgl.create_context()
gl.multisample = True
gl.enable(gl.CULL_FACE)
gl.enable(gl.DEPTH_TEST) def resizeGL(self, w: int, h: int) -> None:
print("~~~~~ resizing ~~~~~")
pass def paintGL(self) -> None:
print("~~~~~ painting ~~~~~")
gl = mgl.create_context()
gl.clear(0, 0, 0)
if self.vao:
self.vao.render() def keyReleaseEvent(self, event: QKeyEvent):
# 按下esc或者q键退出
if event.key() in (Qt.Key_Q, Qt.Key_Escape):
self.close()
# 按下Ctrl+S,保存当前画面
elif event.key() == Qt.Key_S:
if event.modifiers() == Qt.KeyboardModifier.ControlModifier:
self.slotCapture() def contextMenuEvent(self, event: QContextMenuEvent):
self.menu.exec(event.globalPos()) @Slot()
def slotLoadModel(self):
try:
(fileName, selectedFilter) = QFileDialog.getOpenFileName(self, "Select File", "",
"Wavefront Obj File (*.obj)")
if not fileName:
raise Exception("canceled") # 加载obj模型,igl真好用
(v, _, _, f, *_) = igl.read_obj(filename=fileName, dtype="f4")
# 绕着x轴旋转90度。自己看着转吧
for i, x in enumerate(v):
v[i] = glm.rotateX(x, glm.half_pi())
# 这里计算了一下包围盒,然后对模型做了平移加缩放,无非是想左下角为0点,最大尺寸限制到1,1,1
(bb, _) = igl.bounding_box(v)
maxLen = np.max(bb[0] - bb[7])
v = (v - bb[7]) / maxLen (bb, _) = igl.bounding_box(v)
size = bb[0] - bb[7] # 计算个法线跟玩似的
n = igl.per_vertex_normals(v, f, 0) self.makeCurrent()
gl = mgl.create_context() vbo = gl.buffer(v.tobytes())
nbo = gl.buffer(n.tobytes())
ibo = gl.buffer(f.tobytes()) program = gl.program(vertex_shader=vertex_shader, fragment_shader=fragment_shader)
projMat: mgl.Uniform = program["uProjMat"]
projMat.write(glm.ortho(0, size[0], 0, size[1], -2, 2))
viewMat: mgl.Uniform = program["uViewMat"]
viewMat.write(glm.lookAt(glm.vec3(0, 0, 1), glm.vec3(0, 0, 0), glm.vec3(0, 1, 0))) self.vao = gl.vertex_array(
program=program,
content=[
(vbo, "3f", "position"),
(nbo, "3f", "normal"),
],
index_buffer=ibo
) except Exception as e:
print(e) @Slot()
def slotCapture(self):
try:
(fileName, _) = QFileDialog.getSaveFileName(self, "Save Capture File", "", "PNG Format (*.png)")
if not fileName:
raise Exception("canceled") img: QImage = self.grabFramebuffer()
img.save(fileName) except Exception as e:
print(e) if __name__ == "__main__":
app = QApplication(sys.argv) # 这里是全局设置
fmt = QSurfaceFormat()
# 这里有意思了。在win10下,我加了个这,multisample就没了。
# 然而没有这个,在mac下会报错(抗锯齿也是没有)。娘希匹
fmt.setVersion(3, 3)
fmt.setProfile(QSurfaceFormat.CoreProfile)
fmt.setSamples(4)
fmt.setDepthBufferSize(24)
fmt.setStencilBufferSize(8)
QSurfaceFormat.setDefaultFormat(fmt) widget = MyGLWidget(None)
widget.resize(512, 512)
widget.show() sys.exit(app.exec())

我在win10和big sur上都测试了,还不错。

最后,CLion还能搞搞python,还真就比vscode好用。

memoのPython和3D那点事的更多相关文章

  1. Python绘制3d螺旋曲线图实例代码

    Axes3D.plot(xs, ys, *args, **kwargs) 绘制2D或3D数据 参数 描述 xs, ys X轴,Y轴坐标定点 zs Z值,每一个点的值都是1 zdir 绘制2D集合时使用 ...

  2. Python绘制3D图形

    来自:https://www.jb51.net/article/139349.htm 3D图形在数据分析.数据建模.图形和图像处理等领域中都有着广泛的应用,下面将给大家介绍一下如何使用python进行 ...

  3. python 画3D的高斯曲线

    用python画3D的高斯曲线,我想如果有多个峰怎么画? import numpy as npimport matplotlib.pyplot as pltimport mathimport mpl_ ...

  4. Python爬虫爬取糗事百科段子内容

    参照网上的教程再做修改,抓取糗事百科段子(去除图片),详情见下面源码: #coding=utf-8#!/usr/bin/pythonimport urllibimport urllib2import ...

  5. Python爬虫-爬取糗事百科段子

    闲来无事,学学python爬虫. 在正式学爬虫前,简单学习了下HTML和CSS,了解了网页的基本结构后,更加快速入门. 1.获取糗事百科url http://www.qiushibaike.com/h ...

  6. Python爬虫--抓取糗事百科段子

    今天使用python爬虫实现了自动抓取糗事百科的段子,因为糗事百科不需要登录,抓取比较简单.程序每按一次回车输出一条段子,代码参考了 http://cuiqingcai.com/990.html 但该 ...

  7. Python爬虫批量下载糗事百科段子,怀念的天王盖地虎,小鸡炖蘑菇...

    欢迎添加华为云小助手微信(微信号:HWCloud002 或 HWCloud003),输入关键字"加群",加入华为云线上技术讨论群:输入关键字"最新活动",获取华 ...

  8. 用python做些有意思的事——分析QQ聊天记录——私人订制

    之前,写了这篇文章,用python提取全部群成员的发言时间,并简单做了下分析.先补充一下,针对特定单个群成员(这里以  小小白   为例)消息记录的获取. 代码比较简单,主要是正则表达式的书写.(附: ...

  9. 用python做些有意思的事——分析QQ聊天记录

    ####################################### 已更新续集,戳这里. ######################################## 是这样的,有位学 ...

  10. webpy,希望能多了解一些关于WSGI,PYTHON的WEB开发框架的事,也希望能进一步了解PYTHON

    如果能真正看懂源代码,那就强了. 几年了,不应该总是小搞小打的. [Python]Webpy 源码学习(一) http://diaocow.iteye.com/blog/1922760 学习线路: 那 ...

随机推荐

  1. wixtoolset visualstudio 2017打包流程(1)

    第一步: 使用wix提供的 heat.exe 工具生成后缀为 wsx 的配置文件.   heat.exe dir ".\binr" -dr INSTALLFOLDER -cg Pr ...

  2. 【学习笔记】XR872 GUI Littlevgl 8.0 移植(文件系统)

    不得不提 在移植的过程中,发现 LVGL 的文件操作接口并不十分完善,在我看来, LVGL 的文件操作接口,应该更多的是为了 LVGL 内部接口方便读取资源文件而设立的,例如读取图像文件,加载字库文件 ...

  3. 遗传算法求TSP问题

    一.实验内容及目的 本实验以遗传算法为研究对象,分析了遗传算法的选择.交叉.变异过程,采用遗传算法设计并实现了商旅问题求解,解决了商旅问题求解最合适的路径,达到用遗传算法迭代求解的目的.选择.交叉.变 ...

  4. 高效、优雅的对象copy之MapStruct入门到精通,实战踩坑版

    一.前言 大家在开发中,最让人头疼的就是:对象之间的拷贝,前端的VO和数据库的Entity不一致! 性能最好的就是手动set,主要是枯燥且无技术含量,不仅耗费大量时间而且很容易出错: 所以我们要成为优 ...

  5. JS 计算两个时间戳相差年月日时分秒

    // JS 计算两个时间戳相差年月日时分秒 calculateDiffTime(startTime, endTime, type) { var runTime = parseInt(endTime - ...

  6. Balanced Team

    https://vjudge.net/problem/CodeForces-1133C 题意:在数组中找出一段  每两个元素差值不大于5的这段元素个数的最大值. 1 #include <iost ...

  7. .Net6 微服务之Ocelot+IdentityServer4入门看这篇就够了

    前言 .Net 6 使用 Consul 实现服务注册与发现 看这篇就够了.Net6 使用 Ocelot + Consul 看这篇就够了.Net6 微服务之Polly入门看这篇就够了 书接上文,本文将继 ...

  8. 把MyBatis当项目一样,讲透源码的技术书籍!

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 为啥?因为这些年,就很少有人能自主意识到,如何提升编码质量! 但讲屁话没有用,想学好编程突破阶 ...

  9. PostgreSQL处理膨胀与事务回卷

    一.表膨胀查询与处理 1.创建扩展 create extension pgstattuple; 2.表膨胀查询 pgstattuple提供了pgstatetuple()和pgstatindex()两个 ...

  10. global与nonlocal关键字、函数名的多种用法、函数的嵌套调用、函数的嵌套定义、闭包函数、装饰器简介

    目录 一.global与nonlocal关键字 二.函数名的多种用法 三.函数的嵌套调用 四.函数的嵌套定义 五.闭包函数 六.装饰器简介 一.global与nonlocal关键字 global方法: ...