3Delight NSI: A Streamable Render API
3Delight是应用于高端电影级别渲染的软件渲染器,迄今为止已经参与了无数的电影制作,具体可以参见链接。
如果你对3Delight的印象就依然是RenderMan的替代品,那就显然已经和时代发展脱节了。现在的3Delight是一个完全PBR Unbiased的渲染器,而且完全为了交互式渲染以及云端渲染设计,所以你对它的固有印象可以从看到这篇文章开始彻底改变了。
渲染=数据操作
其实“渲染”这个动作的本身,就是数据处理,你可以用任何流行的思路来对照,比如MapReduce。但是归根结底,可以认为只有3个概念。
- 数据填充
- 数据修改
- 数据计算
这3个概念可以直接展开,把你所知道所有的计算机图形学相关的概念和技术都丢入,但是这里不展开。
本文会结合这3个概念,来仔细的阐述3Delight NSI的优点和思路,以及解决的问题。
一切从过程开始
计算机,其实是过程性设备。所谓面向对象,只是软件设计领域的一个对过程和数据的合并抽象而已,本质上,最后的“执行”这个本身依然是个过程。
那么回顾一下RenderMan API(以下简称RI)的设计。
RenderMan
一个完整RI可渲染的场景一般结构如下,来自这里。
##RenderMan RIB-Structure 1.1
##Scene Bouncing Ball
##Creator /usr/ucb/vi
##CreationDate :30pm //
##For RenderMan Jones
##Frames
##Shaders PIXARmarble, PIXARwood, MyUserShader
##CapabilitiesNeeded ShadingLanguage Displacements
version 3.03
Declare "d" "uniform point"
Declare "squish" "uniform float"
Option "limits" "bucketsize" [ ] #renderer specific
Option "limits" "gridsize" [] #renderer specific
Format #mandatory resolution
Projection "perspective"
Clipping 1000.0
FrameBegin
##Shaders MyUserShader, PIXARmarble, PIXARwood
##CameraOrientation 10.0 10.0 10.0 0.0 0.0 0.0
Transform [. -. -.
. -.
-. -. -.
17.3205 ]
WorldBegin
AttributeBegin
Attribute "identifier" "name" "myball"
Displacement "MyUserShader" "squish"
AttributeBegin
Attribute "identifier" "shadinggroup" ["tophalf"]
Surface "PIXARmarble"
Sphere . .
AttributeEnd
AttributeBegin
Attribute "identifier" "shadinggroup" ["bothalf"]
Surface "plastic"
Sphere . -. .
AttributeEnd
AttributeEnd
AttributeBegin
Attribute "identifier" "name" ["floor"]
Surface "PIXARwood" "roughness" [.] "d" []
# geometry for floor
Polygon "P" [-. . -. -. . . . . . 10.0 . -.]
AttributeEnd
WorldEnd
FrameEnd
FrameBegin
##Shaders PIXARwood, PIXARmarble
##CameraOrientation 10.0 20.0 10.0 0.0 0.0 0.0
Transform [. -. -.
.
-.
-. -. -.
24.4949 ]
WorldBegin
AttributeBegin
Attribute "identifier" "name" ["myball"]
AttributeBegin
Attribute "identifier" "shadinggroup" ["tophalf"]
Surface "PIXARmarble"
ShadingRate .
Sphere . .
AttributeEnd
AttributeBegin
Attribute "identifier" "shadinggroup" ["bothalf"]
Surface "plastic"
Sphere . -.
AttributeEnd
AttributeEnd
AttributeBegin
Attribute "identifier" "name" ["floor"]
Surface "PIXARwood" "roughness" [.] "d" []
# geometry for floor
AttributeEnd
WorldEnd
FrameEnd
聪明的你告诉我,你觉得这个场景描述有什么限制?这个问题可能很难回答,但是我们先来提几个看似简单的需求。
- 流式更新
- 几何体数据的修改
- 几何体属性的修改
- 材质数据的修改
- 材质和几何体关系的修改
- 多屏幕计算
- 多屏幕不同分辨率的计算
- 多屏幕不同分辨率不同数据的计算
但是告诉我,如果你想修改这个Mesh的几何数据,你会如何做?这个答案在RI内,使用负责场景数据,范例如下。
RiEditBegin("attribute", "string editlights", "light1", RI_NULL);
// specify the coordinate system for light1
RiTransform( ... );
RiLightsource( "spotlight", RI_HANDLEID, "light1", "color lightcolor", (RtPointer)&color );
RiEditEnd();
这套系统只支持非常有限的场景元素的修改,也就是你只能改改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的片段开始。
#include <nsi.hpp> // Set mesh data.
//
int plane_shape_nvertices_data[] =
{ }; int plane_shape_indices_data[] =
{
, , ,
}; float plane_shape_P_data[] = // 3 * 4
{
-, , ,
, , ,
- , , - ,
, , -
}; int plane_shape_N_data[] = // 3 * 4
{
, , ,
, , ,
, , ,
, ,
}; NSI::ArgumentList plane_shape_attrs; plane_shape_attrs.push(NSI::Argument::New("nvertices")
->SetType(NSITypeInteger)
->SetCount()
->SetValuePointer(plane_shape_nvertices_data)); plane_shape_attrs.push(NSI::Argument::New("P")
->SetType(NSITypePoint)
->SetCount()
->SetFlags(NSIParamInterpolateLinear)
->SetValuePointer(plane_shape_P_data)); plane_shape_attrs.push(NSI::Argument::New("P.indices")
->SetType(NSITypeInteger)
->SetCount()
->SetValuePointer(plane_shape_indices_data)); plane_shape_attrs.push(NSI::Argument::New("N")
->SetType(NSITypeNormal)
->SetCount()
->SetFlags(NSIParamInterpolateLinear)
->SetValuePointer(plane_shape_N_data)); plane_shape_attrs.push(NSI::Argument::New("N.indices")
->SetType(NSITypeInteger)
->SetCount()
->SetValuePointer(plane_shape_indices_data)); 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
#include <nsi.hpp> // Set transform data, which is identity.
//
double plane_xform_matrix_data[] =
{
, , , ,
, , , ,
, , , ,
, , ,
}; NSI::ArgumentList plane_xform_attrs;
plane_xform_attrs.push(NSI::Argument::New("transformationmatrix")
->SetType(NSITypeDoubleMatrix)
->SetCount()
->SetValuePointer(plane_xform_matrix_data)); nsi.SetAttributeAtTime(plane_xform_handle, 0.0, plane_xform_attrs); // Create plane's mesh and connect it to the last transform.
//
const std::string plane_shape_handle("planeShape1"); nsi.Create(plane_shape_handle, "mesh");
nsi.Connect(plane_shape_handle, "", plane_xform_handle, "objects");
其实非常简单,这里使用了SetAttributeAtTime,用来定义多个matrix实现运动模糊。末了,直接调用Connect,这样就把先前构造的mesh放入了transform的objects这个属性之下,从此这个mesh可以被transform所变换。当然transform是可以包含transform,构造成了层次化的变换。
下面当然是需要附上材质了,我们就用最简单的lambert。
#include <nsi.hpp> // Assign lambert shader to the plane.
//
const std::string plane_xform_attrs_handle = plane_xform_handle + "Attrs"; nsi.Create(plane_xform_attrs_handle, "attributes");
nsi.Connect(plane_xform_attrs_handle, "", plane_xform_handle, "geometryattributes"); const std::string lambert_shader_handle("lambert1"); nsi.Create(lambert_shader_handle, "shader"); char lambert_shader_name[];
sprintf(lambert_shader_name, "%s/maya/osl/lambert", delight_dir); nsi.SetAttribute(lambert_shader_handle, (NSI::StringArg("shaderfilename", lambert_shader_name),
NSI::FloatArg("i_diffuse", 0.8))); 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的更多相关文章
- CVE-2018-7600-Drupal远程代码执行漏洞-Render API
今天学习一下Drupal的另一个漏洞,由于渲染数组不当造成的漏洞 poc: url:http://localhost/drupal-8.5.0/user/register?element_parent ...
- 代码审计之CVE-2018-7600-Drupal远程代码执行漏洞-Render API
今天学习一下Drupal的另一个漏洞,由于渲染数组不当造成的漏洞 poc: url:http://localhost/drupal-8.5.0/user/register?element_parent ...
- 何时/如何使用 Vue3 render 函数
什么是 DOM? 如果我们把这个 HTML 加载到浏览器中,浏览器创建这些节点,用来显示网页.所以这个HTML映射到一系列DOM节点,然后我们可以使用JavaScript进行操作.例如: let it ...
- Beginning SDL 2.0(1) SDL功能简介
原文链接为 http://wiki.libsdl.org/Introduction. 由于近期整理音视频可视化的技术,发现好久不更新的SDL发布了2.0版本,以前也没有过于关注,这里准备尝试下.了解S ...
- (转)SDL 1.2 to 2.0 Migration Guide--SDL1.2更新到SDL2.0指南
SDL 1.2 to 2.0 Migration Guide 目录 SDL 1.2 to 2.0 Migration Guide Translations Introduction Overview ...
- tornado大全(甩锅版)
tornado简介 tornado是Python界中非常出名的一款Web框架,和Flask一样它也属于轻量级的Web框架. 但是从性能而言tornado由于其支持异步非阻塞的特性所以对于一些高并发的场 ...
- vue3 到底哪里好?看这一篇就够了
之前写的关于 vue3 的文章,好多人吐槽:这些API每次使用都要引入一遍,感觉有点麻烦. 今天我们就来看看 vue3 相比 vue2 的优点有些啥? 为啥有些人说:自从写了 ts vue3 再也回不 ...
- 【React】学习笔记(一)——React入门、面向组件编程、函数柯里化
课程原视频:https://www.bilibili.com/video/BV1wy4y1D7JT?p=2&spm_id_from=pageDriver 目录 一.React 概述 1.1.R ...
- iView组件添加API中介绍的事件的方式(render方式添加事件)
iView组件好用,文档齐全,品质可靠稳定.最大的好处是使用了Vue框架,使很多数据绑定和交互问题变的轻松,是难得的开源前端组件.给作者点个赞.用这个组件来学习Vue.js也是不错的选择. 最近用的比 ...
随机推荐
- 一、Java 23 种设计模式简介
一.23种设计模式分类: 二.设计模式的六大原则: 1.开闭原则(Open Close Principle):对扩展开放,对修改关闭.在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效 ...
- android 系统dialog的应用
应用示例如下: /* * 提示类型dialog */ private void dialog1(){ AlertDialog.Builder builder = new AlertDialog.Bui ...
- 关于uni-app框架的学习-1
根据官方文档进行学习Uni-APP, 再次过程中,记录一些需要熟悉的内容,有不合适的地方,见着都可知道,----我是一个小白,小白,小白 官网地址:https://uniapp.dcloud.io/ ...
- docker 发布到私有docker registry
1.使用vs发布项目到文件夹: 2.在文件夹中新建dockerfile文件, 内容: FROM mcr.microsoft.com/dotnet/core/aspnet:2.2-stretch-sli ...
- ReactiveSwift源码解析(五) SignalProtocol的observe()、Map、Filter延展实现
上篇博客我们对Signal的基本实现以及Signal的面向协议扩展进行了介绍, 详细内容请移步于<Signal中的静态属性静态方法以及面向协议扩展>.并且聊了Signal的所有的g功能扩展 ...
- 重新发现MATLAB
现场编辑 创建不仅捕获代码的脚本 - 它们讲述了可以与他人共享的故事.自动化的上下文提示可让您在编程时快速移动,并将结果和可视化与代码一起显示. 学到更多 访问MATLAB实时脚本库 ...
- 从壹开始前后端分离[.netCore 不定期 ] 36 ║解决JWT自定义中间件授权过期问题
缘起 哈喽,老张的不定期更新的日常又开始了,在咱们的前后端分离的.net core 框架中,虽然已经实现了权限验证<框架之五 || Swagger的使用 3.3 JWT权限验证[修改]>, ...
- 从壹开始前后端分离 [ Vue2.0+.NET Core2.1] 十九║Vue基础: 样式动态绑定+生命周期
回顾 哈喽大家好,前后端分离系列文章又开始了,今天周一,还是感谢大家花时间来观看我写的博客,周末呢,没有写文章,但是也没有闲着,主要是研究了下遗留问题,看过之前文章的应该知道,之前的在AOP使用Red ...
- MacBook IDEA激活码(附视频)
Windows激活请看这里:IDEA激活码 此教程实时更新,请放心使用:如果有新版本出现猪哥都会第一时间尝试激活: idea官网下载地址:https://www.jetbrains.com/idea/ ...
- 【TensorFlow篇】--Tensorflow框架初始,实现机器学习中多元线性回归
一.前述 TensorFlow是谷歌基于DistBelief进行研发的第二代人工智能学习系统,其命名来源于本身的运行原理.Tensor(张量)意味着N维数组,Flow(流)意味着基于数据流图的计算,T ...