2013-02-14 37 views
9

Tôi đang cố gắng tìm ra một tập lệnh sẽ tạo ra một kết cấu (sau đó có thể được nhân với một hình ảnh thang độ xám để "áp dụng" nó). Cho đến nay phương pháp của tôi liên quan đến việc gieo hạt RNG, sau đó tạo ngẫu nhiên ma trận 8x8 của các số nguyên trong phạm vi [0,3], sau đó mở rộng ma trận đó thành hình ảnh 256x256 bằng cách sử dụng một mức nội suy nào đó.Thủ tục tạo ra một kết cấu

Dưới đây là một đầu ra ví dụ (giá trị hạt giống 24):

Sample http://adamhaskell.net/misc/texture/sample.png

Bên trái là ma trận có quy mô với gần hàng xóm suy. Ở bên phải là nỗ lực của tôi tại nội suy song tuyến. Đối với hầu hết các phần có vẻ như không sao, nhưng sau đó bạn nhận được cấu trúc như gần giữa bên trái, nơi có hai hình vuông màu cam liền kề đường chéo phải đối mặt với hai hình vuông màu đỏ liền kề đường chéo, và kết quả là không có nội suy cho khu vực đó. Ngoài ra, nó đang được xử lý giống như một bản đồ nhiệt (như được hiển thị bởi sự phong phú của màu da cam ở góc trên cùng bên trái) và điều đó gây ra nhiều vấn đề hơn.

Dưới đây là đoạn code tôi có cho "Bilinear suy" của tôi:

<?php 
$matrix = Array(); 
srand(24); 
$dim = 256; 
$scale = 32; 
for($y=0;$y<=$dim/$scale;$y++) for($x=0;$x<=$dim/$scale;$x++) $matrix[$y][$x] = rand(0,3); 
$img = imagecreate($dim,$dim); 
imagecolorallocate($img,255,255,255); 
$cols = Array(
    imagecolorallocate($img,128,0,0), 
    imagecolorallocate($img,128,64,32), 
    imagecolorallocate($img,128,128,0), 
    imagecolorallocate($img,64,64,64) 
); 
for($y=0;$y<$dim;$y++) { 
    for($x=0;$x<$dim;$x++) { 
     $xx = floor($x/$scale); $yy = floor($y/$scale); 
     $x2 = $x%$scale; $y2 = $y%$scale; 
     $col = $cols[round((
      $matrix[$yy][$xx]*($scale-$x2)*($scale-$y2) 
      + $matrix[$yy][$xx+1]*$x2*($scale-$y2) 
      + $matrix[$yy+1][$xx]*($scale-$x2)*$y2 
      + $matrix[$yy+1][$xx+1]*$x2*$y2 
     )/($scale*$scale))]; 
     imagesetpixel($img,$x,$y,$col); 
    } 
} 
header("Content-Type: image/png"); 
imagepng($img); 
exit; 

Trong thực tế, điều này có thể là một chút của một vấn đề XY. Những gì tôi đang cố gắng làm là tạo ra "mô hình lông" cho các sinh vật trong một trò chơi tôi đang lên kế hoạch. Đặc biệt tôi muốn có thể có nó để nhân giống kết hợp các yếu tố từ hai cha mẹ (có thể là màu sắc hoặc các yếu tố của mô hình), do đó, chỉ cần có một hạt giống ngẫu nhiên sẽ không thực sự cắt nó. Lý tưởng nhất là tôi cần một số loại phương pháp tiếp cận dựa trên véc tơ, nhưng tôi ra khỏi chiều sâu của tôi ở đó để bất kỳ sự trợ giúp nào cũng sẽ được đánh giá rất cao.

+3

Tôi nghĩ lý do tại sao nó trông giống như một bản đồ nhiệt là bởi vì bạn không thực sự làm một nội suy tuyến tính thực sự của màu sắc hàng xóm gần nhất, bạn đang thực sự lựa chọn màu sắc gần nhất hiện có cho nội suy này. Đó cũng là lý do tại sao không có nội suy ở gần giữa bên trái. Tại sao bạn không thể trộn màu? Và nếu đó là kết cấu, bạn không thể pha trộn các kết cấu với một số thành phần alpha? – zakinster

