news 2026/6/10 16:14:51

Shadows 使用实时阴影贴图为模型添加阴影效果

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Shadows 使用实时阴影贴图为模型添加阴影效果

一:主要的知识点

1、说明

本文只是教程内容的一小段,因博客字数限制,故进行拆分。主教程链接:vtk教程——逐行解析官网所有Python示例-CSDN博客

2、知识点纪要

本段代码主要涉及的有①vtkShadowMapPass阴影渲染,②RenderPass的解释与使用


二:代码及注释

import vtkmodules.vtkRenderingOpenGL2 import vtkmodules.vtkInteractionStyle from vtkmodules.vtkCommonColor import vtkNamedColors from vtkmodules.vtkIOGeometry import ( vtkBYUReader, vtkOBJReader, vtkSTLReader) from vtkmodules.vtkIOPLY import vtkPLYReader from vtkmodules.vtkIOXML import vtkXMLPolyDataReader from vtkmodules.vtkIOLegacy import vtkPolyDataReader from vtkmodules.vtkRenderingCore import vtkRenderer, vtkRenderWindow, vtkRenderWindowInteractor, vtkLight, vtkPolyDataMapper, vtkActor from vtkmodules.vtkFiltersSources import vtkCubeSource from vtkmodules.vtkRenderingOpenGL2 import vtkShadowMapPass, vtkCameraPass, vtkRenderPassCollection, vtkSequencePass def ReadPolyData(file_name): import os path, extension = os.path.splitext(file_name) extension = extension.lower() if extension == '.ply': reader = vtkPLYReader() reader.SetFileName(file_name) reader.Update() poly_data = reader.GetOutput() elif extension == '.vtp': reader = vtkXMLPolyDataReader() reader.SetFileName(file_name) reader.Update() poly_data = reader.GetOutput() elif extension == '.obj': reader = vtkOBJReader() reader.SetFileName(file_name) reader.Update() poly_data = reader.GetOutput() elif extension == '.stl': reader = vtkSTLReader() reader.SetFileName(file_name) reader.Update() poly_data = reader.GetOutput() elif extension == '.vtk': reader = vtkPolyDataReader() reader.SetFileName(file_name) reader.Update() poly_data = reader.GetOutput() elif extension == '.g': reader = vtkBYUReader() reader.SetGeometryFileName(file_name) reader.Update() poly_data = reader.GetOutput() else: poly_data = None return poly_data def main(): fn = "Data/cow.g" polyData = ReadPolyData(fn) colors = vtkNamedColors() colors.SetColor('HighNoonSun', [255, 255, 251, 255]) # Color temp. 5400°K colors.SetColor('100W Tungsten', [255, 214, 170, 255]) # Color temp. 2850°K renderer = vtkRenderer() renderer.SetBackground(colors.GetColor3d('Silver')) renderWindow = vtkRenderWindow() renderWindow.SetSize(640, 480) renderWindow.AddRenderer(renderer) interactor = vtkRenderWindowInteractor() interactor.SetRenderWindow(renderWindow) # 添加两束光源 light1 = vtkLight() light1.SetPosition(0, 1, 0.2) light1.SetFocalPoint(0, 0, 0) light1.SetColor(colors.GetColor3d('HighNoonSun')) """ SetIntensity 用来设置光源的亮度或强度 """ light1.SetIntensity(0.3) renderer.AddLight(light1) light2 = vtkLight() light2.SetFocalPoint(0, 0, 0) light2.SetPosition(1.0, 1.0, 1.0) light2.SetColor(colors.GetColor3d('100W Tungsten')) light2.SetIntensity(0.8) renderer.AddLight(light2) mapper = vtkPolyDataMapper() mapper.SetInputData(polyData) actor = vtkActor() actor.SetMapper(mapper) actor.GetProperty().SetAmbientColor(colors.GetColor3d('SaddleBrown')) actor.GetProperty().SetDiffuseColor(colors.GetColor3d('Sienna')) actor.GetProperty().SetSpecularColor(colors.GetColor3d('White')) actor.GetProperty().SetSpecular(0.51) actor.GetProperty().SetDiffuse(0.7) actor.GetProperty().SetAmbient(0.7) actor.GetProperty().SetSpecularPower(30.0) actor.GetProperty().SetOpacity(1.0) renderer.AddActor(actor) bounds = polyData.GetBounds() rnge = [0] * 3 rnge[0] = bounds[1] - bounds[0] rnge[1] = bounds[3] - bounds[2] rnge[2] = bounds[5] - bounds[4] expand = 1.0 thickness = rnge[2] * 0.1 plane = vtkCubeSource() plane.SetCenter((bounds[1] + bounds[0]) / 2.0, bounds[2] - thickness / 2.0, (bounds[5] + bounds[4]) / 2.0) plane.SetXLength(bounds[1] - bounds[0] + (rnge[0] * expand)) plane.SetYLength(thickness) plane.SetZLength(bounds[5] - bounds[4] + (rnge[2] * expand)) planeMapper = vtkPolyDataMapper() planeMapper.SetInputConnection(plane.GetOutputPort()) planeActor = vtkActor() planeActor.SetMapper(planeMapper) renderer.AddActor(planeActor) renderWindow.SetMultiSamples(0) """ vtkShadowMapPass vtk中用于实时阴影渲染的一个类 """ shadows = vtkShadowMapPass() """ vtkSequencePass 组合型渲染通道,本身不渲染任何内容,只是一个容器,可以把多个Pass放进去,它会一个一个按顺序调用 """ seq = vtkSequencePass() """ vtkRenderPassCollection 是用来存放和管理多个渲染 Pass(vtkRenderPass)对象的类,它经常和 vtkSequencePass 一起使用 主要作用: | 功能 | 说明 | ----------------------- | ---------------------------------- | 存储渲染 Pass | 存放多个 `vtkRenderPass` 实例 | 顺序访问 | 可以用迭代方式依次取出每个 Pass | 与 vtkSequencePass 协作 | `vtkSequencePass` 从中读取 Pass 并按顺序执行 | 构建渲染流程 | 常用于定义自定义的渲染顺序 常用方法: 方法 | 功能说明 AddItem(vtkRenderPass *pass)` 向集合中添加一个渲染 Pass GetNextRenderPass()` 依次获取下一个 Pass(内部遍历器) InitTraversal()` 重置遍历状态(准备从头遍历) RemoveAllItems()` 清空集合 GetNumberOfItems()` 返回当前包含的 Pass 数量 """ passes = vtkRenderPassCollection() """ 第一个Pass:用光源的视角去渲染场景,生成每个光源的深度贴图(shadow map),把结果存入GPU纹理 相当于“记录从光的角度看到的深度信息” """ passes.AddItem(shadows.GetShadowMapBakerPass()) #添加“阴影贴图生成阶段”(ShadowMapBakerPass) """ 第二个Pass:切换回主摄像机的视角,使用上一步生成的阴影贴图,在片元着色时计算每个点是否被遮挡 渲染带阴影的最终画面 """ passes.AddItem(shadows) # 再添加“阴影渲染阶段”(shadows 本身,即 vtkShadowMapPass) """ 把定义好的渲染 Pass 集合(vtkRenderPassCollection)交给 vtkSequencePass,让它按顺序执行这些 Pass """ seq.SetPasses(passes) """ 下面这段代码的作用是:创建一个相机渲染阶段 (vtkCameraPass) 并把你的自定义渲染序列(seq,即 vtkSequencePass)交给它执行 """ cameraP = vtkCameraPass() cameraP.SetDelegatePass(seq) renderer.SetPass(cameraP) """ 以上的结构关系图 vtkRenderer └── vtkCameraPass (cameraP) └── vtkSequencePass (seq) └── vtkRenderPassCollection (passes) ├── vtkShadowMapBakerPass └── vtkShadowMapPass """ renderer.GetActiveCamera().SetPosition(-0.2, 0.2, 1) renderer.GetActiveCamera().SetFocalPoint(0, 0, 0) renderer.GetActiveCamera().SetViewUp(0, 1, 0) renderer.ResetCamera() renderer.GetActiveCamera().Dolly(2.25) renderer.ResetCameraClippingRange() renderWindow.SetWindowName('Shadows') renderWindow.Render() renderWindow.SetWindowName('Shadows') interactor.Start() """ render本身会按照标准流程绘制场景, 设置相机; 绘制背景; 绘制演员; 绘制灯光阴影; 显示结果。 当调用了SetPass时,相当于自定义了以上的渲染流程,流程就变成了下面的顺序 Renderer.Render() → 调用 cameraP.Render() → cameraP 设置相机(镜头) → 调用 seq.Render() → 按顺序执行 passes: ShadowMapBakerPass(生成阴影) ShadowMapPass(渲染场景) """ if __name__ == '__main__': main()
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/10 12:01:27

