0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

NVIDIA Omniverse USD插件开发中的UI卡顿问题复现及分析

丽台科技 来源:丽台科技 2025-11-03 15:17 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

UI 卡顿问题复现及分析

在进行 NVIDIA Omniverse USD 插件开发的时候遇到了一个性能卡顿的问题,这个功能的初衷是通过路径追踪和原始的绿幕视频,借助 Omniverse Farm 来实现高质量的后期自动化流程,实现思路是记录相机定位 FreeD 的运动轨迹,并记录保存到一个 USD 的 sublayer 当中,根据时间码(Timecode)进行后期自动化合成的流程,流程图如下:

dd8a5bde-b4ac-11f0-8c8f-92fbcf53809c.png

在外部摄影机记录原始的绿幕影片素材的时候,点击开始 / 结束分别会触发一个时间码 (Timecode)的信号,信号可以在 BMD 采集卡当中通过 SDK 获得,这样我们把从开始到结束的相机定位轨迹记录存至 buffer 中,然后更新到 USD 的 stage sublayer 中。

首先通过 Python API 创建一个 Sublayer,把记录的 sequence 通过 USD time sampler 记录到相机 prim 的 attribute 下面,仅对一万个 time sampler 进行记录并统一写入该 sublayer,后观察到该写入过程耗时达数十秒,且造成 Omniverse 主线程 UI 出现卡顿。经测试,无论采用同步、异步 AsyncIO 或线程方式执行操作,均未使情况得到改善,UI 卡死现象始终存在。(可以查看代码文件中注释的 1、2、3)

Tracy.py 的源代码如下:

importomni.kit.app
importtime
importasyncio
frompxrimportSdf, Usd, UsdGeom, Gf
fromomni.kit.usd.layersimportLayerUtils, get_layers, LayerEditMode
importomni.kit.commands
fromcollectionsimportdeque
importos
fromtypingimportList,Tuple
fromomni.kit.widget.layers.path_utilsimportPathUtils
importcarb
fromtypingimportList,Tuple
fromenumimportEnum
importasyncio
frompxrimportSdf, Usd, UsdGeom
frompxrimportUsd, UsdGeom, Gf
fromomni.kit.async_engineimportrun_coroutine
fromconcurrent.futuresimportALL_COMPLETED, ThreadPoolExecutor, wait


defcreate_prim(stage, prim_path="/World/Camera"):
  prim = stage.GetPrimAtPath(prim_path)
 ifprimandprim.GetTypeName() =="Camera":
    carb.log_info(f"Camera already exists at:{prim_path}")
   returnprim
 else:
    camera_prim = UsdGeom.Camera.Define(stage, prim_path)
    camera_prim.AddTranslateOp().Set(Gf.Vec3d(10,20,30))
    camera_prim.AddRotateXYZOp().Set(Gf.Vec3f(0,45,0))
    carb.log_info(f"Created new Camera at:{prim_path}")
   returncamera_prim.GetPrim()
 
