Máy tính tạo ra kết cấu sơn tường


48

Sơn trên tường trong phòng tôi có kết cấu 3 chiều ngẫu nhiên, gần như fractal:

Hình A

Trong thử thách này, bạn sẽ viết một chương trình tạo ra các hình ảnh ngẫu nhiên trông giống như chúng có thể là một phần của bức tường của tôi.

Dưới đây tôi đã thu thập được 10 hình ảnh của các điểm khác nhau trên tường của tôi. Tất cả đều có ánh sáng gần giống nhau và tất cả đều được chụp bằng camera cách tường một bước chân. Các đường viền được cắt đều để làm cho chúng 2048 x 2048 pixel, sau đó chúng được thu nhỏ thành 512 x 512. Hình ảnh trên là hình A.

Đây chỉ là hình thu nhỏ, nhấp vào hình ảnh để xem ở kích thước đầy đủ!

A: B: C: D: E:Hình A Hình ảnh B Hình C Hình D Hình ảnh E

F: G: H: Tôi: J:Hình ảnh F Hình ảnh G Hình H Hình tôi Hình ảnh J

Nhiệm vụ của bạn là viết một chương trình lấy số nguyên dương từ 1 đến 2 16 làm hạt giống ngẫu nhiên và với mỗi giá trị sẽ tạo ra một hình ảnh riêng biệt trông giống như nó có thể là "hình ảnh thứ mười một" của bức tường của tôi. Nếu ai đó nhìn vào 10 hình ảnh của tôi và một vài trong số bạn không thể biết được máy tính nào được tạo thì bạn đã làm rất tốt!

Vui lòng khoe một vài hình ảnh được tạo của bạn để người xem có thể nhìn thấy chúng mà không phải chạy mã.

Tôi nhận ra rằng ánh sáng trong ảnh của tôi không hoàn toàn đồng nhất về cường độ hoặc màu sắc. Tôi xin lỗi vì điều này nhưng đó là điều tốt nhất tôi có thể làm mà không cần thiết bị chiếu sáng tốt hơn. Hình ảnh của bạn không cần phải có ánh sáng thay đổi (mặc dù chúng có thể). Các kết cấu là điều quan trọng hơn để tập trung vào.

Chi tiết

  • Bạn có thể sử dụng các công cụ xử lý hình ảnh và thư viện.
  • Lấy đầu vào theo bất kỳ cách phổ biến nào bạn muốn (dòng lệnh, stdin, biến rõ ràng, v.v.).
  • Hình ảnh đầu ra có thể ở bất kỳ định dạng tệp hình ảnh lossless phổ biến nào, hoặc nó chỉ có thể được hiển thị trong một cửa sổ / cung tên.
  • Bạn có thể lập trình phân tích 10 hình ảnh của tôi nhưng đừng cho rằng mọi người đang chạy mã của bạn đều có quyền truy cập vào chúng.
  • Bạn phải tạo ra các hình ảnh lập trình. Bạn không thể mã hóa một biến thể nhỏ của một trong những hình ảnh của tôi hoặc một số hình ảnh chứng khoán khác. (Mọi người sẽ bỏ phiếu cho bạn vì điều này.)
  • Bạn có thể sử dụng trình tạo số giả ngẫu nhiên tích hợp và giả sử khoảng thời gian là 2 16 trở lên.

Chấm điểm

Đây là một cuộc thi phổ biến để câu trả lời được bình chọn cao nhất sẽ chiến thắng.


PerlinNiri + cắt ngắn + tạo bóng
Bạch tuộc

21
Tôi không thể tạo hình ảnh trên tường, vì vậy thay vào đó có một truyện tranh !
Sp3000

8
@ Sp3000 Điều đó ít nhiều đã xảy ra như thế nào. Mặc dù nếu tôi đang tìm kiếm, có lẽ tôi đã chọn trần nhà của mình , nó cũng có thể hoạt động tốt ...
Sở thích của Calvin vào

Câu trả lời:


65

GLSL (+ JavaScript + WebGL)

nhập mô tả hình ảnh ở đây

Bản demo trực tiếp | Kho GitHub

Cách sử dụng

Tải lại trang cho một hình ảnh ngẫu nhiên mới. Nếu bạn muốn cung cấp một hạt giống cụ thể, hãy mở bảng điều khiển của trình duyệt và gọi drawScreen(seed). Bảng điều khiển sẽ hiển thị các hạt giống được sử dụng trên tải.

