计算机生成的纹理墙面涂料


48

我房间墙壁上的油漆具有随机的,几乎像分形的3维纹理:

图片A

在这个挑战中,您将编写一个程序,该程序生成看起来像是我墙壁的一部分的随机图像。

下面,我收集了墙壁上10个不同点的图像。全部具有大致相同的照明,并且全部是在相机距离墙壁一英尺的地方拍摄的。均匀地裁剪边界以使其为2048 x 2048像素,然后将它们缩放为512 x512。上面的图像是图像A。

这些只是缩略图,单击图像可查看完整尺寸!

A: B:C:D:E:图片A 图片B 图片C 图片D 图片E

F: G:H:I:J:图片F 图片G 图片H 图片I 图片J

您的任务是编写一个程序,该程序以1到2 16的正整数作为随机种子,并且为每个值生成一个独特的图像,看起来像是我墙的“第十一张图像”。如果有人看着我的10张图片,而您的几张却不知道是计算机生成的,那您做得很好!

请展示一些您生成的图像,以便观众无需运行代码即可查看它们。

我意识到图像中的光照强度或颜色并不完全均匀。对此我感到抱歉,但是如果没有更好的照明设备,这是我能做的最好的事情。您的图像不需要具有可变的光照(尽管可以)。纹理是更重要的重点。

细节

  • 您可以使用图像处理工具和库。
  • 以所需的任何常用方式(命令行,stdin,明显变量等)进行输入。
  • 输出图像可以是任何常见的无损图像文件格式,也可以仅在窗口/浏览器中显示。
  • 您可以以编程方式分析我的10张图像,但不要假定运行您的代码的每个人都可以访问它们。
  • 您必须以编程方式生成图像。您可能没有对我的一张图片或其他一些图片的略微变体进行硬编码。(无论如何,人们会为此拒绝您。)
  • 您可以使用内置的伪随机数生成器,并假定周期为2 16或更大。

计分

这是一次人气竞赛,因此赢得最高投票的答案会赢得胜利。


PerlinNoise +截断+底纹
章鱼,

21
我无法制作墙像,所以要漫画
Sp3000

8
@ Sp3000差不多是怎么回事。虽然如果我一直在抬头,我可能会选择我的天花板,它也可以工作……
卡尔文的爱好2015年

Answers:


65

GLSL(+ JavaScript + WebGL)

在此处输入图片说明

现场演示 | GitHub资料库

如何使用

重新加载页面以获取新的随机图像。如果要添加特定的种子,请打开浏览器的控制台并调用drawScreen(seed)。控制台应显示加载时使用的种子。

我尚未在很多平台上进行过实际测试,所以请告诉我它是否对您不起作用。当然,您的浏览器需要支持WebGL。错误会显示在左侧的列中,或显示在浏览器的控制台中(取决于错误的类型)。

新增:现在,您可以通过勾选“移动光源”复选框来使墙壁变得生动起来。

这是什么法术?

我已经在GitHub帐户中浮动了这个WebGL样板代码,我不时使用它,然后在WebGL中快速制作一些2D图形对象的原型。借助一些着色器魔术,我们还可以使其看起来略带3D效果,因此我认为这是获得良好效果的最快方法。大多数设置都来自该样板代码,我正在考虑该提交的库,并且不会在本文中包括。如果您有兴趣,请查看GitHub 上的main.js(以及该文件夹中的其他文件)。

JavaScript所做的全部工作就是建立一个WebGL上下文,将种子存储在统一的着色器中,然后在整个上下文中渲染一个四边形。顶点着色器是一个简单的直通着色器,因此所有魔术都发生在片段着色器中。因此,我将其称为GLSL提交。

该代码的最大一部分实际上是生成Simplex噪声,我在GitHub上发现了该噪声。因此,我在下面的代码清单中也忽略了这一点。重要的部分是,它定义了一个函数snoise(vec2 coords),该函数无需使用纹理或数组查找即可返回单纯噪声。它根本没有种子,因此获得不同噪声的技巧是使用种子来确定在哪里进行查找。

因此,这里去:

#ifdef GL_ES
precision mediump float;
#endif
#extension GL_OES_standard_derivatives : enable

uniform float uSeed;
uniform vec2 uLightPos;

