3Delight是应用于高端电影级别渲染的软件渲染器,迄今为止已经参与了无数的电影制作,具体可以参见链接。

如果你对3Delight的印象就依然是RenderMan的替代品,那就显然已经和时代发展脱节了。现在的3Delight是一个完全PBR Unbiased的渲染器,而且完全为了交互式渲染以及云端渲染设计,所以你对它的固有印象可以从看到这篇文章开始彻底改变了。

渲染=数据操作

其实“渲染”这个动作的本身,就是数据处理,你可以用任何流行的思路来对照,比如MapReduce。但是归根结底,可以认为只有3个概念。

  • 数据填充
  • 数据修改
  • 数据计算

这3个概念可以直接展开,把你所知道所有的计算机图形学相关的概念和技术都丢入,但是这里不展开。

本文会结合这3个概念,来仔细的阐述3Delight NSI的优点和思路,以及解决的问题。

一切从过程开始

计算机,其实是过程性设备。所谓面向对象,只是软件设计领域的一个对过程和数据的合并抽象而已,本质上,最后的“执行”这个本身依然是个过程。

那么回顾一下RenderMan API(以下简称RI)的设计。

RenderMan

一个完整RI可渲染的场景一般结构如下,来自这里。

 1 ##RenderMan RIB-Structure 1.1
 2 ##Scene Bouncing Ball
 3 ##Creator /usr/ucb/vi
 4 ##CreationDate 12:30pm 8/24/89
 5 ##For RenderMan Jones
 6 ##Frames 2
 7 ##Shaders PIXARmarble, PIXARwood, MyUserShader
 8 ##CapabilitiesNeeded ShadingLanguage Displacements
 9 version 3.03
10 Declare "d" "uniform point"
11 Declare "squish" "uniform float"
12 Option "limits" "bucketsize" [6 6]  #renderer specific
13 Option "limits" "gridsize" [18]  #renderer specific
14 Format 1024 768 1  #mandatory resolution
15 Projection "perspective"
16 Clipping 10 1000.0
17 FrameBegin 1
18     ##Shaders MyUserShader, PIXARmarble, PIXARwood
19     ##CameraOrientation 10.0 10.0 10.0 0.0 0.0 0.0
20     Transform  [.707107  -.408248  -.57735 0
21                 0  .816497  -.57735  0
22                 -.707107  -.408248  -.57735  0
23                 0  0  17.3205  1 ]
24     WorldBegin
25         AttributeBegin
26             Attribute "identifier" "name" "myball"
27             Displacement "MyUserShader" "squish" 5
28             AttributeBegin
29                 Attribute "identifier" "shadinggroup" ["tophalf"]
30                 Surface "PIXARmarble"
31                 Sphere .5 0 .5 360
32             AttributeEnd
33             AttributeBegin
34             Attribute "identifier" "shadinggroup" ["bothalf"]
35                 Surface "plastic"
36                 Sphere .5 -.5 0. 360
37             AttributeEnd
38         AttributeEnd
39         AttributeBegin
40             Attribute "identifier" "name" ["floor"]
41                 Surface "PIXARwood" "roughness" [.3] "d" [1]
42                 # geometry for floor
43                 Polygon "P" [-100. 0. -100.  -100. 0. 100.  100. 0. 100.  10.0 0. -100.]
44         AttributeEnd
45     WorldEnd
46 FrameEnd
47 FrameBegin 2
48     ##Shaders PIXARwood, PIXARmarble
49     ##CameraOrientation 10.0 20.0 10.0 0.0 0.0 0.0
50     Transform [.707107  -.57735  -.408248  0
51                0   .57735
52                -.815447 0
53                -.707107  -.57735  -.408248  0
54                0  0  24.4949 1 ]
55     WorldBegin
56         AttributeBegin
57             Attribute "identifier" "name" ["myball"]
58             AttributeBegin
59                 Attribute "identifier" "shadinggroup" ["tophalf"]
60                     Surface "PIXARmarble"
61                     ShadingRate .1
62                     Sphere .5 0 .5 360
63                 AttributeEnd
64             AttributeBegin
65             Attribute "identifier" "shadinggroup" ["bothalf"]
66                 Surface "plastic"
67                 Sphere .5 -.5 0 360
68             AttributeEnd
69         AttributeEnd
70         AttributeBegin
71             Attribute "identifier" "name" ["floor"]
72             Surface "PIXARwood" "roughness" [.3] "d" [1]
73             # geometry for floor
74         AttributeEnd
75     WorldEnd
76 FrameEnd

View Code