Tôi chưa thực sự thử nghiệm điều này trên nhiều nền tảng, vì vậy hãy cho tôi biết nếu nó không hoạt động với bạn. Tất nhiên, trình duyệt của bạn cần hỗ trợ WebGL. Lỗi được hiển thị ở cột bên trái hoặc trong bảng điều khiển của trình duyệt (tùy thuộc vào loại lỗi).

Mới: Bây giờ bạn có thể làm cho các bức tường trở nên sống động hơn một chút, bằng cách đánh dấu vào hộp kiểm "nguồn sáng di động".

Đây là yêu thuật gì?

Tôi đã nhận được mã soạn sẵn WebGL này trôi nổi xung quanh tài khoản GitHub của mình , cái mà tôi sử dụng mọi lúc và sau đó để nhanh chóng tạo nguyên mẫu một số thứ đồ họa 2D trong WebGL. Với một số phép thuật đổ bóng, chúng ta cũng có thể làm cho nó trông hơi 3D, vì vậy tôi nghĩ đó là cách nhanh nhất để có được một số hiệu ứng đẹp mắt. Hầu hết các thiết lập là từ mã soạn sẵn đó và tôi đang xem xét rằng một thư viện cho bài nộp này và sẽ không bao gồm nó trong bài viết này. Nếu bạn quan tâm, hãy xem main.js trên GitHub (và các tệp khác trong thư mục đó).

Tất cả những gì JavaScript làm là để thiết lập bối cảnh WebGL, lưu trữ hạt giống trong bộ đồng phục cho trình đổ bóng và sau đó kết xuất một hình tứ giác trên toàn bộ bối cảnh. Shader đỉnh là một shader xuyên qua đơn giản, vì vậy tất cả các phép thuật xảy ra trong shader mảnh. Đó là lý do tại sao tôi gọi đây là bài nộp GLSL.

Phần lớn nhất của mã thực sự là tạo ra nhiễu Simplex, mà tôi tìm thấy trên GitHub . Vì vậy, tôi cũng bỏ qua điều đó trong danh sách mã dưới đây. Phần quan trọng là, nó định nghĩa một hàm snoise(vec2 coords)trả về nhiễu đơn giản mà không cần sử dụng tra cứu kết cấu hoặc mảng. Nó hoàn toàn không phải là hạt giống, vì vậy mẹo để có được tiếng ồn khác nhau là sử dụng hạt giống để xác định nơi cần thực hiện tra cứu.

Vì vậy, ở đây đi:

#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;
}

Đó là nó. Tôi có thể thêm một số giải thích vào ngày mai, nhưng ý tưởng cơ bản là:

  • Chọn một vị trí ánh sáng ngẫu nhiên.
  • Thêm một vài quãng tám tiếng ồn, để tạo ra mô hình fractal.
  • Bình phương tiếng ồn để giữ cho đáy thô.
  • Cho tiếng ồn qua tanhđể san bằng đỉnh.
  • Thêm hai quãng tám nữa để có thêm một chút kết cấu ở lớp trên cùng.
  • Tính toán các chỉ tiêu của bề mặt kết quả.
  • Chạy một bóng râm đơn giản trên bề mặt đó, với đèn chiếu sáng và khuếch tán. Các màu được chọn dựa trên một số màu ngẫu nhiên tôi chọn từ hình ảnh ví dụ đầu tiên.

17
Điều này thực tế hơn chính bức tường: o
Quentin

1
Một số "tĩnh mạch" / "rắn" / "sâu" sẽ làm cho bức tranh này phù hợp hơn với "bức tường". Nhưng vẫn đẹp.
Nova

33

Toán học Spackling

Ứng dụng dưới đây áp dụng lốm đốm cho một hình ảnh ngẫu nhiên. Nhấp vào "bản vá mới" sẽ tạo ra một hình ảnh ngẫu nhiên mới để làm việc và sau đó áp dụng các hiệu ứng theo các cài đặt hiện tại. Các hiệu ứng là sơn dầu, bộ lọc Gaussian, áp phích và dập nổi. Mỗi hiệu ứng có thể được điều chỉnh độc lập. Hạt giống cho trình tạo số ngẫu nhiên có thể là bất kỳ số nguyên nào từ 1 đến 2 ^ 16.

Cập nhật : Bộ lọc Gaussian, làm mềm các cạnh, giờ là hiệu ứng hình ảnh cuối cùng được áp dụng. Với sửa đổi này, hiệu ứng posterization không còn cần thiết và do đó bị loại bỏ.

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}])]