红黑树插入情景分析:VibeThinker一步步带你理解旋转操作

红黑树插入情景分析:VibeThinker一步步带你理解旋转操作 在算法工程实践中,红黑树一直是个“既绕不开又难啃”的硬骨头。无论是准备面试、刷LeetCode,还是深入阅读STL源码,只要涉及高效有序容器,就几乎必然要面对它的五…

作者头像 李华
网站建设 2026/6/10 11:54:46

预训练模型十年演进(2015–2025)

预训练模型十年演进(2015–2025) 一句话总论: 2015年预训练模型还只是“Word2Vec静态词向量小规模无监督”的萌芽时代,2025年已进化成“万亿级多模态VLA大模型自监督/强化自进化量子加速全域意图级统一智能”的终极预训练范式&…

作者头像 李华
网站建设 2026/6/10 11:54:08

模型量化十年演进(2015–2025)

模型量化十年演进(2015–2025) 一句话总论: 2015年模型量化还是“后训练INT8手工标定精度损失5–10%”的实验阶段,2025年已进化成“量化感知训练QAT量子混合精度自适应端到端VLA万亿模型端侧部署自进化零损失量化”的普惠终极时代…

作者头像 李华
网站建设 2026/6/10 13:41:58

智能语言模型十年演进(2015–2025)

智能语言模型十年演进(2015–2025) 一句话总论: 2015年智能语言模型还是“RNN/LSTM序列预测小规模监督学习”的初级时代,2025年已进化成“万亿级多模态VLA统一大模型意图级实时推理量子鲁棒自进化全域社交/情感/具身行动”的终极智…

作者头像 李华
网站建设 2026/6/10 12:35:59

还在手动切换分支?自动化Git工作树隔离方案(Docker+CI/CD集成秘籍)

第一章:还在手动切换分支?自动化Git工作树隔离的必要性在现代软件开发中,多任务并行是常态。开发者常常需要同时处理多个功能开发、紧急修复和代码审查任务,而这些任务通常分布在不同的 Git 分支上。频繁地使用 git checkout 切换…

作者头像 李华
网站建设 2026/6/10 10:58:01

拯救者 Y9000K 开箱全记录:游戏本性能王者的开箱仪式感与细节揭秘!

对于游戏玩家和设计从业者来说,入手联想拯救者 Y9000K 绝对是值得期待的时刻 —— 作为拯救者系列的旗舰级游戏本,它不仅承载着强劲的性能表现,更在外观设计、接口配置、散热系统等方面备受关注。很多用户在开箱前都会充满好奇:包…

作者头像 李华