varying vec4 vColor;
varying vec4 vPos;

/* ... functions to define snoise(vec2 v) ... */

float tanh(float x)
{
    return (exp(x)-exp(-x))/(exp(x)+exp(-x));
}

void main() {
    float seed = uSeed * 1.61803398875;
    // Light position based on seed passed in from JavaScript.
    vec3 light = vec3(uLightPos, 2.5);
    float x = vPos.x;
    float y = vPos.y;

    // Add a handful of octaves of simplex noise
    float noise = 0.0;
    for ( int i=4; i>0; i-- )
    {
        float oct = pow(2.0,float(i));
        noise += snoise(vec2(mod(seed,13.0)+x*oct,mod(seed*seed,11.0)+y*oct))/oct*4.0;
    }
    // Level off the noise with tanh
    noise = tanh(noise*noise)*2.0;
    // Add two smaller octaves to the top for extra graininess
    noise += sqrt(abs(noise))*snoise(vec2(mod(seed,13.0)+x*32.0,mod(seed*seed,11.0)+y*32.0))/32.0*3.0;
    noise += sqrt(abs(noise))*snoise(vec2(mod(seed,13.0)+x*64.0,mod(seed*seed,11.0)+y*64.0))/64.0*3.0;

    // And now, the lighting
    float dhdx = dFdx(noise);
    float dhdy = dFdy(noise);
    vec3 N = normalize(vec3(-dhdx, -dhdy, 1.0)); // surface normal
    vec3 L = normalize(light - vec3(vPos.x, vPos.y, 0.0)); // direction towards light source
    vec3 V = vec3(0.0, 0.0, 1.0); // direction towards viewpoint (straight up)
    float Rs = dot(2.0*N*dot(N,L) - L, V); // reflection coefficient of specular light, this is actually the dot product of V and and the direction of reflected light
    float k = 1.0; // specular exponent

    vec4 specularColor = vec4(0.4*pow(Rs,k));
    vec4 diffuseColor = vec4(0.508/4.0, 0.457/4.0, 0.417/4.0, 1.0)*dot(N,L);
    vec4 ambientColor = vec4(0.414/3.0, 0.379/3.0, 0.344/3.0, 1.0);

    gl_FragColor = specularColor + diffuseColor + ambientColor;
    gl_FragColor.a = 1.0;
}

而已。明天我可能会添加更多解释,但是基本思想是:

  • 选择一个随机的灯光位置。
  • 加上几个八度的噪声,以生成分形图案。
  • 调整噪音以保持底部粗糙。
  • 传导噪音tanh以使顶部平整。
  • 在顶层增加两个八度,以获得更多的纹理。
  • 计算所得曲面的法线。
  • 在具有曲面和漫反射光的表面上运行简单的Phong着色。颜色是根据我从第一个示例图像中选取的一些随机颜色选择的。

17
这比隔离墙本身更现实:o
Quentin

1
更多“静脉” /“蛇形” /“蠕虫”将使此图片更适合“墙”。但是还是不错的。
新星

33

Mathematica打包

下面的应用将斑点图像应用于随机图像。单击“新补丁”会生成一个新的随机图像以供使用,然后根据当前设置应用效果。效果包括油画,高斯滤镜,后代化和浮雕。每个效果都可以独立调整。随机数生成器的种子可以是1到2 ^ 16之间的任何整数。

更新:高斯滤镜可柔化边缘,现在是应用的最后一个图像效果。通过此修改,不再需要后代效果,因此可以将其删除。

Manipulate[
 GaussianFilter[ImageEffect[ImageEffect[r, {"OilPainting", o}], {"Embossing", e, 1.8}], g],
 Button["new patch", (SeedRandom[seed] r = RandomImage[1, {400, 400}])], 
 {{o, 15, "oil painting"}, 1, 20, 1, ContinuousAction -> False, Appearance -> "Labeled"}, 
 {{e, 1.64, "embossing"}, 0, 5, ContinuousAction -> False, Appearance -> "Labeled"},
 {{g, 5, "Gaussian filter"}, 1, 12, 1, ContinuousAction -> False, Appearance -> "Labeled"},
 {{seed, 1}, 1, 2^16, 1, ContinuousAction -> False, Appearance -> "Labeled"}, 
 Initialization :> (SeedRandom[seed]; r = RandomImage[1, {400, 400}])]