kết quả cuối cùng


Giải trình

Lời giải thích dựa trên một phiên bản hơi khác, trong đó áp phích được sử dụng và GaussianFilterđược áp dụng sớm. Nhưng nó vẫn phục vụ để làm rõ cách mỗi hiệu ứng hình ảnh thay đổi một hình ảnh. Kết quả cuối cùng là một kết cấu sơn với các cạnh sắc nét hơn. Khi bộ lọc Gaussian chỉ được áp dụng ở cuối, kết quả sẽ mượt mà hơn, như hình trên cho thấy.

Chúng ta hãy nhìn vào một số hiệu ứng hình ảnh, từng cái một.

Tạo một hình ảnh bắt đầu.

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

hình ảnh ngẫu nhiên


Lena sẽ cho chúng ta thấy mỗi hiệu ứng hình ảnh biến đổi một bức tranh giống như cuộc sống như thế nào.

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

Lena


Một hiệu ứng sơn dầu áp dụng cho Lena.

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

dầu lena

Một hiệu ứng sơn dầu áp dụng cho hình ảnh ngẫu nhiên của chúng tôi. Hiệu ứng được tăng cường (16 thay vì 8).

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

dầu


Hiệu ứng bộ lọc Gaussian áp dụng cho Lena (không áp dụng cho phiên bản hiệu ứng sơn dầu của Lena). Bán kính là 10 pixel. (Trong phiên bản cuối cùng, ở đầu mục này, GaussianFilter được áp dụng làm hiệu ứng cuối cùng.)

 GaussianFilter[Lena, 10]

lena gaussian.


Hiệu ứng bộ lọc Gaussian nhẹ hơn được áp dụng cho r1. Bán kính là 5 pixel.

 r2 = GaussianFilter[r1, 5]

gauss


Một hiệu ứng áp phích dữ dội được áp dụng cho Lena. (Trong phiên bản cuối cùng của ứng dụng, tôi đã xóa áp phích. Nhưng chúng tôi sẽ để nó trong phân tích, vì các ví dụ trong phân tích được dựa trên phiên bản trước đó có áp phích.)

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

lena posterize


Một hiệu ứng posterization áp dụng cho r2.

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

áp phích


Lena dập nổi

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

lena dập nổi


Dập nổi r3 hoàn thành xử lý hình ảnh. Điều này được dự định để trông giống như trần nhà của OP.

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

dập nổi


Đối với những người tò mò, đây là Lena với các hiệu ứng hình ảnh tương tự được áp dụng.

lena4


... có tích hợp để lấy hình ảnh Lena không? CƯỜI NGẢ NGHIÊNG.
dùng253751

7
Đúng. Có khoảng 30 hình ảnh tích hợp trong Mathematica được sử dụng để kiểm tra xử lý hình ảnh.
DavidC

Với một sửa đổi nhỏ, người ta có thể nuôi RandomIntegermột hạt giống, do đó đảm bảo một đầu ra cụ thể. Hay bạn có ý gì khác, như một hình ảnh bắt đầu, không ngẫu nhiên mà hiệu ứng nào được áp dụng?
DavidC

1
Bây giờ nó chấp nhận một hạt giống từ 1 đến 2 ^ 16.
DavidC

1
+1 vì Lena will show us how each image effect transforms a life-like pictuređã biến tôi thành LOL. Điều kỳ lạ là, hình ảnh Lena cuối cùng dường như có một người Aztec hoặc Inca quay mặt sang trái, đội mũ trùm đầu và vặn một cành cây như thể đó là một khẩu súng.
Cấp sông St

13

POV-Ray

Rất nhiều tiềm năng chơi gôn, chạy với povray /RENDER wall.pov -h512 -w512 -K234543 nhập mô tả hình ảnh ở đây

Đầu tiên, nó tạo ra một kết cấu ngẫu nhiên, nhưng thay vì dừng lại ở đó, nó biến đổi kết cấu thành trường chiều cao 3D để làm cho các bóng xuyên tâm từ máy ảnh trở nên chân thực hơn. Và để đo lường tốt, nó thêm một kết cấu khác của những vết sưng nhỏ trên đầu.
Cách duy nhất ngoài việc mã hóa hạt giống ngẫu nhiên là sử dụng clockbiến có nghĩa là cho hình ảnh động, điều này được truyền bằng -K{number}cờ

#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>
}

Không cần phải chơi golf này cả. Kết quả tốt đẹp! :)
Martin Ender
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.