You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在PyQtGraph的GLMeshItem中设置光源位置与阴影效果?

解决pyqtgraph.opengl GLMeshItem光源与相机视角同步的问题

pyqtgraph的GLMeshItem默认Phong着色并未暴露直接调整光源位置的API,但可以通过自定义着色器+实时绑定相机位置实现光源随相机视角移动,解决模型过暗、光源位置异常的问题。

核心思路

  1. 替换默认着色器,新增lightPos uniform变量接收相机位置
  2. 在渲染循环中实时获取相机世界坐标,传递给着色器
  3. 修改着色器中的光源方向计算逻辑,让光源始终跟随相机

完整实现代码

import pyqtgraph.opengl as gl
from pyqtgraph.Qt import QtCore, QtGui
import numpy as np
from stl import mesh

# 加载STL模型
stl_mesh = mesh.Mesh.from_file("your_model.stl")
vertices = stl_mesh.vectors.reshape(-1, 3)
faces = np.arange(len(vertices)).reshape(-1, 3)

app = QtGui.QApplication([])
w = gl.GLViewWidget()
w.show()
w.setWindowTitle('STL Viewer with Camera-Linked Light')

# 创建GLMeshItem
mesh_item = gl.GLMeshItem(vertexes=vertices, faces=faces, color=(1,1,1,1), smooth=True, shaded=True)
w.addItem(mesh_item)

# 自定义顶点着色器
vertex_shader = """
attribute vec3 vertex;
attribute vec3 normal;
attribute vec4 color;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
uniform mat3 normalMatrix;
uniform vec3 lightPos;

varying vec3 vNormal;
varying vec4 vColor;
varying vec3 vLightDir;

void main() {
    vNormal = normalize(normalMatrix * normal);
    vColor = color;
    vec4 viewPos = modelViewMatrix * vec4(vertex, 1.0);
    vLightDir = normalize(lightPos - viewPos.xyz);
    gl_Position = projectionMatrix * modelViewMatrix * vec4(vertex, 1.0);
}
"""

# 自定义片段着色器
fragment_shader = """
varying vec3 vNormal;
varying vec4 vColor;
varying vec3 vLightDir;

void main() {
    // 调整ambient值可优化模型整体亮度
    float ambient = 0.3;
    float diff = max(dot(vNormal, vLightDir), 0.0);
    // 调整高光指数(16.0)可改变高光区域大小
    float spec = pow(max(dot(reflect(-vLightDir, vNormal), vec3(0,0,1)), 0.0), 16.0);
    vec3 color = vColor.rgb * (ambient + diff) + vec3(1.0) * spec;
    gl_FragColor = vec4(color, vColor.a);
}
"""

# 替换MeshItem的着色器
shader_program = gl.GLShaderProgram(vertex_shader, fragment_shader)
mesh_item.setShader(shader_program)

# 实时更新光源位置(绑定相机)
def update_light_source():
    # 获取相机的世界空间位置
    camera_pos = w.cameraPosition()
    shader_program.setUniformValue('lightPos', camera_pos)

# 每帧更新(约60fps)
update_timer = QtCore.QTimer()
update_timer.timeout.connect(update_light_source)
update_timer.start(16)

QtGui.QApplication.instance().exec_()

关键说明

  • w.cameraPosition()返回相机在世界空间的坐标,确保光源始终跟随相机视角
  • 着色器中通过lightPos - viewPos.xyz计算光源方向,实现相机位置作为光源的效果
  • 调整ambient(环境光强度)、高光指数(代码中16.0)可解决模型过暗问题,根据需求微调
  • 若之前自定义着色器无效,大概率是未实时更新uniform变量或光源方向计算错误(混淆了视图空间与世界空间坐标)

内容的提问来源于stack exchange,提问作者Nagarjun Vinukonda

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 03:52:40