最终结果


说明

解释基于稍有不同的版本,在该版本中采用了后代化,并GaussianFilter在早期应用。但这仍然有助于阐明每种图像效果如何改变图像。最终结果是具有更锐利边缘的油漆纹理。当仅在最后应用高斯滤波器时,结果将更加平滑,如上图所示。

让我们来看一些图像效果,一次。

生成起始图像。

 r = RandomImage[1, {200, 200}]

随机图像


莉娜(Lena)将向我们展示每种图像效果如何转变出逼真的图像。

Lena = ExampleData[{"TestImage", "Lena"}]

莉娜


将油画效果应用于Lena。

ImageEffect[Lena, {"OilPainting", 8}]

莲娜油

油画效果应用于我们的随机图像。效果增强(从16代替8)。

 r1 = ImageEffect[r, {"OilPainting", 16}]

油


将高斯滤镜效果应用于Lena(不适用于Lena的油画效果版本)。半径为10像素。(在最终版本中,在此条目的顶部,将应用GaussianFilter作为最终效果。)

 GaussianFilter[Lena, 10]

莱娜高斯。


对r1施加了稍微温和的高斯滤波效果。半径为5个像素。

 r2 = GaussianFilter[r1, 5]

高斯


强烈的后代化效果应用于Lena。(在应用程序的最终版本中,我删除了后继化。但是我们将其保留在分析中,因为分析中的示例基于具有后继化的早期版本。)

 ImageEffect[Lena, {"Posterization", 2}]

莱娜海报


后代化效果应用于r2。

r3 = ImageEffect[r2, {"Posterization", 4}]

后置


压花莉娜

 ImageEffect[Lena, {"Embossing", 1.2, 1.8}]

莱娜压花


压印r3完成图像处理。这旨在看起来像OP的天花板。

 ceilingSample = ImageEffect[r3, {"Embossing", 1.2, 1.8}]

浮雕


出于好奇,这里是应用了相同图像效果的莉娜。

lena4


...有内置获取Lena图像的工具吗?大声笑。
user253751

7
是。Mathematica中大约有30张内置图片用于图像处理测试。
DavidC 2015年

稍加修改,就可以喂养RandomInteger种子,从而保证了特定的产量。还是说其他意思,例如应用了效果的初始非随机图像?
DavidC 2015年

1
现在它接受1到2 ^ 16的种子。
DavidC

1
+1是因为Lena will show us how each image effect transforms a life-like picture让我大声笑。奇怪的是,Lena的最终图像看起来像是向左左的阿兹台克人或印加人,戴着头饰并把树枝编成了枪支。
等级河圣

13

POV射线

具有很多高尔夫潜力 povray /RENDER wall.pov -h512 -w512 -K234543 在此处输入图片说明

首先,它会创建一个随机纹理,但不是将其停在那里,而是将纹理转换为3D高场,以使相机闪光灯产生的径向阴影更加逼真。并且在良好的效果下,它还在顶部添加了另一个小凸起的纹理。
除了对随机种子进行硬编码之外,唯一的方法是使用clock用于动画的变量,该变量与-K{number}标志一起传递

#default{ finish{ ambient 0.1 diffuse 0.9 }} 

camera {location y look_at 0 right x}
light_source {5*y color 1}

#declare R1 = seed (clock); // <= change this

#declare HF_Function  =
 function{
   pigment{
     crackle turbulence 0.6
     color_map{
       [0.00, color 0.01]
       [0.10, color 0.05]
       [0.30, color 0.20]
       [0.50, color 0.31]
       [0.70, color 0.28]
       [1.00, color 0.26]
     }// end color_map
    scale <0.25,0.005,0.25>*0.7 
    translate <500*rand(R1),0,500*rand(R1)>
   } // end pigment
 } // end function

height_field{
  function  512, 512
  { HF_Function(x,0,y).gray * .04 }
  smooth 
  texture { pigment{ color rgb<0.6,0.55,0.5>}
            normal { bumps 0.1 scale 0.005}
            finish { phong .1 phong_size 400}
          } // end of texture  
  translate< -0.5,0.0,-0.5>
}

根本不需要打高尔夫球。结果不错!:)
马丁·恩德
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.