สีทาผนังพื้นผิวที่สร้างโดยคอมพิวเตอร์


48

สีบนผนังในห้องของฉันมีพื้นผิวแบบสามมิติแบบสุ่มเกือบจะเป็นเศษส่วน:

รูปภาพ A

ในการท้าทายนี้คุณจะเขียนโปรแกรมที่สร้างภาพสุ่มที่ดูเหมือนว่าพวกเขาอาจเป็นส่วนหนึ่งของกำแพงของฉัน

ด้านล่างฉันได้รวบรวม 10 ภาพของจุดที่แตกต่างกันบนผนังของฉัน ทั้งหมดมีแสงเดียวกันประมาณเดียวกันและทุกอย่างถูกนำไปด้วยกล้องห่างจากผนังหนึ่งฟุต เส้นขอบถูกครอบตัดอย่างสม่ำเสมอเพื่อให้มีขนาด 2048 x 2048 พิกเซลจากนั้นจะถูกปรับเป็น 512 x 512 ภาพด้านบนคือภาพ A

นี่เป็นเพียงภาพขนาดย่อคลิกที่ภาพเพื่อดูขนาดเต็ม!

A: B: C: D: E:รูปภาพ A รูปภาพ B รูปภาพ C รูปภาพ D รูปภาพ E

F: G: H: I: J:รูปภาพ F รูปภาพ G รูปภาพ H รูปฉัน รูปภาพ J

งานของคุณคือการเขียนโปรแกรมที่ใช้จำนวนเต็มบวกจาก 1 ถึง 2 16เป็นเมล็ดสุ่มและสำหรับแต่ละค่าจะสร้างภาพที่แตกต่างซึ่งดูเหมือนว่าอาจเป็น "ภาพที่สิบเอ็ด" ของผนังของฉัน หากใครบางคนมองที่ 10 ภาพของฉันและบางส่วนของคุณไม่สามารถบอกได้ว่าเป็นคอมพิวเตอร์ที่สร้างขึ้นแล้วคุณทำได้ดีมาก!

โปรดอวดรูปภาพที่คุณสร้างขึ้นบางส่วนเพื่อให้ผู้ดูสามารถเห็นได้โดยไม่ต้องเรียกใช้รหัส

ฉันตระหนักว่าแสงในภาพของฉันไม่เหมือนกันอย่างสมบูรณ์ในความเข้มหรือสี ฉันขอโทษสำหรับเรื่องนี้ แต่มันเป็นสิ่งที่ดีที่สุดที่ฉันทำได้โดยไม่ต้องใช้อุปกรณ์ส่องสว่าง รูปภาพของคุณไม่จำเป็นต้องมีแสงที่เปลี่ยนแปลงได้ (แม้ว่าจะทำได้) พื้นผิวเป็นสิ่งสำคัญที่จะเน้น

รายละเอียด

  • คุณสามารถใช้เครื่องมือและไลบรารีการประมวลผลภาพ
  • รับอินพุตในลักษณะทั่วไปที่คุณต้องการ (บรรทัดคำสั่ง stdin ตัวแปรที่ชัดเจน ฯลฯ )
  • ภาพที่ส่งออกสามารถอยู่ในรูปแบบไฟล์ภาพ lossless ทั่วไปหรือสามารถแสดงในหน้าต่าง / bowser
  • คุณสามารถวิเคราะห์ภาพ 10 ภาพของฉันโดยทางโปรแกรม แต่อย่าคิดว่าทุกคนที่ใช้รหัสของคุณสามารถเข้าถึงภาพเหล่านั้นได้
  • คุณต้องสร้างภาพโดยทางโปรแกรม คุณไม่สามารถใช้รหัสที่แตกต่างกันเล็กน้อยสำหรับหนึ่งในภาพของฉันหรือภาพสต็อกอื่น ๆ (ผู้คนจะให้คะแนนคุณสำหรับเรื่องนี้อยู่ดี)
  • คุณอาจใช้เครื่องกำเนิดตัวเลขเทียมหลอกในตัวและถือว่าระยะเวลาเป็น 2 16หรือมากกว่า

เกณฑ์การให้คะแนน

นี่คือการประกวดความนิยมเพื่อให้คำตอบที่ได้รับคะแนนสูงสุดชนะ


PerlinNoise + การตัดปลาย + การแรเงา
Octopus

21
ฉันทำภาพวอลล์ไม่ได้ดังนั้นแทนที่จะมีการ์ตูน !
Sp3000