+0

Không thực sự là câu trả lời, nhưng có thể là câu chuyện có liên quan hữu ích. Tôi nghĩ rằng Alan Turing đã làm việc trên một số thuật toán toán học để sản xuất các mẫu da động vật thuộc loại này. Có lẽ chúng đáng xem? – AntonChanning

Trả lời

1

Một vài điều tôi suy nghĩ:

  1. You are not nội suy các giá trị màu. Để mở rộng nhận xét của zakinster, bạn đang nội suy các chỉ số màu và sau đó làm tròn các chỉ mục màu. Một trong những hiệu ứng này là bạn gió lên với một dải màu vàng (chỉ số 2) ở giữa màu da cam (chỉ số 1) và màu xám (chỉ số 3) khu vực. Nếu bạn xen vào các giá trị màu thay vào đó, bạn sẽ có gió, có lẽ, màu cam xám?

  2. Bạn có nhiều màu vàng và màu da cam, và ít màu đỏ và xám hơn trong hình ảnh cuối cùng. Điều này là do sử dụng vòng() để chụp vào một chỉ mục màu. Tính toán của bạn (trước khi round()) có thể tạo ra phao phân bố đều giữa 0 đến 3, nhưng làm tròn không bảo toàn nó.

Vì vậy, sau đây là một số gợi ý:

  1. Nếu bạn không giới hạn đến 4 màu, sử dụng nhiều. Nội suy các giá trị màu (tức là (128,0,0) trộn với (64,64,64) tạo ra (91,32,32)) thay vì chỉ số.

  2. Nếu bạn bị giới hạn chỉ 4 màu đó, hãy thử một số loại phối màu. Một cách tiếp cận đơn giản, với những thay đổi tối thiểu đối với mã của bạn, sẽ thêm một số ngẫu nhiên vào chỉ mục màu được chọn. Vì vậy, thay vì vòng (...), hãy làm một cái gì đó như thế này: nói rằng tính toán của bạn tạo ra giá trị 1.7. Sau đó, làm tròn đến 2 với xác suất 70% và giảm xuống còn 30% còn lại. Điều này sẽ pha trộn các màu sắc, nhưng nó có thể tạo ra một hình ảnh rất ồn ào. Nếu bạn chuẩn bị thay đổi mã của mình đáng kể hơn, hãy xem Floyd-Steinberg dithering.

1

Tôi biết nó là câu hỏi cũ, và câu trả lời từ @ Markku-k là đúng, dù sao tôi có vấn đề tương tự và đây là mã của tôi sửa đổi cho câu hỏi

vài thông báo:

  1. nó tạo ra 2 hình ảnh trong một, để hiển thị "ma trận ban đầu" và kết quả
  2. nó sử dụng ma trận 8x8 để tạo ra kết quả, nhưng ma trận thực tế là 10x10 để trang trải biên giới
  3. nó sử dụng màu để màu thuật toán chỉ số cơ sở trên đồng bằng đơn giản, nó hoạt động ok cho tôi

đây là mã:

<?php 
$matrix = array(); 
$dim = 256; 
$scale = 32; 

for($y=0; $y<=9; $y++) 
{ 
    $matrix[$y] = array(); 
    for($x=0; $x<=9; $x++) 
    { 
     $same = false; 
     do 
     { 
      $matrix[$y][$x] = mt_rand(0, 3); // do not use rand function, mt_rand provide better results 
      if (($x>0) && ($y>0)) // check for checkers siatuion, where no colors are preferable and produce 90 degree angles 
      { 
       $c1 = $matrix[$y-1][$x-1]; 
       $c2 = $matrix[$y][$x]; 
       $c3 = $matrix[$y-1][$x]; 
       $c4 = $matrix[$y][$x-1]; 
       $same = (($c1==$c2) && ($c3==$c4)); 
      } 
     } while ($same); 
    } 
} 

