mieki256's diary



2016/02/14() [n年前の日記]

#1 [prog][dxruby] スプライン曲線について調べてたり

3次スプライン曲線、とやらが気になってきたのです。Catmull-Romスプラインと比べて結果は違うのかな、どうなのかな、と。

3次スプライン曲線を Ruby + DXRubyで試したり。 :

以下、参考ページ。

_[PHP]3次スプライン曲線を使ったスプライン補間 | PHP Archive
_数値計算

Ruby + DXRuby に移植して動作確認してみたり。

cubic_spline_ss.png
スクリプトを起動後、ウインドウ内でマウスクリックすると、各点の配置が全部変わりますよ、とメモ。

_cubic_spline.rb
# DXRubyで3次スプライン曲線を描画
# xが右方向に増えていくことが前提、らしい?
#
# 参考ページ
#
# [PHP]3次スプライン曲線を使ったスプライン補間 | PHP Archive
# http://php-archive.net/php/cubic-spline/
#
# 数値計算
# http://www.sist.ac.jp/~suganuma/kougi/other_lecture/SE/num/num.htm#7.2

require 'dxruby'

# 3次スプライン補間
class CubicSpline

  # コンストラクタ
  # @param [Array] poslist [x,y]の配列群
  def initialize(poslist)
    init(poslist)
  end

  # 係数を計算して記憶
  # @param [Array] poslist [x,y]の配列群
  def init(poslist)
    @n = poslist.length - 1
    @h = []
    @b = []
    @d = []
    @g = []
    @u = []
    @q = []
    @s = []
    @r = []
    @x = []
    @y = []

    poslist.each do |px, py|
      @x.push(px.to_f)
      @y.push(py.to_f)
    end

    # step 1
    0.step(@n - 1, 1) do |i|
      @h[i] = @x[i + 1] - @x[i]
    end

    1.step(@n - 1, 1) do |i|
      @b[i] = 2.0 * (@h[i] + @h[i - 1])
      @d[i] = 3.0 * ((@y[i+1] - @y[i]) / @h[i] - (@y[i] - @y[i-1]) / @h[i-1])
    end

    # step 2
    @g[1] = @h[1] / @b[1]
    2.step(@n - 2, 1) do |i|
      @g[i] = @h[i] / (@b[i] - @h[i-1] * @g[i-1])
    end

    @u[1] = @d[1] / @b[1]
    2.step(@n - 1, 1) do |i|
      @u[i] = (@d[i] - @h[i-1] * @u[i-1]) / (@b[i] - @h[i-1] * @g[i-1])
    end

    # step 3
    @r[0] = 0.0
    @r[@n] = 0.0
    @r[@n-1] = @u[@n-1]
    (@n - 2).step(1, -1) do |i|
      @r[i] = @u[i] - @g[i] * @r[i+1]
    end

    # step 4
    0.step(@n - 1, 1) do |i|
      @q[i] = (@y[i+1] - @y[i]) / @h[i] - @h[i] * (@r[i+1] + 2.0 * @r[i]) / 3.0
      @s[i] = (@r[i+1] - @r[i]) / (3.0 * @h[i])
    end
  end

  # 補間値の計算
  # @param [Number] x1 補間値を求める値
  # @return [Number] 補間値
  def get_value(x1)
    i = -1.0

    i1 = 1
    while i1 < @n and i < 0.0
      i = i1 - 1 if x1 < @x[i1]
      i1 += 1
    end

    i = @n - 1 if i < 0.0

    xx = x1 - @x[i]
    y1 = @y[i] + xx * (@q[i] + xx * (@r[i] + @s[i] * xx))

    return y1
  end
end