8
@ Sp3000 นั่นเป็นสิ่งที่เกิดขึ้นไม่มากก็น้อย แม้ว่าถ้าฉันได้รับการมองขึ้นฉันอาจจะได้รับการแต่งตั้งเพดานของฉันซึ่งสามารถทำงานได้เช่นกัน ...
คาลวินอดิเรก

คำตอบ:


65

GLSL (+ JavaScript + WebGL)

ป้อนคำอธิบายรูปภาพที่นี่

การสาธิตสด | พื้นที่เก็บข้อมูล GitHub

วิธีใช้

โหลดหน้านี้ซ้ำสำหรับภาพสุ่มใหม่ drawScreen(seed)หากคุณต้องการที่จะเลี้ยงในเมล็ดโดยเฉพาะอย่างยิ่งเปิดคอนโซลและโทรเบราว์เซอร์ของคุณ คอนโซลควรแสดง seed ที่ใช้กับโหลด

ฉันไม่ได้ทดสอบสิ่งนี้บนแพลตฟอร์มจำนวนมากดังนั้นแจ้งให้เราทราบหากไม่ได้ผลสำหรับคุณ แน่นอนว่าเบราว์เซอร์ของคุณต้องรองรับ WebGL ข้อผิดพลาดจะปรากฏขึ้นในคอลัมน์ทางด้านซ้ายหรือในคอนโซลของเบราว์เซอร์ (ขึ้นอยู่กับประเภทของข้อผิดพลาด)

ใหม่:ตอนนี้คุณสามารถทำให้กำแพงมีชีวิตชีวาได้โดยทำเครื่องหมายที่ช่องทำเครื่องหมาย "แหล่งกำเนิดแสงที่เคลื่อนที่ได้"

คาถานี้คืออะไร?

ฉันได้รับโค้ดแท่งประมวลผล WebGL ที่ลอยอยู่รอบ ๆ บัญชี GitHub ของฉันซึ่งฉันใช้อยู่ทุกขณะจากนั้นสร้างต้นแบบกราฟิก 2D สองมิติใน WebGL อย่างรวดเร็ว ด้วยเวทย์มนตร์ shader เราสามารถทำให้มันดู 3D เล็กน้อยดังนั้นฉันคิดว่านั่นเป็นวิธีที่เร็วที่สุดในการทำให้เอฟเฟกต์ดีๆ การตั้งค่าส่วนใหญ่มาจากรหัสสำเร็จรูปและฉันกำลังพิจารณาว่าห้องสมุดสำหรับการส่งนี้และจะไม่รวมไว้ในโพสต์นี้ หากคุณสนใจลองดูmain.jsใน GitHub (และไฟล์อื่น ๆ ในโฟลเดอร์นั้น)

JavaScript ทั้งหมดทำเพื่อตั้งค่าบริบท WebGL จัดเก็บเมล็ดพันธุ์ในรูปแบบสำหรับ shader จากนั้นแสดงผลหนึ่งส่วนสี่ส่วนทั่วทั้งบริบท เวอร์เท็กซ์เชดเดอร์เป็นพาสสวิงแบบง่าย ๆ ดังนั้นเวทมนตร์ทั้งหมดจึงเกิดขึ้นในตัวแบ่งส่วน นั่นเป็นเหตุผลที่ฉันเรียกสิ่งนี้ว่าการส่งแบบ 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ไปยังระดับปิดด้านบน
  • เพิ่มอ็อกเทฟอีกสองตัวเพื่อเพิ่มพื้นผิวเล็กน้อยบนเลเยอร์ด้านบน
  • คำนวณบรรทัดฐานของพื้นผิวที่เกิด
  • ใช้พงษ์แรเงาที่เรียบง่ายบนพื้นผิวนั้นด้วยแสงที่กระจายแสง สีถูกเลือกตามสีแบบสุ่มที่ฉันเลือกจากภาพตัวอย่างแรก

17
สิ่งนี้สมจริงกว่ากำแพง: o
เควนติ

1
"เส้นเลือด" / "งู" / "หนอน" มากกว่านี้จะทำให้รูปภาพนี้เหมาะสมสำหรับ "ผนัง" มากขึ้น แต่ก็ยังดี
โนวา

33

Mathematica Spackling