classTestClass:
 def__init__(self):
    self._rotate_queue = deque()
    self._translate_queue = deque()
    self._pts_queue = deque()
    self._pts =0
    self._Layer_num =0


 defcreate_sublayer(self, _root_layer, strLayerName, orderIndex, bSetAuthoring):
   #layname =
    self._Layer_num +=1
    identifier1 = LayerUtils.create_sublayer(_root_layer, orderIndex, strLayerName).identifier
   #
   ifbSetAuthoring:
      omni.kit.commands.execute("SetEditTargetCommand", layer_identifier=identifier1)


 defprepare_data(self):
    begin = time.time()
    rotation_1 = Gf.Vec3f(0.0,0.0,0.0)
    _translate = Gf.Vec3d(0.0,0.0,0.0)
   for_inrange(10000):
      self._rotate_queue.append(rotation_1)
      self._translate_queue.append(_translate)
    end = time.time()


    carb.log_info(f"prepare_data elaspe:{end - begin}")


 asyncdefawait_flush_save(self):
    carb.log_info("before await_flush_save {time.time()}")
   awaitomni.kit.app.get_app().next_update_async()
    self.flush_save()
    carb.log_info("end await_flush_save {time.time()}")


 defflush_save(self):
    timecode =0
   whileself._rotate_queueorself._translate_queue:
     ifself._rotate_queue:
        f_val = self._rotate_queue.popleft()
        self._rotation_ops.Set(time = timecode, value = f_val)
     ifself._translate_queue:
        d_val = self._translate_queue.popleft()
        self._translate_ops.Set(time = timecode, value = d_val)


      timecode +=10


    self._render_update_sub =None


 asyncdefawaitflush(self):
   awaitomni.kit.app.get_app().next_update_async()
    self.flush_save(self)


 asyncdefflush_save_async(self):
    time0 = time.perf_counter()
    carb.log_info("flush_save_async begin")
    loop = asyncio.get_running_loop()
   # 直接调用同步函数(主线程),但用await asyncio.sleep(0)切分事件循环
   awaitloop.run_in_executor(None, self.flush_save)
    time1 = time.perf_counter()
    carb.log_info(f"flush_save_async end elaspe:{time1 - time0}")


 definit_stage_camera(self, stage, camera_prim_path):
    self._stage = stage
    self._camera_path = camera_prim_path
    self._camera_prim = UsdGeom.Camera.Get(stage, camera_prim_path).GetPrim()
    xform_ops = UsdGeom.Xformable(self._camera_prim).GetOrderedXformOps()


   foropinxform_ops:
       ifop.GetOpType()in[UsdGeom.XformOp.TypeRotateXYZ,
            UsdGeom.XformOp.TypeRotateXZY,
            UsdGeom.XformOp.TypeRotateYXZ,
            UsdGeom.XformOp.TypeRotateYZX,
            UsdGeom.XformOp.TypeRotateZXY,
            UsdGeom.XformOp.TypeRotateZYX]:
         #rotation = op.Get()
          self._rotation_type = op.GetOpType()
          self._rotation_ops = op
         #print(f"rotation is {rotation}")
       elifop.GetOpType() == UsdGeom.XformOp.TypeScale:
          self._scale_ops = op
       elifop.GetOpType() == UsdGeom.XformOp.TypeTranslate:
          self._translate_ops = op


if__name__ =="__main__":
  _stage = omni.usd.get_context().get_stage()
  root_layer = _stage.GetRootLayer()
  prim_path ="/World/Camera"
  new_layer_path ="d:/camera_sublayer.usd"
  runclass = TestClass()
 
  create_prim(_stage, prim_path)
  runclass.init_stage_camera(_stage, prim_path)
  runclass.create_sublayer(root_layer, new_layer_path,0,True)
  runclass.prepare_data()
 
  begin = time.time()
  carb.log_info(f"before run coroutine")
 #(1)Async block UI for about 50 seconds
  run_coroutine(runclass.await_flush_save())
 #(2)Also block UI about 50 seconds
 # with ThreadPoolExecutor() as executor:
 #   executor.submit(runclass.flush_save())
 #(3)Sync, same block
 #self.flush_save()


  end = time.time()
  carb.log_info(f"elaspe time is{end-begin}, 10000 ends")

* 附代码链接:https://github.com/slayersong/OVPerf_Tracy/blob/main/tracy_profiler.py(复制链接至浏览器打开)

复现问题:打开菜单中的Developer --Script Editor,打开 tray_profiler.py 文件,然后点击 Run,可以看到创建了一个 camera_sublayer,并且主 UI 卡住了几十秒无响应。

需要注意的是,在 Omniverse USD 的 layer 层级继承覆盖当中,在上层的 Layer 的行为会覆盖下层的 layer,关于 USD layer 层级的关系,请查看本文结尾提供的 DLI 课程链接。

dde56ed4-b4ac-11f0-8c8f-92fbcf53809c.png

然后在 Content Browser 中单击鼠标右键,选择 Edit,可以看到数据成功写入了 USD 文件,只是中间卡顿的时间过长。

de3a43b4-b4ac-11f0-8c8f-92fbcf53809c.png