if $0 == __FILE__
  # ----------------------------------------
  # 動作テスト

  # 四角を描画
  # @param [Number] x x座標
  # @param [Number] y y座標
  # @param [Number] sz サイズ
  # @param [Array] col 色。[r, g, b]の配列
  def draw_dot(x, y, sz, col)
    sz /= 2.0
    Window.drawBoxFill(x - sz, y - sz, x + sz, y + sz, col)
  end

  # 点を描画
  # @param [Number] x x座標
  # @param [Number] y y座標
  # @param [Array] col 色。[r, g, b]の配列
  def draw_dot2(x, y, color)
    Window.drawLine(x, y, x, y, color)
  end

  # 座標群を乱数で生成
  # @return [Array] [x0,y0],[x1,y1]...[xn,yn]の配列を生成して返す
  def get_poslist
    poslist = []
    w = Window.width
    h = Window.height
    0.step(w, 50) do |x|
      y = rand(h / 2) + (h / 4)
      poslist.push([x, y])
    end
    return poslist
  end

  fnt = Font.new(12)

  poslist = get_poslist
  spline = CubicSpline.new(poslist)

  # メインループ
  Window.loop do
    break if Input.keyPush?(K_ESCAPE) # ESCキーで終了

    if Input.mousePush?(M_LBUTTON)
      # マウスボタンが押されたら座標群を生成し直し
      poslist = get_poslist
      spline.init(poslist)
    end

    # 制御点を描画
    poslist.each do |x, y|
      draw_dot(x, y, 6, C_RED)
    end

    # 3次スプラインを描画
    end_x1 = poslist.last[0]
    x1 = 0.0
    x1_add = end_x1.to_f / (poslist.length * 16)
    while x1 <= (end_x1 + 0.01)
      y1 = spline.get_value(x1)
      draw_dot2(x1, y1, C_WHITE)
      x1 += x1_add
    end

    Window.drawFont(4, 4, "Please Click", fnt)
  end

end

ベタ移植してるうちに気がついたのだけど。コレってもしかして、x が必ずプラス方向に増えていくことが前提の実装…なのでは…。グラフを描く時はたしかにそのほうが都合がいいわけだけど、自分の場合、ゲームっぽい何かに使えないかと思いながら実験してるので、各点を自由に配置できないとなると、ちょっと使いどころが…。

別のスプライン曲線を試したり。 :

その後、別の実装をしてる例を見かけたり。

_Flashゲーム講座&ASサンプル集【曲線について】

ただ、これは、どんな種類のスプライン曲線なのか記述が無いので、何スプライン曲線なのか分らんのですけれど。とりあえずコレも、Ruby + DXRuby にベタ移植して動作確認してみたり。

spline_ss.png
スクリプト起動後、ウインドウ内でマウスクリックすると、点の位置を順々に指定できますよ、とメモ。

_spline.rb
# DXRubyでスプライン曲線を描画
# 2次スプラインなのか、3次スプラインかなのか不明
#
# 参考ページ
#
# Flashゲーム講座&ASサンプル集【曲線について】
# http://hakuhin.jp/as/curve.html#CURVE_04

require 'dxruby'
require 'pp'