$img = imagecreate($dim*2 + 32*4, $dim + 32*2); 
$colorsRGB = array(0x800000, 0x804020, 0x808000, 0x404040); 
$cols = Array(
     imagecolorallocate($img,128,0,0), // red 
     imagecolorallocate($img,128,64,32), // orange 
     imagecolorallocate($img,128,128,0), // yellow 
     imagecolorallocate($img,64,64,64), // gray 
     imagecolorallocate($img,0,0,0), // black, just to fill background 
); 

imagefilledrectangle($img, 0, 0, $dim*2 + 32*4 - 1, $dim + 32*2 - 1, $cols[4]); 

function mulclr($color, $multiplicator) 
{ 
    return array(($color>>16) * $multiplicator, (($color>>8)&0xff) * $multiplicator, ($color&0xff) * $multiplicator); 
} 

function addclr($colorArray1, $colorArray2) 
{ 
    return array($colorArray1[0]+$colorArray2[0], $colorArray1[1]+$colorArray2[1], $colorArray1[2]+$colorArray2[2]); 
} 

function divclr($colorArray, $div) 
{ 
    return array($colorArray[0]/$div, $colorArray[1]/$div, $colorArray[2]/$div); 
} 

function findclridx($colorArray, $usedColors) 
{ 
    global $colorsRGB; 

    $minidx = $usedColors[0]; 
    $mindelta = 255*3; 
    foreach ($colorsRGB as $idx => $rgb) 
    { 
     if (in_array($idx, $usedColors)) 
     { 
      $delta = abs($colorArray[0] - ($rgb>>16)) + abs($colorArray[1] - (($rgb>>8)&0xff)) + abs($colorArray[2] - ($rgb&0xff)); 
      if ($delta < $mindelta) 
      { 
       $minidx = $idx; 
       $mindelta = $delta; 
      } 
     } 
    } 
    return $minidx; 
} 

for($y=0; $y<($dim+64); $y++) 
{ 
    for($x=0; $x<($dim+64); $x++) 
    { 
     $xx = $x>>5; 
     $yy = $y>>5; 
     $x2 = ($x - ($xx<<5)); 
     $y2 = ($y - ($yy<<5)); 

     imagesetpixel($img, $x, $y, $cols[$matrix[$yy][$xx]]); 

     if (($xx>0) && ($yy>0) && ($xx<=8) && ($yy<=8)) 
     { 
      $color1 = $colorsRGB[$matrix[$yy][$xx]]; 
      $color2 = $colorsRGB[$matrix[$yy][ ($xx+1) ]]; 
      $color3 = $colorsRGB[$matrix[ ($yy+1) ][$xx]]; 
      $color4 = $colorsRGB[$matrix[ ($yy+1) ][ ($xx+1) ]]; 

      $usedColors = array_unique(array($matrix[$yy][$xx], $matrix[$yy][ ($xx+1) ], $matrix[ ($yy+1) ][$xx], $matrix[ ($yy+1) ][ ($xx+1) ])); 

      $a1 = mulclr($color1, ($scale-$x2)*($scale-$y2)); 
      $a1 = addclr($a1, mulclr($color2, $x2*($scale-$y2))); 
      $a1 = addclr($a1, mulclr($color3, ($scale-$x2)*$y2)); 
      $a1 = addclr($a1, mulclr($color4, $x2*$y2)); 
      $a1 = divclr($a1, $scale*$scale); 
      $clrIdx = findclridx($a1, $usedColors); 

      $col = $cols[$clrIdx]; 
      imagesetpixel($img, $dim+$x+32*2, $y, $col); 
     } 
    } 
} 
header("Content-Type: image/png"); 
imagepng($img); 
exit; 

đây là kết quả mẫu:

enter image description here

+0

Đáng chú ý rằng một cách có thể để tránh có ma trận 10x10 trong trường hợp này có thể là giả định một gạch ma trận 8x8 với chính nó, từ trên xuống dưới và từ trái sang phải. Như vậy ở phía trên bên trái của góc trên cùng bên trái là góc dưới cùng bên phải. – AntonChanning

Các vấn đề liên quan