แอปด้านล่างนี้ใช้การทำให้เป็นจุดภาพสุ่ม การคลิกที่ "แพทช์ใหม่" จะสร้างภาพสุ่มใหม่เพื่อใช้งานจากนั้นจึงใช้เอฟเฟกต์ตามการตั้งค่าปัจจุบัน ผลที่ได้คือภาพสีน้ำมันตัวกรองเกาส์เซียนโปสเตอร์และลายนูน แต่ละเอฟเฟกต์สามารถปรับแต่งได้อย่างอิสระ seed สำหรับตัวสร้างหมายเลขสุ่มสามารถเป็นจำนวนเต็มใด ๆ ตั้งแต่ 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}]

น้ำมัน


เอฟเฟกต์แบบเกาส์ที่ใช้กับลีนา (ไม่ใช่รุ่นเอฟเฟ็กต์ภาพสีน้ำมันของลีนา) รัศมีคือ 10 พิกเซล (ในเวอร์ชั่นสุดท้ายที่ด้านบนของรายการนี้ GaussianFilter จะถูกใช้เป็นเอฟเฟกต์สุดท้าย)

 GaussianFilter[Lena, 10]

Lena Gaussian


เอฟเฟกต์ตัวกรองแบบเกาส์ที่ค่อนข้างแรงขึ้นนำไปใช้กับ r1 รัศมีคือ 5 พิกเซล

 r2 = GaussianFilter[r1, 5]

เกาส์


การเอฟเฟกต์ภาพโปสเตอร์ที่เข้มข้นใช้กับ Lena (ในเวอร์ชันสุดท้ายของแอพฉันลบ posterization ออก แต่เราจะทิ้งไว้ในการวิเคราะห์เนื่องจากตัวอย่างในการวิเคราะห์นั้นอิงจากเวอร์ชันก่อนหน้านี้ด้วยการทำให้เป็นโปสเตอร์)

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

Lena posterize


เอฟเฟกต์ภาพโปสเตอร์ที่ใช้กับ r2

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

Posterize


ลายนูน Lena

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

Lena ลายนูน


Embossing r3 เสร็จสิ้นการประมวลผลภาพ นี่มีจุดประสงค์เพื่อให้ดูเหมือนเพดานของ OP

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

ทำให้มีผิวนูน


สำหรับคนที่อยากรู้อยากเห็น Lena นี่คือเอฟเฟกต์ภาพเดียวกันกับที่ใช้

lena4


... มีภาพในตัวเพื่อรับภาพ Lena หรือไม่? ฮ่า ๆ.
253751

7
ใช่. มีรูปภาพในตัวประมาณ 30 ภาพใน Mathematica ที่ใช้สำหรับการทดสอบการประมวลผลภาพ
DavidC

ด้วยการดัดแปลงเพียงเล็กน้อยใครสามารถป้อนRandomIntegerเมล็ดได้ดังนั้นจึงรับประกันผลลัพธ์เฉพาะ หรือคุณหมายถึงอย่างอื่นเช่นรูปภาพเริ่มต้นไม่ใช่แบบสุ่มซึ่งมีเอฟเฟกต์ใดบ้าง
DavidC

1
ตอนนี้รับเมล็ดจาก 1 ถึง 2 ^ 16
DavidC

1
+1 เพราะLena will show us how each image effect transforms a life-like pictureทำให้ฉัน LOL สิ่งที่แปลกคือภาพสุดท้ายของ Lena ดูเหมือนจะมี Aztec หรือ Inca หันหน้าไปทางซ้ายสวมผ้าโพกศีรษะ
เลเวลริเวอร์เซนต์

13

POV-Ray

ศักยภาพในการเล่นกอล์ฟมีมากมาย povray /RENDER wall.pov -h512 -w512 -K234543 ป้อนคำอธิบายรูปภาพที่นี่

ก่อนอื่นมันจะสร้างพื้นผิวแบบสุ่ม แต่แทนที่จะหยุดตรงนั้นมันจะเปลี่ยนพื้นผิวให้เป็นฟิลด์ความสูง 3 มิติเพื่อสร้างเงารัศมีจากแฟลชของกล้องให้สมจริงยิ่งขึ้น และสำหรับการวัดที่ดีก็เพิ่มพื้นผิวของการกระแทกเล็ก ๆ อีกด้านบน
วิธีเดียวที่นอกเหนือจากการเข้ารหัสแบบสุ่มคือการใช้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>
}

ไม่จำเป็นต้องเล่นกอล์ฟเลย ผลลัพธ์ที่ดี! :)
Martin Ender
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.