# スプライン補間用クラス
#
# @attr [Array] result スプライン補間した座標群が配列の形で入る
#
class SplineStream

  # x,y座標保持用クラス
  class Vec
    attr_accessor :x
    attr_accessor :y

    def initialize(x, y)
      @x = x.to_f
      @y = y.to_f
    end
  end

  attr_accessor :result

  # コンストラクタ
  # @param [Array] poslist 座標群。一要素が[x,y]になってる配列
  # @param [Number] interpolate 分解度
  def initialize(poslist, interpolate)
    init(poslist, interpolate)
  end

  # 座標群から補間値を生成する
  # @param [Array] poslist 座標群。一要素が[x,y]になってる配列
  # @param [Number] interpolate 分解度
  def init(poslist, interpolate)
    @num = poslist.length
    @l = []
    @aa = []
    @bb = []
    @cc = []

    p = []
    poslist.each do |d|
      p.push(Vec.new(d[0], d[1]))
    end

    0.step(@num - 2, 1) do |i|
      p0 = p[i]
      p1 = p[i+1]
      @l[i] = Math.sqrt((p0.x - p1.x) * (p0.x - p1.x) + (p0.y - p1.y) * (p0.y - p1.y))
    end

    @aa[0] = [0.0, 1.0, 0.5]
    @bb[0] = {
      :x => (3.0 / (2.0 * @l[0])) * (p[1].x - p[0].x),
      :y => (3.0 / (2.0 * @l[0])) * (p[1].y - p[0].y)
    }

    @aa[@num - 1] = [1.0, 2.0, 0.0]
    @bb[@num - 1] = {
      :x => (3.0 / @l[@num - 2]) * (p[@num - 1].x - p[@num - 2].x),
      :y => (3.0 / @l[@num - 2]) * (p[@num - 1].y - p[@num - 2].y)
    }

    1.step(@num - 2, 1) do |i|
      a = @l[i - 1]
      b = @l[i]
      @aa[i] = [b, 2.0 * (b + a), a]
      @bb[i] = {
        :x => (3.0 * (a * a * (p[i + 1].x - p[i].x)) + 3.0 * b * b * (p[i].x - p[i - 1].x)) / (b * a),
        :y => (3.0 * (a * a * (p[i + 1].y - p[i].y)) + 3.0 * b * b * (p[i].y - p[i - 1].y)) / (b * a)
      }
    end

    1.step(@num - 1, 1) do |i|
      d = @aa[i-1][1] / @aa[i][0]
      @aa[i] = [0, @aa[i][1] * d - @aa[i-1][2], @aa[i][2] * d]
      @bb[i][:x] = @bb[i][:x] * d - @bb[i - 1][:x]
      @bb[i][:y] = @bb[i][:y] * d - @bb[i - 1][:y]

      @aa[i][2] /= @aa[i][1]
      @bb[i][:x] /= @aa[i][1]
      @bb[i][:y] /= @aa[i][1]
      @aa[i][1] = 1
    end

    @cc[@num - 1] = {
      :x => @bb[@num-1][:x],
      :y => @bb[@num-1][:y]
    }

    (@num - 1).step(1, -1) do |j|
      @cc[j - 1] = {
        :x => @bb[j - 1][:x] - @aa[j - 1][2] * @cc[j][:x],
        :y => @bb[j - 1][:y] - @aa[j - 1][2] * @cc[j][:y]
      }
    end

    outdata = []
    count = 0
    0.step(@num - 2, 1) do |i|
      a = @l[i]
      v00 = p[i].x
      v01 = @cc[i][:x]
      v02 = (p[i + 1].x - p[i].x) * 3.0 / (a * a) - (@cc[i + 1][:x] + 2 * @cc[i][:x]) / a
      v03 = (p[i + 1].x - p[i].x) * (-2.0 / (a * a * a)) + (@cc[i + 1][:x] + @cc[i][:x]) * (1.0 / (a * a))

      v10 = p[i].y
      v11 = @cc[i][:y]
      v12 = (p[i + 1].y - p[i].y) * 3.0 / (a * a) - (@cc[i + 1][:y] + 2 * @cc[i][:y]) / a
      v13 = (p[i + 1].y - p[i].y) * (-2.0 / (a * a * a)) + (@cc[i + 1][:y] + @cc[i][:y]) * (1.0 / (a * a))

      t = 0.0
      t_spd = a.to_f / interpolate.to_f
      0.step(interpolate - 1, 1) do |j|
        tx = ((v03 * t + v02) * t + v01) * t + v00
        ty = ((v13 * t + v12) * t + v11) * t + v10
        outdata.push([tx, ty])
        t += t_spd
      end
    end

    outdata.push([p[@num-1].x, p[@num-1].y])

    @result = outdata
  end
end

if $0 == __FILE__
  # ----------------------------------------
  # 動作確認

  Window.caption = "Spline Curve"

  # 四角(塗り潰し)を描画
  def draw_dot(x, y, sz, col)
    sz = sz / 2.0
    Window.drawBoxFill(x - sz, y - sz, x + sz, y + sz, col)
  end

  # 点を描画
  def draw_dot2(x, y, col)
    Window.drawLine(x, y, x, y, col)
  end

  # 四角(線のみ)を描画
  def draw_box(x, y, sz, col)
    sz = sz / 2.0
    x1, y1 = x - sz, y - sz
    x2, y2 = x + sz, y + sz
    Window.drawLine(x1, y1, x2, y1, col)
    Window.drawLine(x1, y2, x2, y2, col)
    Window.drawLine(x1, y1, x1, y2, col)
    Window.drawLine(x2, y1, x2, y2, col)
  end

  fnt = Font.new(12)

  # 1区間を何分割するか
  interpolate = 16

  # 初期座標群
  poslist = [
    [50, 200],
    [150, 200],
    [250, 100],
    [350, 400],
    [450, 200],
    [550, 100],
  ]

  spline = SplineStream.new(poslist, interpolate)
  mode = 0

  Window.loop do
    break if Input.keyPush?(K_ESCAPE)

    if Input.mousePush?(M_LBUTTON)
      # マウスボタンがクリックされたら座標変更
      poslist[mode] = [Input.mousePosX.to_f, Input.mousePosY.to_f]
      mode += 1
      mode = 0 if mode >= poslist.length

      # スプライン曲線を作り直し
      spline.init(poslist, interpolate)
    end

    # 制御点を描画
    poslist.each_with_index do |d, i|
      x, y = d
      draw_dot(x, y, 6, C_RED)
      draw_box(x, y, 12, C_CYAN) if i == mode
    end

    # スプライン曲線を描画
    spline.result.each do |d|
      x, y = d
      draw_dot2(x, y, C_WHITE)
    end

    Window.drawFont(4, 4, "Please Click", fnt)
  end
