news 2026/6/12 17:13:59

PBR_Clear_Coat 实现一个具有 金属质感 + 镜面反射 + 天空盒光照 的立方体

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
PBR_Clear_Coat 实现一个具有 金属质感 + 镜面反射 + 天空盒光照 的立方体

一:主要的知识点

1、说明

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

2、知识点纪要

本段代码主要涉及的有①纹理的伽马校正,②清漆层


二:代码及注释

import json from pathlib import Path from vtkmodules.vtkRenderingCore import vtkPolyDataMapper, vtkActor from vtkmodules.vtkCommonColor import vtkNamedColors from vtkmodules.vtkRenderingOpenGL2 import vtkOpenGLRenderer from vtkmodules.vtkRenderingCore import vtkLight, vtkRenderWindow, vtkRenderWindowInteractor, vtkSkybox, vtkTexture from vtkmodules.vtkInteractionStyle import vtkInteractorStyleTrackballCamera from vtkmodules.vtkIOImage import vtkImageReader2Factory, vtkHDRReader, vtkPNGReader from vtkmodules.vtkImagingCore import vtkImageFlip from vtkmodules.vtkFiltersSources import vtkCubeSource from vtkmodules.vtkFiltersCore import vtkTriangleFilter, vtkPolyDataTangents def get_parameters(fn_path): """ Read the parameters from a JSON file and check that the file paths exist. :param fn_path: The path to the JSON file. :return: True if the paths correspond to files and the parameters. """ with open(fn_path) as data_file: json_data = json.load(data_file) parameters = dict() # Extract the values. keys_no_paths = {'title', 'object', 'objcolor', 'bkgcolor', 'skybox'} keys_with_paths = {'cubemap', 'equirectangular', 'albedo', 'normal', 'material', 'coat', 'anisotropy', 'emissive'} paths_ok = True for k, v in json_data.items(): if k in keys_no_paths: parameters[k] = v continue if k in keys_with_paths: if k == 'cubemap': if ('root' in v) and ('files' in v): root = Path(v['root']) if not root.exists(): print(f'Bad cubemap path: {root}') paths_ok = False elif len(v['files']) != 6: print(f'Expect six cubemap file names.') paths_ok = False else: cm = list(map(lambda p: root / p, v['files'])) for fn in cm: if not fn.is_file(): paths_ok = False print(f'Not a file {fn}') if paths_ok: parameters['cubemap'] = cm else: paths_ok = False print('Missing the key "root" and/or the key "fíles" for the cubemap.') else: fn = Path(v) if not fn.exists(): print(f'Bad {k} path: {fn}') paths_ok = False else: parameters[k] = fn # Set Boy as the default surface. if ('object' in parameters.keys() and not parameters['object']) or 'object' not in parameters.keys(): parameters['object'] = 'Boy' return paths_ok, parameters def read_cubemap(cubemap): cube_map = vtkTexture() cube_map.CubeMapOn() i = 0 for fn in cubemap: reader_factory = vtkImageReader2Factory() img_reader = reader_factory.CreateImageReader2(str(fn)) img_reader.SetFileName(str(fn)) flip = vtkImageFlip() flip.SetInputConnection(img_reader.GetOutputPort()) flip.SetFilteredAxis(1) cube_map.SetInputConnection(i, flip.GetOutputPort()) cube_map.MipmapOn() cube_map.InterpolateOn() return cube_map def read_equirectangular_file(fn_path): texture = vtkTexture() suffix = fn_path.suffix.lower() if suffix in ['.jpeg', '.jpg', '.png']: read_factory = vtkImageReader2Factory() reader = read_factory.CreateImageReader2(str(fn_path)) reader.SetFileName(str(fn_path)) texture.SetInputConnection(reader.GetOutputPort()) else: reader = vtkHDRReader() reader.SetFileName(str(fn_path)) texture.SetColorModeToDirectScalars() texture.SetInputConnection(reader.GetOutputPort()) texture.MipmapOn() texture.InterpolateOn() return texture def main(): fn = "Data/PBR_Parameters.json" use_cubemap = False paths_ok, parameters = get_parameters(fn) colors = vtkNamedColors() ren = vtkOpenGLRenderer() ren.SetBackground(colors.GetColor3d("Black")) """ AutomaticLightCreationOff 禁用渲染器的自动光照创建机制 在 VTK 中,为了让用户即使不手动添加光源也能看到3D模型,会先检查是否有光源,没有就会自动创建一个,防止场景一片漆黑 """ ren.AutomaticLightCreationOff() light = vtkLight() light.SetPosition(2.0, 0.0, 2.0) light.SetFocalPoint(0.0, 0.0, 0.0) ren.AddLight(light) ren_win = vtkRenderWindow() ren_win.SetSize(600, 600) ren_win.AddRenderer(ren) iren = vtkRenderWindowInteractor() iren.SetRenderWindow(ren_win) style = vtkInteractorStyleTrackballCamera() iren.SetInteractorStyle(style) irradiance = ren.GetEnvMapIrradiance() irradiance.SetIrradianceStep(0.3) skybox = vtkSkybox() is_hdr = False has_skybox = False gamma_correct = False if use_cubemap and 'cubemap' in parameters.keys(): env_texture = read_cubemap(parameters['cubemap']) if parameters['skybox']: skybox.SetTexture(env_texture) elif 'equirectangular' in parameters.keys(): env_texture = read_equirectangular_file(parameters['equirectangular']) if parameters['equirectangular'].suffix.lower() in '.hdr .pic': gamma_correct = True is_hdr = True if parameters['skybox']: skybox.SetFloorRight(0, 0, 1) skybox.SetProjection(vtkSkybox.Sphere) skybox.SetTexture(env_texture) has_skybox = True else: return ren.UseImageBasedLightingOn() if is_hdr: ren.UseSphericalHarmonicsOn() ren.SetEnvironmentTexture(env_texture, False) else: ren.UseSphericalHarmonicsOff() ren.SetEnvironmentTexture(env_texture, True) cube = vtkCubeSource() triangulation = vtkTriangleFilter() triangulation.SetInputConnection(cube.GetOutputPort()) tangents = vtkPolyDataTangents() tangents.SetInputConnection(triangulation.GetOutputPort()) mapper = vtkPolyDataMapper() mapper.SetInputConnection(tangents.GetOutputPort()) # 读取cube的表面的材质的照片 material_reader = vtkPNGReader() material_reader.SetFileName(parameters['material']) material = vtkTexture() material.InterpolateOn() material.SetInputConnection(material_reader.GetOutputPort()) # 颜色贴图的读取 albedo_reader = vtkPNGReader() albedo_reader.SetFileName(parameters['albedo']) albedo = vtkTexture() """ UseSRGBColorSpaceOn 这是 PBR 中最关键的设置之一,等同于对纹理进行输入伽马校正 大多数颜色贴图(包括 Albedo 贴图)都是在非线性的 sRGB 颜色空间中保存的。但是,渲染器内部的光照计算必须在线性空间中进行才能保证物理准确性 这确保了物体的基础颜色在渲染时不会显得过亮或过暗 """ albedo.UseSRGBColorSpaceOn() albedo.InterpolateOn() albedo.SetInputConnection(albedo_reader.GetOutputPort()) # 法相贴图的读取 normal_reader = vtkPNGReader() normal_reader.SetFileName(parameters['normal']) normal = vtkTexture() normal.InterpolateOn() normal.SetInputConnection(normal_reader.GetOutputPort()) # 作用于清漆层(Clear Coat)的法线贴图 """ 清漆层(Coat Layer)是指覆盖在主体材质(Base Material)之上的一层薄而透明的保护层 现实世界示例: 汽车漆(最外层的透明保护漆)、家具上的清漆/光油、带有釉面的陶瓷。 物理效果: 清漆层有自己的反射和粗糙度属性,它会独立地产生一次反射(高光),并且这层反射是半透明的, 因此光线会穿透它,击中下方的基础材质,再产生第二次反射(漫反射和基础反射)。 coat_normal就是一张法线贴图,但它只应用于最外面的清漆层 """ coat_normal = vtkTexture() coat_normal.InterpolateOn() coat_normal.SetInputConnection(normal_reader.GetOutputPort()) actor = vtkActor() actor.SetOrientation(0.0, 25.0, 0.0) actor.SetMapper(mapper) actor.GetProperty().SetInterpolationToPBR() actor.GetProperty().SetMetallic(1.0) actor.GetProperty().SetRoughness(1.0) """ SetCoatStrength 启用并设置清漆层的强度为 1.0(最大强度)。这模拟了物体表面覆盖着一层透明的保护漆或釉面。 """ actor.GetProperty().SetCoatStrength(1.0) """ SetCoatColor 定义清漆层的高光颜色。在这里设置为 'Red',意味着清漆层反射的光线会带有红色调,模拟一些特殊的着色清漆。 """ actor.GetProperty().SetCoatColor(colors.GetColor3d('Red')) """ SetBaseColorTexture 用于定义物体表面的基础颜色。这是材质的“底色”。 """ actor.GetProperty().SetBaseColorTexture(albedo) """ SetORMTexture 设置材质属性,通常一个3D模型的材质属性会存储在三原色通道中: - R 通道: Occlusion (环境光遮蔽) - G 通道: Roughness (粗糙度) - B 通道: Metallic (金属性) """ actor.GetProperty().SetORMTexture(material) """ SetNormalTexture 添加法线贴图 """ actor.GetProperty().SetNormalTexture(normal) """ SetCoatNormalTexture 清漆层法线贴图 """ actor.GetProperty().SetCoatNormalTexture(coat_normal) ren.AddActor(actor) if has_skybox: if gamma_correct: skybox.GammaCorrectOn() else: skybox.GammaCorrectOff() ren.AddActor(skybox) ren_win.SetWindowName('PBR_Clear_Coat') ren_win.Render() ren.GetActiveCamera().Zoom(1.5) iren.Start() if __name__ == '__main__': main()
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/10 13:13:58

