我正在尝试(在C#中)实现“纹理和建模-K. Perlin等人”(如果有的话,请参阅第91页)中介绍的图像扰动算法,该算法会使图像失真。
以下代码是用Renderman语言:
纹理访问

Ct = texture("example.tx", s, t);

替换为

point Psh;
float ss, tt;
Psh = transform("shader", P);
ss = s + 0.2 * snoise(Psh);
tt = t + 0.2 * snoise(Psh+(l.5,6.7,3.4));
Ct = texture("example.tx", ss, tt);


转换从左到右的图像。


根据我不了解的内容,代替访问坐标$(s,t)\ in [0,1] $,我们访问了一点微扰协调$(ss,tt)$并将其显示在$(s,t)$处,从而创建看起来有些微扰的图像。

$ snoise(x)$被定义为$(noise (x)* 2)-1 $,将噪声从$ [0,1] $映射到$ [-1,1] $,并在RenderMan文档$ noise(P)$中,其中P是一个点,返回一个值基于某些噪音(很可能是Perlin或晶格)。
(http://renderman.pixar.com/resources/current/RenderMan/noiseFunctions.html)

我不做什么明白是什么transf orm函数可以,它应该将3d点P映射到“着色器”空间中,以及如何实现。
此外,我不确定noise(x)是否返回3d点(浮点数) (会更有意义),如果我可以使用Perlin噪声的简单2d实现来达到相同的期望效果。

#1 楼

如您所料,transform()函数将点从一个坐标空间转换为另一个坐标空间。 (分别还有vtransform()ntransform()分别用于转换方向向量和法向向量。)字符串参数命名要转换为的坐标空间。

有关此内容的说明如下:


在开始执行着色器时,所有点,向量,法线和矩阵变量都在“当前”坐标系中表示。哪个坐标系是“当前”的确切位置取决于实现。恰好是PRMan *的“当前”是“相机”,但您永远不要指望这种行为-完全有可能其他兼容RenderMan的渲染器(包括来自Pixar的未来渲染器)可能会使用其他空间(例如“世界”)作为“当前”空间。


接着给出一个这样的例子作为例子。大多数照明计算应在相机空间中进行,但评估噪波功能应在对象的坐标系中,因为您希望噪波在对象在世界空间中移动时保持不变。

在C#实现中,还需要将要着色的点从摄影机空间转换为对象的坐标系。也许在计算纹理坐标之前已经完成了此操作。如果不是,则需要乘以对象的转换矩阵。请记住,此变换点的唯一用途是作为Perlin噪声生成器的输入(例如种子)。它设置了噪声变化的范围:世界空间坐标。

在RSL中,noise()函数可以返回任何您喜欢的类型:floatcolorpointvector。将其添加到另一个floatuv)时,您将在此代码中得到一个float。实际上,添加到noise()s的两个t调用用于生成单个2D噪声矢量。在您自己的代码中,如果使用2D向量存储纹理坐标,则可以使用返回2D向量的单个噪波函数在一行代码中获得相同的效果。


如果您对制作一个出色的噪声发生器感兴趣,Shadertoy拥有许多噪声着色器,它们具有Perlin噪声的不同变体,具有不同的属性(各向同性或非同质性,可配置的平滑度和带宽),值得一看灵感以及实施提示。