end

これは3次スプライン曲線なのだろうか…。なんだか違う気がする…。Catmull-Rom と形が似てる気もするし…。

スプライン曲線では道路の自動生成は難しいかも。 :

道路の自動生成に使えないかと、それぞれの曲線描画を試しているのだけど。もしかすると、どれを使っても上手くいかないのではないか、という気がしてきたり。

おそらく、道路の自動生成は、自機の位置がある程度進んだら、新しい制御点を追加、かつ、一番古い手前の制御点を削除して、曲線を再作成、という感じの処理になるのかなと想像しているけど。今まで試したアレコレは、制御点が増えたり減ったりすると、曲線の形が変わってしまうように見えるわけで。つまり、道路用の制御点が増えたり減ったりするたびに、画面の中に見えている道路の形がパカッパカッと潔く変わってしまうのではないか、と。

違う方法を考えたほうがいいのかもしれない…。

#2 [windows] Windows10にアップグレードしたらWebサーバが使えなくなってしまった

普段この日記ページをローカルでプレビューする時は、 _04WebServer というWebサーバを起動して確認しているのですけど。

Windows7 から Windows10 にアップグレードして、そこで初めて 04WebServer を起動してみたら、「通信ポートのオープンに失敗しました」とエラーメッセージが表示されて。何故。

色々ググってみたら、どうも Windows10 からは IIS が有効になっていて、80番ポートを既に使われちゃってるらしくて。

_XAMPPがWindows10で動かない時の対処法 | ブログが書けたよ!
_Windows10でIISを(ホームページ)有効化する設定
_Windows10にアップグレードしたらApache起動しなくなったので対策に乗り出したっていう話 | Thought is free

てなわけで、スタートボタン横の検索窓に「Windows機能の有効化または無効化」と打ち込んで起動して、「インターネット インフォメーション サービス」のチェックを外して、IISを無効化してみたり。OS再起動後、04WebServerが使えるようになった。

しかしコレ、Windows10 は IIS を一体何に使っているのだろう…。無効にしないほうがいいのかな…。

#3 [anime][neta] ファフナーの、遠い親戚、おそ松さん

思考メモ。

「蒼穹のファフナー EXODUS」というアニメのラストのあたりを先日視聴したのですけど。なんだか凄いことが起きてるらしいけど前のシリーズは見てないから設定が分らなくて何が起きてるのかさっぱりだな参ったなあ、などと思いながらぼんやり眺めていたのです。

設定はともかく、個人的に一番辛かったのは、出てくる少年少女キャラの顔が皆同じで全然区別がつかない点。髪型と声は違うけど、目鼻のデザインや配置バランスが同じなので、誰が誰やら。 *1

実際の設定がどうなってるかは分らんのですが、これはおそらくアレだなと。全員がクローンという設定なのだろうと自分は勝手に推測したのです。

何せ、人類が敵にボコボコにされてる世界設定だから、若い世代がごっそり死んでて、仕方なくクローンで増やして人口を調整してるに違いないと。

あるいは、巨大ロボットを動かせる資質を持った個体がそうそう自然に生まれてこないので、クローンでパイロットを増やしてるんだろうと。要するに EVAの綾波みたいなものではないか。などと思いながら見ていたわけです。や、実際の設定がどうなのかは知らんのですけど。そういう設定と考えれば、顔が皆同じなのは納得できるぞと。

しかし、クローン設定って、面白いことは面白いけど、真面目に映像化すると困ったことになるなと。ついさっき誰かが死んだと思ったら、その数カット後にそっくりさんが「うおー」「クソォ」と叫んで戦ってるわけで。「アレ? コイツ、さっき死んでなかったっけ?」みたいな。そんな映像見せられたら、作品に没入とかちょっとハードル高いよなと。