Unity引擎实时渲染画面+HeyGem后期配音合成

Unity引擎实时渲染画面 HeyGem后期配音合成 在企业培训视频制作的日常中,你是否遇到过这样的场景:同一套课件内容,需要为不同地区、不同语言的员工分别录制讲解视频?传统方式下,这意味着重复搭建场景、反复调整灯光动…

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

飞书妙记转写文字+TTS生成音频+HeyGem合成

飞书妙记转写文字 TTS生成音频 HeyGem 合成数字人视频:构建高效 AIGC 视频生产线 在企业内容生产日益高频、个性化的今天,一个常见的痛点浮现出来:如何快速将一场会议、一次培训或一段讲稿,变成多个版本的专业级播报视频&#x…

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

汽车客运站大变样!护照阅读器成出行新“神器”

在保障车站安全方面,护照阅读器更是 “功不可没”。它能与公安系统联网,实时比对旅客身份信息和重点人员数据库。一旦发现可疑人员,比如失信被执行人、在逃人员,系统立即发出警报,车站工作人员和安保人员可及时采取措施…

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

掌握C#集合表达式只需8分钟:让列表编码效率飙升的终极方法

第一章:C#集合表达式的核心概念集合表达式的定义与作用 C# 集合表达式是一种用于声明和初始化集合类型的简洁语法,允许开发者在一行代码中创建并填充数组、列表或其他可枚举类型。该特性自 C# 12 起被引入,显著提升了代码的可读性和编写效率。…

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

你还在手动排查错误?,C#智能日志系统让问题无处遁形

第一章:你还在手动排查错误?,C#智能日志系统让问题无处遁形在现代软件开发中,手动追踪异常和调试问题已不再高效。C# 应用通过集成智能日志系统,能够自动记录运行时状态、异常堆栈和关键业务流程,极大提升故…

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

GitLab Runner执行HeyGem视频生成流水线实验

GitLab Runner执行HeyGem视频生成流水线实验 在内容生产日益智能化的今天,企业对高效、标准化视频输出的需求正以前所未有的速度增长。从在线教育课程到产品宣传短片,传统依赖人工剪辑与专业设备的制作流程已难以应对高频、批量化的任务挑战。与此同时&a…

作者头像 李华