聪明的你告诉我,你觉得这个场景描述有什么限制?这个问题可能很难回答,但是我们先来提几个看似简单的需求。

  • 流式更新
  • 几何体数据的修改
  • 几何体属性的修改
  • 材质数据的修改
  • 材质和几何体关系的修改
  • 多屏幕计算
  • 多屏幕不同分辨率的计算
  • 多屏幕不同分辨率不同数据的计算

但是告诉我,如果你想修改这个Mesh的几何数据,你会如何做?这个答案在RI内,使用负责场景数据,范例如下。

1 RiEditBegin("attribute", "string editlights", "light1", RI_NULL);
2   // specify the coordinate system for light1
3   RiTransform( ... );
4   RiLightsource( "spotlight", RI_HANDLEID, "light1", "color lightcolor", (RtPointer)&color );
5 RiEditEnd();

View Code

这套系统只支持非常有限的场景元素的修改,也就是你只能改改Shader参数,移动一下位置如此,也就是我们现在看到常见IPR的所有的操作。

当然这一套系统的限制呢,也是写的明明白白。

Restrictions, Constraints, and Known Issues
Each re-rendering mode has certain restrictions and limitations that should be considered before being incorporated in a production pipeline. It is our intent to address these in future releases. Below is the current list of restrictions, constraints, and known issues:

  • Hider restrictions The only hiders supported are stochastic and raytrace. Sigma buffer and stitching are not supported.
  • Camera restrictions Multi-camera rendering is not supported.
  • Graphics primitives CSG is not supported.
  • Display Progressive refinement is critical to making editing interactive. We have provided a new display driver, multires, that can quickly display the multi-resolution images produced by re-rendering. However, existing display drivers can't display multi-resolution images and will cause the re-renderer to disable progressive refinement, rendering only at the highest resolution.
  • Resizable Arrays Traditional shaders with resizeable arrays will not be baked properly, leading to a crash during re-rendering. However, shader object-based shaders do support the use of resizeable arrays.

限制有

  • 仅仅是支持stochastic和raytrace 2种Hider。
  • 不支持多摄影机渲染。
  • 不支持CSG几何体。
  • 需要新的Display Driver支持。
  • 不支持变长的Shader数组参数。

那么显然,这一套系统的缺陷是

  • 先后顺序存在依赖
  • API太多太琐碎每次都得学新的函数
  • 可操作的对象和数据类型受限
  • 不支持复杂操作,比如删除几何体
  • 不支持修改分辨率、摄影机参数等必须参数

来到Nodel Scene API

显然到了如今,再遵循RenderMan标准,显然已经没有意义。如今RenderMan渲染器本身就没有丝毫优势,大家的渲染已经更多,已经不是当年那个缺少靠谱的解决方案的时代了。所以,为了克服RenderMan的所有缺点和限制,3Delight重新引入了NSI这么一套API。下面是所有函数列表,对,你没有看错,所有的函数。

NSIContext_t NSIBegin(int nparams, const struct NSIParam_t *params );void NSIEnd( NSIContext_t ctx );void NSICreate(NSIContext_t ctx, NSIHandle_t handle, const char *type, int nparams, const struct NSIParam_t *params );void NSIDelete(NSIContext_t ctx, NSIHandle_t handle, int nparams, const struct NSIParam_t *params);void NSISetAttribute(NSIContext_t ctx, NSIHandle_t object, int nparams, const struct NSIParam_t *params );void NSISetAttributeAtTime(NSIContext_t ctx, NSIHandle_t object, double time, int nparams, const struct NSIParam_t *params );void NSIDeleteAttribute(NSIContext_t ctx, NSIHandle_t object, const char *name );void NSIConnect(NSIContext_t ctx, NSIHandle_t from, const char *from_attr, NSIHandle_t to, const char *to_attr, int nparams, const struct NSIParam_t *params );void NSIDisconnect(NSIContext_t ctx, NSIHandle_t from, const char *from_attr, NSIHandle_t to, const char *to_attr);void NSIEvaluate(NSIContext_t ctx, int nparams, const struct NSIParam_t *params);void NSIRenderControl(NSIContext_t ctx, int nparams, const struct NSIParam_t *params);

以上就是所有的函数。

其实从函数名字就可以看到背后的设计思路,虽然还是填充场景对象的数据,但是由于这个不存在任何的依赖关系,所以克服了RI的那几个重要的缺点,一切的一切只要在调用NSIRenderControl之前即可。用户可以用这一套API以自己喜欢的顺序组织场景,构造节点和节点之间的连接即可。下面来具体用例子解释如何构造场景。

一个NSI场景

首先从构造一个Plane的片段开始。

 1 #include <nsi.hpp>
 2
 3
 4 // Set mesh data.
 5 //
 6 int plane_shape_nvertices_data[1] =
 7 {
 8     4
 9 };