そこでふと、「おそ松さん」を思い出したわけですよ。…と言っても、「おそ松さん」って自分は一度も見れてないんですけど。 *2 それはさておいて、アレはどうやってそのへん解決してるのだろうかと。

「おそ松さん」って、たしか放送された最初の頃は、「六つ子に個性を与えるとは愚行である」「彼等のアイデンティティが崩壊するではないか」などと叩かれてた記憶があるのですけど、今となっては「コレは○松」と女性視聴者が一発で見分けてるらしいじゃないですか。おそらく、個性を強調する方針は正しかったのだと歴史(?)が証明してくれたのだ、とか思ってたりするのですが。

その、おそ松さんのキャラデザ・キャラ設定メソッドを、クローン設定モノに流用すれば状況を改善できたりしないか、と。

と言っても、おそ松さんは結構ダイナミックなキャラデザだから、そのメソッドが使えるのかなあ…。

仮に、ファフナーの少年少女達の顔がおそ松さんみたいな顔だったら、これは一体どうなっちゃうんだろう…。その場合ファフナーは、続編が作れるぐらいにちゃんと人気が出たのだろうか…。いやー、どうかなー。どうなんだー。

オチは無いです。思考メモというか妄想メモです。

キャラデザが一人ってのがおかしい気もする。 :

クローン設定云々はおいといて。フツーの設定のアニメでも、キャラの区別がつかないことって、たまにあるよなと。

昔のディズニーアニメは、キャラ一人につき、キャラデザ、兼、担当アニメーターがついた状態で作ってたらしいのですけど。どうして日本は、そうならなかったのかなと…。昔のディズニー方式なら、キャラの区別がつかない、みたいな話は無かったんじゃないかと思ったりもするわけで。

せめて、最初のダンクーガみたいに、最低限キャラデザの人だけでも6人ぐらい居ます、みたいなスタッフ構成もアリじゃないかと思ったりするんですけど。アレがその後もあまり続いてないのは、やっぱり何か問題があるんですかね。

漫画の影響、なのかなあ。漫画の延長として、日本のアニメは存在してるし。漫画家さんはえてして一人で色んなキャラを描いてしまうから、アニメのキャラデザも一人が理想、みたいなことになってるのかしらん。そのあたりは、手塚治虫先生が偉大過ぎたのかなあ…。あの人、一人で色んなキャラを描いちゃうし。もっとも、スターシステムという名の使い回しは必ずしてるような気もするけど。

これがもし、漫画を描く時も、キャラ一人つき漫画家一人がついて作画するのが当たり前、みたいなことになってたら、アニメのキャラデザもそのように変わったのだろうか。

このあたり、ベテランアニメーター、大塚康生さんの著書、「作画汗まみれ」の中でも、若い頃の大塚さんが若干悩んでた記述があったような記憶も。あの時代に、日本風のアニメの作り方・キャラデザの仕方が決まっちゃったのでしょうけど…。

*1: 一応、少年少女パイロット達は、ヘルメットを被らないでコクピットに乗ってたりするので…。見分けられるように、あえてヘルメットを被らせてないんだろう、一応工夫はしてるっぽい、とは思いましたが、それでも区別がつかない…。
*2: ただでさえ、BS11とBS-TBSがアニメを放送してぶつけ合ってる時間帯に、狙ったかのようにBSジャパンが「おそ松さん」までぶつけてきたので、見れないんですよね…。曜日も、時間帯も、他にいくらでも空いてるのに、なんでわざわざぶつけてくるの? 関係者は馬鹿なの? って気分ですよ。どうして曜日や時間帯をずらさないのかなあ。BSジャパンは「ワンパンマン」も変な時間帯に流しちゃってたので、録画できなかったし…。

#4 [nitijyou] 体調は少し良くなってきた

おそらくは _新ルル - A錠 を飲んだら、随分楽になってきた。鼻はつまり気味だけど、咳はほとんど治まったし。

以上、1 日分です。

過去ログ表示

Prev - 2016/02 - Next
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29

カテゴリで表示

検索機能は Namazu for hns で提供されています。(詳細指定/ヘルプ


注意: 現在使用の日記自動生成システムは Version 2.19.6 です。
公開されている日記自動生成システムは Version 2.19.5 です。

Powered by hns-2.19.6, HyperNikkiSystem Project