分析:在遇到 Profiler 的时候不要盲猜,可能是 memory、IO Bound、Compute Bound 或者一些不太能想到的情况,这时候则需要利用专业化的工具进行分析定位,找到问题所在并解决,比如可以利用著名工具Tracy(https://github.com/wolfpld/tracy),该工具可以分析 CPU / GPU 性能瓶颈,并支持主流 Graphics API:DX、Vulkan、OpenGL、CUDA 等,且 Omniverse 已经把该工具与 Omniverse Kit 进行了集成。因此可以利用 Tracy 去看底层的 CallStack 里什么影响了这个操作,在 Omniverse 当中,Tracy 已经配置好了 Symbol 符号表, 可以看到底层的代码函数调用堆栈,后而寻找具体是什么情况卡住了不正常的几十秒时间。

Tracy 的使用

2.1 操作介绍

Omniverse 已经集成了 Tracy 的开发集成插件:https://docs.omniverse.nvidia.com/extensions/latest/ext_profiler_tracy.html

Tracy 本身是一个著名的分析工具,具体的菜单操作可以参考知乎这个帖子:https://zhuanlan.zhihu.com/p/1915041165033607442

UI 操作的详细讲解可参考如下视频:

Tracy 讲解文档

视频参考:

https://www.bilibili.com/video/BV1or421J7Du/?spm_id_from=333.337.search-card.all.click

文档参考:

https://github.com/CppCon/CppCon2023/blob/main/Presentations/Tracy_Profiler_2024.pdf

2.2 安装

首先打开菜单 Developer -- Extension 搜索,找到 Profiler Tracy 并且安装。

de9610ea-b4ac-11f0-8c8f-92fbcf53809c.png

然后会出现一个新的 Profiler 菜单,点击 Profiler --Tracy --Launch and Connect。

deea4f66-b4ac-11f0-8c8f-92fbcf53809c.png

Tracy 基本使用操作:

1. Pause:在实时监测到发生性能瓶颈的事件以后要暂停,否则时间轴会一直向右走

2. 按住鼠标右键可以拖动到你想要的位置

3. 鼠标滚轮:Zoom in / out

2.3 分析问题

运行上述代码,点击 Tracy 中的 Pause 暂停(不暂停 Tracy 会一直记录的一直滚动)。之后按住 Ctrl 和鼠标中间的滚轮,Zoom 缩小操作,可以很容易找到一个最大的耗时,从 11 秒开始到 31 秒,这一个 Frame Render 用了二十几秒(注意:函数的调用堆栈已经正确显示),可以发现卡在了 RenderThread 中的usd_mutex_wait函数上面:

df4b994c-b4ac-11f0-8c8f-92fbcf53809c.png

这样通过 Tracy 的使用就明白了问题卡住的大致原因,简而言之,渲染线程会等待 USD 写入的结束,一直卡在usd_mutex_wait。

2.4 解决问题

分析:该问题的本质其实是 USD 的写入与修改会非常的慢,这是 USD 的基础架构造成的。

单单针对这个问题解决的方法不复杂,可以思考一下,写入的 Sublayer 其实并不需要实时参与 USD Composite, 因为我们并不需要实时观察到合成结果,可以创建离线的 Sublayer ,等待写入结束以后再自动或者手动把 Sublayer 加入进来,代码如下,看到并没有卡顿这一个过程,那么问题就解决了。

针对此次问题的 Solution 如下:

importomni.kit.app
importtime
importasyncio
frompxrimportSdf, Usd, UsdGeom, Gf
fromomni.kit.usd.layersimportLayerUtils, get_layers, LayerEditMode
importomni.kit.commands
fromcollectionsimportdeque
importos
fromtypingimportList,Tuple
fromomni.kit.widget.layers.path_utilsimportPathUtils
importcarb
fromtypingimportList,Tuple
fromenumimportEnum
importasyncio
frompxrimportSdf, Usd, UsdGeom
frompxrimportUsd, UsdGeom, Gf
fromomni.kit.async_engineimportrun_coroutine
fromconcurrent.futuresimportALL_COMPLETED, ThreadPoolExecutor, wait


defcreate_prim(stage, prim_path="/World/Camera"):
  prim = stage.GetPrimAtPath(prim_path)
 ifprimandprim.GetTypeName() =="Camera":
    carb.log_info(f"Camera already exists at:{prim_path}")
   returnprim
 else:
    camera_prim = UsdGeom.Camera.Define(stage, prim_path)
    camera_prim.AddTranslateOp().Set(Gf.Vec3d(10,20,30))
    camera_prim.AddRotateXYZOp().Set(Gf.Vec3f(0,45,0))
    carb.log_info(f"Created new Camera at:{prim_path}")
   returncamera_prim.GetPrim()


classTestClass:
 def__init__(self):
    self._rotate_queue = deque()
    self._translate_queue = deque()
    self._pts_queue = deque()
    self._pts =0
 
 defregis(self):
    self._app = omni.kit.app.get_app()     
    self._render_update_sub = self._app.get_update_event_stream().create_subscription_to_pop(
    self.pre_frame_render, order=-10, name="gm_render_event")
 
 defpre_frame_render(self,e):
    self._pts +=1
    self.get_push_pos_rotate(self._pts)
   
   ifself._pts ==1000:
      begin = time.time()
      carb.log_info(f"before run coroutine")
      run_coroutine(self.await_flush_save())
     #self.flush_save()
      carb.log_info(f"end run coroutine")
      end = time.time()
      carb.log_info(f"elaspe time is{end-begin}")
      self._render_update_sub =None
 
 defget_push_pos_rotate(self, pts):
    rotae = self._rotation_ops.Get()
    translate = self._translate_ops.Get()
   
    self._rotate_queue.append(rotae)
    self._translate_queue.append(translate)
    self._pts_queue.append(pts)
 
 defprepare_data(self):
    begin = time.time()
   
    rotation_1 = Gf.Vec3f(0.0,0.0,0.0)
    _translate = Gf.Vec3d(0.0,0.0,0.0)
   foriinrange(500):
     # rotation_1 = Gf.Vec3f(0.0, 0.0, 0.0)
     # _translate = Gf.Vec3d(0.0, 0.0, 0.0)
      rotation_1 = Gf.Vec3f(-253.0, i * (360.0/499),93) # 99是为了最后一次达到360
     # _translate的xyz从0递增到100
      _translate = Gf.Vec3d(2124.0, 2124.0, 104)
     
      self._rotate_queue.append(rotation_1)
      self._translate_queue.append(_translate)
    end = time.time()
   
    carb.log_info(f"prepare_data elaspe:{end - begin}")
 
 asyncdefawait_flush_save(self):
    carb.log_info("before await_flush_save {time.time()}")
   awaitomni.kit.app.get_app().next_update_async()
    self.flush_save()
    carb.log_info("end await_flush_save {time.time()}")
 
 defflush_save(self):
    timecode =0
   whileself._rotate_queueorself._translate_queue:
     ifself._rotate_queue:
        f_val = self._rotate_queue.popleft()
       #self._rotation_ops.Set(time = timecode, value = f_val)
        self.seq_write_rotate_op.Set(time = timecode, value = f_val)
     ifself._translate_queue:
        d_val = self._translate_queue.popleft()
        self.seq_write_translate_op.Set(time = timecode, value = d_val)
       #self._translate_ops.Set(time = timecode, value = d_val)
     
      timecode +=10
   
    self._sub_stage.GetRootLayer().Save()
    self._render_update_sub =None
 
 asyncdefawaitflush(self):
   awaitomni.kit.app.get_app().next_update_async()
    self.flush_save(self)
 
 asyncdefflush_save_async(self):
    time0 = time.perf_counter()
    carb.log_info("flush_save_async begin")
    loop = asyncio.get_running_loop()
   # 直接调用同步函数(主线程),但用await asyncio.sleep(0)切分事件循环
   awaitloop.run_in_executor(None, self.flush_save)
    time1 = time.perf_counter()
    carb.log_info(f"flush_save_async end elaspe:{time1 - time0}")
 
 defcreate_offline_layer(self, layer_base_path, prim_path, bOverride):
   # split name and ext
    name, ext = os.path.splitext(layer_base_path)
   
    index =1
    new_layer_path = layer_base_path
   
   #If exist create a new path such as basepath_1.usd
   whileos.path.exists(new_layer_path):
      new_layer_path =f"{name}_{index}{ext}"
      index +=1
   
    new_layer = Sdf.Layer.CreateNew(new_layer_path)
   
   # 2. 打开该layer对应的Stage(编辑该layer)
    self._sub_stage = Usd.Stage.Open(new_layer)
   
   # 3. 以over方式定义相机Prim(覆盖已有的/world/Camera)
   ifbOverride:
      self._seq_camera_prim = self._sub_stage.OverridePrim(prim_path)
      self._seq_camera_prim.SetSpecifier(Sdf.SpecifierOver)
   else:
      self._seq_camera_prim = self._sub_stage.DefinePrim(prim_path)
   
   # 4. 获取或创建Xformable接口,用于添加变换操作
    xformable = UsdGeom.Xformable(self._seq_camera_prim)
   
   # 5. 添加translate和rotateXYZ操作
    self.seq_write_translate_op = xformable.AddTranslateOp()
    self.seq_write_rotate_op = xformable.AddRotateXYZOp()
   
 definit_stage_camera(self, stage, camera_prim_path):
    self._stage = stage
    self._camera_path = camera_prim_path
    self._camera_prim = UsdGeom.Camera.Get(stage, camera_prim_path).GetPrim()
    xform_ops = UsdGeom.Xformable(self._camera_prim).GetOrderedXformOps()
   
   foropinxform_ops:
       ifop.GetOpType()in[UsdGeom.XformOp.TypeRotateXYZ,
            UsdGeom.XformOp.TypeRotateXZY,
            UsdGeom.XformOp.TypeRotateYXZ,
            UsdGeom.XformOp.TypeRotateYZX,
            UsdGeom.XformOp.TypeRotateZXY,
            UsdGeom.XformOp.TypeRotateZYX]:
         #rotation = op.Get()
          self._rotation_type = op.GetOpType()
          self._rotation_ops = op
         #print(f"rotation is {rotation}")
       elifop.GetOpType() == UsdGeom.XformOp.TypeScale:
          self._scale_ops = op
       elifop.GetOpType() == UsdGeom.XformOp.TypeTranslate:
          self._translate_ops = op


if__name__ =="__main__":
  _stage = omni.usd.get_context().get_stage()
 
  prim_path ="/World/Camera"
  new_layer_path ="d:\tes303.usda"
 
  runclass = TestClass()
  create_prim(_stage, prim_path)
  runclass.init_stage_camera(_stage, prim_path)
 
  runclass.create_offline_layer(new_layer_path, prim_path,True)
  carb.log_info("create_offline_layer after")
 
 #runclass.regis()
  runclass.prepare_data()
  begin = time.time()
  carb.log_info(f"before run coroutine")
  run_coroutine(runclass.flush_save_async())
 #run_coroutine(runclass.await_flush_save())
 #runclass.flush_save()
  carb.log_info(f"end run coroutine")
 #runclass.flush_save()
 # with ThreadPoolExecutor() as executor:
 #   executor.submit(runclass.flush_save())
 
  end = time.time()
  carb.log_info(f"elaspe time is{end-begin}, 1000 ends")


# class YourClass:
#   def __init__(self):
#     # 初始化队列等
#     pass


#   def flush_save(self):
#     # 这是同步函数,不能改动
#     # 里面调用了Omniverse API,必须在主线程执行
#     print("Begin flush save")
#     time.sleep(1)
#     print("end flush save")


#   async def flush_save_async(self):
#     time0 = time.perf_counter()
#     print("run task begin")
#     loop = asyncio.get_running_loop()
#     # 直接调用同步函数(主线程),但用await asyncio.sleep(0)切分事件循环
#     await loop.run_in_executor(None, self.flush_save)
#     time1 = time.perf_counter()
#     print(f"run task end elaspe:{time1 - time0}")
 
#   async def testawait():
#     pass




# # obj = YourClass()


# # run_coroutine(obj.flush_save_async())
# # print(f"run pass the async")
# # count = 0


# # def pre_frame_render(e):
# #   #print(f"Frame Begin: {app.get_update_number()} {e.payload}, event-type {e.type}, {time.time() * 1000 % 1000000} ")
# #   asyncio.ensure_future(obj.flush_save_async())
# # async def run_task():
# #   time0 = time.perf_counter()
# #   print("run task begin")
# #   await obj.flush_save_async()
# #   print("run task end")
# #   time1 = time.perf_counter()


# #   elapse_time = time1 - time0
# #   print(f"run taks elapse is {elapse_time}")


# # def frame_render(e):
# #   print(f"Frame Render: {app.get_update_number()} {e.payload}, event-type {e.type}, {time.time() * 1000 % 1000000}")


# # def post_frame_render(e):
# #   print(f"Frame End: {app.get_update_number()} {e.payload}, event-type {e.type}, {time.time() * 1000 % 1000000}")


# first_last_event = 1000000


# # pre_update_sub = app.get_pre_update_event_stream().create_subscription_to_pop(
# #   pre_frame_render, order=-first_last_event, name="gm_frame_begin")


# #asyncio.ensure_future(obj.flush_save_async())

* 附代码链接:https://github.com/slayersong/OVPerf_Tracy/blob/main/solution_%20tracy_profiler.py

但是在一些项目当中一定要实时观察到结果。比如,有很多的数字孪生的工业场景中会存在小车传送带,各种物品都是实时进入到场景管线当中,这其中必定要参与 USD 合成。

所以这里介绍一个 Omniverse 对 USD 进行重构的基本概念 Fabric,USDRT(USDRT 是 Fabric 的 API),NVIDIA 在 Omniverse 当中开发了 Fabric 组件专门处理 USD 实时更改缓慢的问题:

https://docs.omniverse.nvidia.com/kit/docs/usdrt/latest/docs/usd_fabric_usdrt.html

通过这个官方文档的图也验证了刚才的结论:Render 线程会等待 USD 的合成结果 Composed 后进行渲染。

dfa0bd8c-b4ac-11f0-8c8f-92fbcf53809c.png

结束:如果单解决这个问题其实并不复杂,但是其中需要用到很多的基础知识,包括 USD 的合成机制、多线程开发、遇到问题如何去利用工具定位分析等。后面我们将会对 USDRT 与 Fabric 进行更细致的讲解,包括代码的开发使用和 Omniverse 中其他性能工具的使用教程。也希望更多的朋友可以分享在 USD 开发过程当中的心得体会。

附录:

关于前面提到的 USD 的基本开发教程,包括 USD 合成机制,USD 基本动画 TimeSampler 等:

文案提供和技术支持:

宋毅明

NVIDIA Omniverse & OpenUSD 开发者关系经理

*与 NVIDIA 产品相关的图片或视频(完整或部分)的版权均归 NVIDIA Corporation 所有。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • NVIDIA
    +关注

    关注

    14

    文章

    5496

    浏览量

    109110
  • 摄影机
    +关注

    关注

    0

    文章

    73

    浏览量

    10904
  • 插件
    +关注

    关注

    0

    文章

    345

    浏览量

    23420

原文标题:Omniverse 性能优化系列(一):Tracy Profiler

文章出处:【微信号:Leadtek,微信公众号:丽台科技】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    LabviewUI无法刷新

    Labview调用C的DLL,这个过程没有问题。但执行其中一个函数时,不但UI,而且整个labview都卡住了。这有解吗?跑到ConnectDevice时,卡住了,只有连上了手机,
    发表于 03-27 11:38

    NVIDIA透露即将发布的Blender 3.0将包括USD支持

    在SIGGRAPH的特别演讲NVIDIA透露即将发布的Blender 3.0将包括USD支持。 新版本
    的头像 发表于 08-16 15:56 2338次阅读

    NVIDIANVIDIA Omniverse带给全球超过250万的开发

    NVIDIA开发者计划现将NVIDIA Omniverse带给全球超过250万的开发者。在SIGGRAPH大会,
    的头像 发表于 08-16 16:08 1989次阅读

    利用NVIDIA Omniverse加速游戏开发管线

      对于没有丰富脚本或编码经验的团队成员,Omni.UI Graph 是一个易于使用的图形编辑框架,用于为扩展程序或应用程序开发自定义行为。借助 Omni.UI Graph、Omniverse
    的头像 发表于 04-22 09:44 1763次阅读
    利用<b class='flag-5'>NVIDIA</b> <b class='flag-5'>Omniverse</b>加速游戏<b class='flag-5'>开发</b>管线

    NVIDIA USD是什么 有哪些功能

    USDNVIDIA Omniverse 的基础,这个实时协作平台可让各种内容创作工具相互连接。
    的头像 发表于 06-21 09:30 2353次阅读

    NVIDIA SIGGRAPH的最新发布与重要更新

    在今年的 SIGGRAPH 2022 上,NVIDIA 宣布,为基于通用场景描述(USD)连接和构建元宇宙世界的平台——NVIDIA Omniverse 提供一系列新的
    的头像 发表于 08-12 11:14 1227次阅读

    Omniverse 中文课程系列 1: 开发 Extensions 来自定义 Omniverse 功能与 UI

    Omniverse 定制化开发和发布 Extensions 学习目标 想要根据自己的喜好更改 Omniverse 的功能和用户界面(UI
    的头像 发表于 05-27 17:45 1335次阅读
    <b class='flag-5'>Omniverse</b> 中文课程系列 1: <b class='flag-5'>开发</b> Extensions 来自定义 <b class='flag-5'>Omniverse</b> 功能与 <b class='flag-5'>UI</b>

    奥比光将接入 NVIDIA Omniverse开发平台

    ,作为其合作伙伴,奥比光正式宣布将Femto Mega和其它3D相机集成到NVIDIA Omniverse生态开发平台中。 NVIDIA
    的头像 发表于 05-31 09:03 1383次阅读

    Omniverse 中文课程系列 2:USD 入门、基础与进阶 — 赋能协同 3D 工作流

    Omniverse 中文课程系列 现 已上线 NVIDIA 深度学习培训中心(DLI)! 跟随 官方中文讲解视频 、 详细的图文说明 和 代码演示 等,一起玩转 Omniverse! 适用于协同
    的头像 发表于 06-04 02:25 1521次阅读
    <b class='flag-5'>Omniverse</b> 中文课程系列 2:<b class='flag-5'>USD</b> 入门、基础与进阶 — 赋能协同 3D 工作流

    Omniverse 中文课程系列 3:实战练习如何成为自定义 UI 界面大师

    Omniverse 为 3D 工具构建漂亮的自定义 UI 界面 学习目标 如果您是虚拟世界的构建者和创作者,那么您一定不能错过亲身体验 NVIDIA Omniverse 套件
    的头像 发表于 06-09 20:45 1333次阅读
    <b class='flag-5'>Omniverse</b> 中文课程系列 3:实战练习如何成为自定义 <b class='flag-5'>UI</b> 界面大师

    NVIDIA 知乎精彩问答甄选 | 查看 NVIDIA Omniverse 相关精彩问答

    Omniverse 的应用,可提供适用于完整的 USD 工作流程的新协作界面,让艺术家在创作时更加自由。 OmniLive Workflows 可以对 Omniverse
    的头像 发表于 08-01 19:55 982次阅读
    <b class='flag-5'>NVIDIA</b> 知乎精彩问答甄选 | 查看 <b class='flag-5'>NVIDIA</b> <b class='flag-5'>Omniverse</b> 相关精彩问答

    SIGGRAPH 2023 | NVIDIA Omniverse 开启通往 OpenUSD 广阔天地的大门

    全新 Omniverse Cloud API 帮助开发者采用 OpenUSD;生成式 AI 模型 ChatUSD LLM 使用 USD 进行对话;RunUSD 将 USD 转换成交互式
    的头像 发表于 08-09 19:10 716次阅读

    NVIDIA Omniverse的物理模拟功能

    NVIDIA Omniverse™ Simulation 作为 NVIDIA Omniverse™ 平台的关键组件之一,由 NVIDIA
    的头像 发表于 03-08 11:30 2533次阅读
    <b class='flag-5'>NVIDIA</b> <b class='flag-5'>Omniverse</b><b class='flag-5'>中</b>的物理模拟功能

    NVIDIA Omniverse USD Composer能用来做什么?如何获取呢?

    NVIDIA OmniverseUSD Composer(以前称为 Create)是 NVIDIA Omniverse™ 中用于构建虚拟
    的头像 发表于 05-20 10:07 2014次阅读
    <b class='flag-5'>NVIDIA</b> <b class='flag-5'>Omniverse</b> <b class='flag-5'>USD</b> Composer能用来做什么?如何获取呢?

    Omniverse教程(12):NVIDIA Omniverse USD Presenter的基础应用

    如前所述,NVIDIA Omniverse™ 是一个参考开发平台,通过模块化的开发框架能够轻松扩展和自定义。
    的头像 发表于 05-20 10:09 1663次阅读
    <b class='flag-5'>Omniverse</b>教程(12):<b class='flag-5'>NVIDIA</b> <b class='flag-5'>Omniverse</b> <b class='flag-5'>USD</b> Presenter的基础应用