10
11 int plane_shape_indices_data[4] =
12 {
13     0, 1, 3, 2
14 };
15
16 float plane_shape_P_data[12] = // 3 * 4
17 {
18     -50, 0, 50,
19     50, 0, 50,
20     - 50, 0, - 50,
21     50, 0, - 50
22 };
23
24 int plane_shape_N_data[12] = // 3 * 4
25 {
26     0, 1, 0,
27     0, 1, 0,
28     0, 1, 0,
29     0, 1, 0
30 };
31
32 NSI::ArgumentList plane_shape_attrs;
33
34 plane_shape_attrs.push(NSI::Argument::New("nvertices")
35     ->SetType(NSITypeInteger)
36     ->SetCount(1)
37     ->SetValuePointer(plane_shape_nvertices_data));
38
39 plane_shape_attrs.push(NSI::Argument::New("P")
40     ->SetType(NSITypePoint)
41     ->SetCount(4)
42     ->SetFlags(NSIParamInterpolateLinear)
43     ->SetValuePointer(plane_shape_P_data));
44
45 plane_shape_attrs.push(NSI::Argument::New("P.indices")
46     ->SetType(NSITypeInteger)
47     ->SetCount(4)
48     ->SetValuePointer(plane_shape_indices_data));
49
50 plane_shape_attrs.push(NSI::Argument::New("N")
51     ->SetType(NSITypeNormal)
52     ->SetCount(4)
53     ->SetFlags(NSIParamInterpolateLinear)
54     ->SetValuePointer(plane_shape_N_data));
55
56 plane_shape_attrs.push(NSI::Argument::New("N.indices")
57     ->SetType(NSITypeInteger)
58     ->SetCount(4)
59     ->SetValuePointer(plane_shape_indices_data));
60
61 nsi.SetAttribute(plane_shape_handle, plane_shape_attrs);

对于一个mesh来说,它具备如下几个内置的属性

  • P
  • nvertices
  • nholes
  • clockwisewinding
  • subdivision.scheme
  • subdivision.cornervertices
  • subdivision.cornersharpness
  • subdivision.creasevertices
  • subdivision.creasesharpness

顾名思义,这些属性定义了这个mesh的所有几何数据,每一个属性的数据就是一个数组,如同范例C++代码所展示的一样。

光有mesh当然不行,还需要transform

 1 #include <nsi.hpp>
 2
 3 // Set transform data, which is identity.
 4 //
 5 double plane_xform_matrix_data[16] =
 6 {
 7     1, 0, 0, 0,
 8     0, 1, 0, 0,
 9     0, 0, 1, 0,
10     0, 0, 0, 1
11 };
12
13 NSI::ArgumentList plane_xform_attrs;
14 plane_xform_attrs.push(NSI::Argument::New("transformationmatrix")
15     ->SetType(NSITypeDoubleMatrix)
16     ->SetCount(1)
17     ->SetValuePointer(plane_xform_matrix_data));
18
19 nsi.SetAttributeAtTime(plane_xform_handle, 0.0, plane_xform_attrs);
20
21 // Create plane's mesh and connect it to the last transform.
22 //
23 const std::string plane_shape_handle("planeShape1");
24
25 nsi.Create(plane_shape_handle, "mesh");
26 nsi.Connect(plane_shape_handle, "", plane_xform_handle, "objects");

其实非常简单,这里使用了SetAttributeAtTime,用来定义多个matrix实现运动模糊。末了,直接调用Connect,这样就把先前构造的mesh放入了transform的objects这个属性之下,从此这个mesh可以被transform所变换。当然transform是可以包含transform,构造成了层次化的变换。

下面当然是需要附上材质了,我们就用最简单的lambert。

 1 #include <nsi.hpp>
 2
 3 // Assign lambert shader to the plane.
 4 //
 5 const std::string plane_xform_attrs_handle = plane_xform_handle + "Attrs";
 6
 7 nsi.Create(plane_xform_attrs_handle, "attributes");
 8 nsi.Connect(plane_xform_attrs_handle, "", plane_xform_handle, "geometryattributes");
 9
10 const std::string lambert_shader_handle("lambert1");
11
12 nsi.Create(lambert_shader_handle, "shader");
13
14 char lambert_shader_name[256];
15 sprintf(lambert_shader_name, "%s/maya/osl/lambert", delight_dir);
16
17 nsi.SetAttribute(lambert_shader_handle, (NSI::StringArg("shaderfilename", lambert_shader_name),
18     NSI::FloatArg("i_diffuse", 0.8)));
19
20 nsi.Connect(lambert_shader_handle, "", plane_xform_attrs_handle, "surfaceshader");

这里需要先构造attributes,然后把这个attributes和之前创造的transform节点的geometryattributes连接,这样所有attributes都会被所有transform的objects所继承,从此那个mesh就会附上了这个lambert材质。当然此shader实例可以用同样的方式共享给其他的几何体。

