// 一本道道路の生成テスト /* @pjs preload="road_tex.png"; crisp="true"; */ PImage img; // テクスチャ画像 Road road; // 道路生成クラス float t; // 時間(進行度) void setup() { size(1280, 720, P3D); img = loadImage("road_tex.png"); textureMode(IMAGE); noStroke(); road = new Road(); t = 0; } void draw() { background(0); // 道路中央の線分を得て、どのあたりに居るかを得る PVector[] l0 = road.getLinePos(road.idx + 2); PVector[] l1 = road.getLinePos(road.idx + 12); float lx0 = getLinearValue(l0[0].x, l0[1].x, t); float ly0 = getLinearValue(l0[0].y, l0[1].y, t); float lz0 = getLinearValue(l0[0].z, l0[1].z, t); float lx1 = getLinearValue(l1[0].x, l1[1].x, t); // float ly1 = getLinearValue(l1[0].y, l1[1].y, t); float lz1 = getLinearValue(l1[0].z, l1[1].z, t); pushMatrix(); // 現在の座標系を保存 translate(width / 2, height / 2, 0); // カメラ設定 float ty = 50; camera(lx0, ly0 - ty, lz0, // 視点x,y,z lx1, ly0 - ty, lz1, // 中心点x,y,z 0.0, 1.0, 0.0 // 天地x,y,z ); // 道路を描画 int idx = road.idx; float tu = 0; float tw = img.width; float th = img.height / 2; for (int i = idx; i< idx + 72; i++ ) { PolyData p = road.getPoly(i); float tv = (p.tex_num == 0)? 0 : th; beginShape(QUADS); texture(img); vertex(p.p[0].x, p.p[0].y, p.p[0].z, tu, tv); vertex(p.p[1].x, p.p[1].y, p.p[1].z, tu + tw, tv); vertex(p.p[2].x, p.p[2].y, p.p[2].z, tu + tw, tv + th); vertex(p.p[3].x, p.p[3].y, p.p[3].z, tu, tv + th); endShape(); } popMatrix(); // 座標系を復元 // 時間(進行度)を進める t += 0.15; if (t >= 1.0) { road.incIndex(); t -= 1.0; } } // 一次関数の値を取得 float getLinearValue(float v_start, float v_end, float t) { return (v_start + (v_end - v_start) * t); } // 道路用座標値保存用クラス class PosData { PVector p0, p1; int tex_num; PosData (float x0, float y0, float z0, float x1, float y1, float z1, int tn) { p0 = new PVector(x0, y0, z0); p1 = new PVector(x1, y1, z1); tex_num = tn; } } class PolyData { PVector[] p; int tex_num; PolyData (PVector p0, PVector p1, PVector p2, PVector p3, int tn) { p = new PVector[4]; p[0] = p0; p[1] = p1; p[2] = p2; p[3] = p3; tex_num = tn; } } // 道路生成クラス class Road { int idx, w, dist, tex_num; float t, t_spd; float angw_beg, angw_chg; float y_chg; float v_dur; PVector pnt; PosData[] pos_list; Road () { idx = 0; w = 160 / 2; // 道路の幅(片方の幅) dist = 64; // 道路の一片の長さ tex_num = 0; // テクスチャ番号(0 or 1) t = 0.0; // 時間(進行度) angw_beg = 270.0; // スタート角度 v_dur = 1.0; setNextChangeValue(); pnt = new PVector(0, 0, 0); // ポリゴン座標群を生成して配列に格納 pos_list = new PosData[256]; float x0 = pnt.x - w; float x1 = pnt.x + w; pos_list[0] = new PosData(x0, pnt.y, pnt.z, x1, pnt.y, pnt.z, tex_num); updateTexNum(); for (int i=1; i < pos_list.length; i++) { pushNewPos(i); } } // 角度の変化量と変化速度を更新 void setNextChangeValue() { angw_chg = random(-80, 80); y_chg = random(-10.0, 10.0); t_spd = random(0.015, 0.04); } // 時間(進行度)を進める void setNextTime() { t += t_spd; if (t >= 1.0) { t -= 1.0; angw_beg += angw_chg; pnt.y += y_chg; setNextChangeValue(); } } // 道路片参照インデックス値を更新。新座標値を生成して配列に格納 void incIndex() { pushNewPos(idx); idx = (idx + 1) % pos_list.length; } // テクスチャ番号を更新 void updateTexNum() { tex_num = (tex_num + 1) % 2; } // 道路片のポリゴン座標を得る PVector[] getNextPos(PVector pnt, float w, float h, float t, float angw_beg, float angw_chg, float y_chg, float v_dur) { float angw = easeInOutQuint(t, angw_beg, angw_chg, v_dur); float cy = easeInOutExpo(t, pnt.y, y_chg, v_dur); float dx = radians(angw); float cx = h * cos(dx) + pnt.x; float cz = h * sin(dx) + pnt.z; PVector c = new PVector(cx, cy, cz); dx = radians(angw - 90.0); PVector p0 = new PVector(w * cos(dx) + cx, cy, w * sin(dx) + cz); dx = radians(angw + 90.0); PVector p1 = new PVector(w * cos(dx) + cx, cy, w * sin(dx) + cz); PVector[] ret = {c, p0, p1}; return ret; } // 座標を生成して配列に格納 void pushNewPos(int idx) { PVector[] p = getNextPos(pnt, w, dist, t, angw_beg, angw_chg, y_chg, v_dur); pos_list[idx] = new PosData(p[1].x, p[1].y, p[1].z, p[2].x, p[2].y, p[2].z, tex_num); updateTexNum(); pnt.x = p[0].x; pnt.y = p[0].y; pnt.z = p[0].z; setNextTime(); } float easeInOutQuad(float t, float b, float c, float d) { t /= (d / 2.0); if (t < 1.0) return (c / 2.0 * t * t + b); t -= 1.0; return (-c / 2.0 * (t * (t - 2.0) - 1.0) + b); } float easeInOutCubic(float t, float b, float c, float d) { t /= (d / 2.0); if ( t < 1.0) return (c/ 2.0 * t * t * t + b); t -= 2.0; return (c / 2.0 * (t * t * t + 2.0) + b); } float easeInOutQuint(float t, float b, float c, float d) { t /= (d / 2.0); if ( t < 1.0) return (c/ 2.0 * t * t * t * t * t + b); t -= 2.0; return (c / 2.0 * (t * t * t * t * t + 2.0) + b); } float easeInOutExpo(float t, float b, float c, float d) { t /= (d / 2.0); if ( t < 1.0) return (c/ 2.0 * pow(2, 10 * (t - 1)) + b); t -= 1.0; return (c / 2.0 * ( -pow(2, -10 * t) + 2.0) + b); } // 一次関数の値を取得 float getLinearValue(float t, float v_start, float v_chg) { return (v_start + (v_chg * t)); } // 道路片のポリゴン座標を得る PolyData getPoly(int idx) { PosData p0 = pos_list[(idx + 1) % pos_list.length]; PosData p1 = pos_list[idx % pos_list.length]; PolyData dt = new PolyData(p0.p0, p0.p1, p1.p1, p1.p0, p1.tex_num); return dt; } // 道路片の中央の線分を得る PVector[] getLinePos(int idx) { PolyData p = getPoly(idx); PVector c_start = new PVector( (p.p[2].x + p.p[3].x) / 2.0, (p.p[2].y + p.p[3].y) / 2.0, (p.p[2].z + p.p[3].z) / 2.0); PVector c_end = new PVector( (p.p[0].x + p.p[1].x) / 2.0, (p.p[0].y + p.p[1].y) / 2.0, (p.p[0].z + p.p[1].z) / 2.0); PVector[] ret = {c_start, c_end}; return ret; } }