// 中点変位法でヘイトマップを生成 // 3D表示してみる // クリックするたびにヘイトマップを再生成 // // ActionScript入門Wiki - 中点変位法でハイトマップを生成する // http://web.archive.org/web/20111017054549/http://www40.atwiki.jp/spellbound/pages/1691.html PImage img; float minsize = 0.5; // 分割を終了させるしきい値 // 初期化 void setup() { size(512, 512, P3D); smooth(8); frameRate(24); img = createImage(24, 24, RGB); makeHeightMap(); } // 描画 void draw() { background(255); lights(); float mx = 180 * (mouseX - width / 2) / (width / 2); float my = 90 * (mouseY - height / 2) / (height / 2); float sx = 64; float sz = sx; float sy = 4; float ay = 128 * sy; translate(width / 2, height / 2, -128 * sy); rotateX(radians(-my)); rotateY(radians(mx)); int w = img.width; int h = img.height; float ww = w / 2; float hh = h / 2; stroke(0); strokeWeight(1); fill(200); img.loadPixels(); for (int z = 0; z < h - 1; z++) { for (int x = 0; x < w - 1; x++) { int adrs = z * w + x; float v0 = -red(img.pixels[adrs]) * sy + ay; float v1 = -red(img.pixels[adrs + 1]) * sy + ay; float v2 = -red(img.pixels[adrs + w]) * sy + ay; float v3 = -red(img.pixels[adrs + w + 1]) * sy + ay; float x0 = (x - ww) * sx; float x1 = ((x + 1) - ww) * sx; float z0 = (z - hh) * sz; float z1 = ((z + 1) - hh) * sz; beginShape(TRIANGLES); vertex(x0, v0, z0); vertex(x1, v1, z0); vertex(x0, v2, z1); vertex(x1, v1, z0); vertex(x0, v2, z1); vertex(x1, v3, z1); endShape(); } } } // クリックでヘイトマップ再生成 void mouseClicked() { makeHeightMap(); } // ヘイトマップを生成 void makeHeightMap() { img.loadPixels(); float tl = random(1); float tr = random(1); float bl = random(1); float br = random(1); generateHeightMap(0, 0, (float)img.width, (float)img.width, tl, tr, bl, br); img.updatePixels(); } // ヘイトマップ生成 // @param x [Number] 左上の座標 x // @param y [Number] 左上の座標 y // @param sz [Number] サイズ(横幅, 縦幅) // @param sz0 [Number] 初期値サイズ(横幅, 縦幅) // @param tl [Number] 左上の値 // @param tr [Number] 右上の値 // @param bl [Number] 左下の値 // @param br [Number] 右下の値 void generateHeightMap(float x, float y, float sz, float sz0, float tl, float tr, float bl, float br) { if (sz <= minsize) { // 分割終了 float v = (tl + tr + bl + br) / 4; // 平均値を得る float col = v * 255; // 色(明るさ)を得る int px = int(x); int py = int(y); img.pixels[py * img.width + px] = color(col); return; } // 分割中 // 四隅から見て中央にあるピクセルに // 平均値 + 変位させるランダム値を入れる float midv = (tl + tr + bl + br) / 4; midv += (random(-0.5, 0.5) * sz / sz0); // 0.0 から 1.0 の範囲に収める midv = min(max(midv, 0.0), 1.0); // 中央から見て上下左右にあるピクセルにも平均値を入れる float pTop = (tl + tr) / 2; // 左上と右上の平均値 float pBottom = (bl + br) / 2; // 左下と右下の平均値 float pLeft = (tl + bl) / 2; // 左上と左下の平均値 float pRight = (tr + br) / 2; // 右上と右下の平均値 // 2x2に分割するのでサイズを半分にする sz /= 2; generateHeightMap(x, y, sz, sz0, tl, pTop, pLeft, midv); generateHeightMap(x + sz, y, sz, sz0, pTop, tr, midv, pRight); generateHeightMap(x, y + sz, sz, sz0, pLeft, midv, bl, pBottom); generateHeightMap(x + sz, y + sz, sz, sz0, midv, pRight, pBottom, br); }