还有更多的代码可以从nsi-example这个开源项目看到完整的源代码。

感兴趣的用户可以直接到3Delight Download下载试用版体验最新3Delight,体验其卓越的性能和所有功能特色。

3Delight NSI: A Streamable Render API相关推荐

  1. 代码审计之CVE-2018-7600-Drupal远程代码执行漏洞-Render API

    今天学习一下Drupal的另一个漏洞,由于渲染数组不当造成的漏洞 poc: url:http://localhost/drupal-8.5.0/user/register?element_parent ...

  2. graphite http api

    Render API Graphite web 提供了/render API用来生成图片和获取原始数据.这个API通过查询字符串支持各种参数.参数之间通过&进行分割,如下所示: &na ...

  3. vue-babylonjs入门api

    1.安装 npm i @babylonjs/core@preview npm install babylonjs-gui npm install @babylonjs/inspector Vue3+B ...

  4. React 回忆录(三)使用 React 渲染界面

    Hi 各位,欢迎来到 React 回忆录!? 在上一章中,我介绍了 React 框架的"五大特点":虚拟DOM,组件化,声明式代码,单向数据流和纯粹的 JavaScript 语法. ...

  5. drupal cve-2018-7600 远程代码执行漏洞 简介

    漏洞分析 Drupal 在 3 月 28 日爆出一个远程代码执行漏洞,CVE 编号 CVE-2018-7600,通过对比官方的补丁,可以得知是请求中存在 # 开头的参数.Drupal Render A ...

  6. electron 两个窗口如何通信_关于 Electron 进程间通信的一个小小实践

    Electron 是一个跨平台桌面框架,它集成了 node.js 和 chromium,所以我们可以借助 node.js 实现桌面客户端访问操作系统资源的功能(出于安全,浏览器是不可以访问操作系统的) ...

  7. Windows遗产之RPC/DCOM:还在用吗,内部又有什么区别?

    2019独角兽企业重金招聘Python工程师标准>>> 从原理和使用程度上看,微软没有必要,也的确没有要废弃RPC/DCOM的迹象,但是显然这些技术会长期退入幕后当作基础设施了. 他 ...

  8. React 18 带给我们的惊喜

    大家好,我是若川.持续组织了8个月源码共读活动,感兴趣的可以点此加我微信 ruochuan12 参与,每周大家一起学习200行左右的源码,共同进步.同时极力推荐订阅我写的<学习源码整体架构系列& ...

  9. angular面试题及答案_关于最流行的Angular问题的StackOverflow上的48个答案

    angular面试题及答案 by Shlomi Levi 通过Shlomi Levi 关于最流行的Angular问题的StackOverflow上的48个答案 (48 answers on Stack ...

最新文章

  1. MySQL常用存储引擎之Memory
  2. 应用程序自动更新组件GeneralUpdate3.2.1发布
  3. future.cancel不能关闭线程_彻底弄懂线程池-newFixedThreadPool实现线程池
  4. python中网页关闭再打开_Python Selenium 之关闭窗口close与quit的方法
  5. cube云原生机器学习平台-架构(五)
  6. 银河麒麟系统如何取得终端的root权限和查看所有服务状态
  7. 软件创始人必须要知道的事情
  8. Html中的表格、Table和div,表格页面、员工登记表、Div代码
  9. 目标检测论文综述(一)深度卷积神经网络
  10. c 语言翻译软件,分享一款 程序员秒懂的翻译软件
  11. VMware Tanzu Application Service——Config Client (TAS)
  12. LAV Filter 源代码分析 4: LAV Video (2)
  13. Linux学习笔记26——什么是 Shell scripts、shell script练习及讲解
  14. 香橙派基于翔云的人脸识别
  15. Oracle 层次查询、递归
  16. 通用数据保护条例GDPR今日起正式生效,不会影响机器学习
  17. 解决浏览器连不上校园网问题
  18. PHP简介以及环境的安装
  19. Python pandas 里面的数据类型坑,astype要慎用
  20. EMQX 入门教程——导读

热门文章

  1. Undefined control sequence. 问题
  2. IEDA快速书写代码快捷键
  3. [BUUCTF-pwn]——ciscn_2019_es_2(内涵peak小知识)
  4. 广西2021高考成绩什么时候可以查询,2021年广西高考成绩什么时候公布出来,几月几号几点钟可以查询...
  5. arcgis python脚本实现从界面选择输入输出_ArcGIS Python脚本使用
  6. 当期收益率(Current Yield)
  7. 固定收益证券(fixed income)
  8. oracle 数组类型
  9. the server did not provide any additional information
  10. 10树莓派Samba的安装与配置