画像を背面から前面に半円を描くように移動させる

タグの編集
投稿者 くらうど  (社会人) 投稿日時 2010/5/24 10:30:41
2つの画像が前面から背面になめらかな動きで入れ替わるように
したいと考えてますが、これはどのようなアルゴリズムで実現されて
いるのでしょうか
VB2010でも可能でしょうか
投稿者 るきお  (社会人) 投稿日時 2010/5/24 13:01:06
こんにちは。

「前面」と「背面」がよくわからないです。
何の前面・背面でしょうか?

1.擬似的な3Dを考えて遠くにあるもの(背面)と近くにあるもの(前面)のイメージですか?
2.それとも、あくまでも2Dの世界でどちらが手前に表示されているかという意味での前面・背面でしょうか?
3.または、なにかをはさんで前面・背面になっているでしょうか?

ここで挙げた1、2のパターンはVB2010で処理可能です。
3のパターンははさんでいるもの次第です。

それから、アプリケーションの種類は「Windows フォーム アプリケーション」でしょうか?
投稿者 くらうど  (社会人) 投稿日時 2010/5/24 17:58:51
>「前面」と「背面」がよくわからないです。
>何の前面・背面でしょうか?
説明が不足していてすみません。提示していただいた2です

2.それとも、あくまでも2Dの世界でどちらが手前に表示されているかという意味での前面・背面でしょうか?



>それから、アプリケーションの種類は「Windows フォーム アプリケーション」でしょうか? 
 
そうです

半円を描くような動きはどのようにするのですか?
  
投稿者 葉月  (社会人) 投稿日時 2010/5/24 19:27:05
>前面から背面になめらかな動きで入れ替わるように
時々、ゲームをやってて見かけることがありますね。
.NETで試したことはありませんが、こんな感じにやるんだと思います。

画像を2枚用意して――

①1枚目の画像を普通に表示、2枚目は視覚できない状態まで透過させます。
②1枚目の画像を少しずつ透過、2枚目は逆に見えるように透過を解いていきます。
③時間が経つうちに、1枚目と2枚目が入れ替わっているように見えます。

Javaで似たようなサンプルを書いたことはありますが、.NETはよく知りません。
でも、原理は同じだと思います。
提示URLのサンプルを見てください。


>半円を描くような動きはどのようにするのですか?
計算によって、画像の座標や角度を変える方法しかわかりませんね。
簡単なやり方があるかも知れないので、他の回答者の返答を待ってください。
投稿者 葉流  (社会人) 投稿日時 2010/5/24 21:42:01
ハンドルがまぎわらしくて申し訳ないですが、上の人とは別です。
本題ですが、VB.Netには画像を透過させる機能は無いと思います。
しかし、Formは透過させられますから、Formに画像を貼ればOKでしょう。
それは、Me.Opacity プロパティです。主Formの画像の上に副Formをかぶせて。
しかし透過と半円に移動させる関係の意味が分かりません。
単に画像を動かすだけなら、Timerコントロールで画像のLocation座標を変えれば。
微小角度の、画像の回転表示も、多分VB.Netでは、普通には出来ないと思いますが。
投稿者 葉流  (社会人) 投稿日時 2010/5/24 21:55:46
補足です。アニメGIFを使うか、または同じように多くの連続画像を用意して置いて、
それを連続的に貼り付けるか、DrawImageするか、この方が現実的な気もします。
投稿者 るきお  (社会人) 投稿日時 2010/5/24 22:53:00
こんにちは。

2つの画像の位置関係がやっぱりわからないです。

一応仮のもので作ろうと思ったのですが、数学の知識がさびついていてうまい具体に座標が計算できませんでした。とりあえず、座標はずれますが孤上にPictureboxが移動する例です。
PictreBox2個とButton1個をフォームに貼りつけて試してみてください。

  
Public Class Form1

    Dim center As Point
    Dim radius As Double

    Private Sub Form1_Load(ByVal sender As System.ObjectByVal e As System.EventArgs) Handles MyBase.Load
        Timer1.Interval = 100
    End Sub
    Private Sub Button1_Click(ByVal sender As System.ObjectByVal e As System.EventArgs) Handles Button1.Click
        ImageCircle(Me.RectangleToScreen(PictureBox1.DisplayRectangle), Me.RectangleToScreen(PictureBox2.DisplayRectangle))
        Timer1.Enabled = True
    End Sub

    Private Sub ImageCircle(ByVal rect1 As Rectangle, ByVal rect2 As Rectangle)

        center = ((rect2.Location) - (rect1.Location))
        center.X /= 2
        center.Y /= 2

        radius = CalcDistance(rect1.Location, center)
        startDeg = Math.Tan((center.Y - rect1.Top) / (center.X - rect1.Left))

    End Sub

    Private Function CalcDistance(ByVal pos1 As Point, ByVal pos2 As Point) As Double

        Dim Kou As Double = pos2.X - pos1.X
        Dim Ko As Double = pos2.Y - pos1.Y
        Dim Gen As Double

        Gen = Math.Sqrt(Kou ^ 2 + Ko ^ 2)

        Return Gen

    End Function

    Dim tick As Integer
    Private Sub Timer1_Tick(ByVal sender As System.ObjectByVal e As System.EventArgs) Handles Timer1.Tick

        tick += 1
        PictureBox1.Location = ClacPoint(tick)

    End Sub

    Dim startDeg As Double

    Const MoveUnit As Double = (Math.PI * 2) / 360

    Private Function ClacPoint(ByVal tick As IntegerAs Point

        Dim deg As Double = startDeg - (tick * MoveUnit)
        Dim x As Integer
        Dim y As Integer

        x = radius * (Math.Cos(deg)) + center.X
        y = radius * (Math.Sin(deg)) + center.Y

        Me.Text = deg & "(" & x & "," & y & ")"
        Return New Point(x, y)

    End Function

    
End Class


たぶん、象限ごとに座標計算をわけなければいけないのか、Y軸が下方向がプラスという感覚がおかしくなっているのか、ともあれ、この手のプログラムの問題のほとんどは数学上の座標計算であって、プログラムの機能的には特に難しくありません。

なお、この場合の座標計算は私の仮定上では以下の問題の解に帰着します。

問い
XY座標平面上に長方形Rect1と長方形Rect2がある。
ただし、この座標平面ではY軸は下側がプラスで上側がマイナスである。
Rect1の左上の頂点をPos1、Rect2の左上の頂点をPos2とするとき、線分Pos1・Pos2を直径とする円を考える。
その円周上を動点がPos1からPos2までt秒かけて移動するとき、s秒後のこの動点の座標を求めよ。

この答えがだせればプログラムも完成すると思います。
くらうどさん、解けますか?
投稿者 るきお  (社会人) 投稿日時 2010/5/24 22:54:37
すいません。書き間違いました。
(いつも書き忘れて連投になってしまいます…)

>PictreBox2個とButton1個をフォームに貼りつけて試してみてください。
これに加えてTimerも1つ配置してください。
投稿者 葉流  (社会人) 投稿日時 2010/5/24 23:39:24
> 微小角度の、画像の回転表示も、多分VB.Netでは、普通には出来ないと思いますが

訂正します。DrawImageでは、回転表示もできるようです。失礼しました。

投稿者 葉月  (社会人) 投稿日時 2010/5/25 01:07:59
こんばんは。
ちょっとサンプルを作ってみましたが、想定した動きにならないですね。
並列処理で試そうと思ったら、やり方忘れてますし(汗)
過去ログ除いて、過去の自分に教えてもらいに行ってきます(笑)
形になったら提示します。

>VB.Netには画像を透過させる機能は無いと思います。
お気づきかも知れませんが、画像の透過もできますよ。
http://msdn.microsoft.com/ja-jp/library/system.drawing.imaging.colormatrix%28VS.80%29.aspx

詳しくは前回の私の提示URLをご覧ください。
るきおさんが作ったサンプルで、透過させるのに必要なアルファ値をいじっています。
関連URLに、他のやり方も載せておきます。

■追伸
デリゲートやポインター操作など、Javaにできない機能はありますが逆は知らないです。
ただ、JavaはLinuxなどで動かせるメリットがあります。
Linuxでやった場合のEclipseの設定もそれほど複雑じゃないです。
投稿者 葉月  (社会人) 投稿日時 2010/5/25 01:36:00
もう深夜時間ですね。投稿して気付きました。
時間が遅いので、中途半端なコードを載せます。
今日の夜に気力があれば、また取り組みます。

マイピクチャーにsample1.bmpとsample2.bmpを置いてください。
ピクチャーボックスを一個用意し、
Formに張り付けてDockしてください。
時間がないので中途半端な出来ですが一応動きます。
コメントは殴り書きなので、変なこと書いてるかも知れません。

>サンプル
Public Class Form1

    ''' <summary> 
    ''' マイピクチャーのパス 
    ''' </summary> 
    ''' <returns>マイピクチャーのパス</returns> 
    Private ReadOnly Property GetPicturePath()
        Get
            Dim strImgPath As String
            strImgPath = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures)

            Return strImgPath
        End Get
    End Property


    Private Sub PictureBox1_Click(ByVal sender As System.ObjectByVal e As System.EventArgs) Handles PictureBox1.Click

        ' グラフィックス 
        Dim g As Graphics = PictureBox1.CreateGraphics()

        ' イメージ 
        Dim strImgPath As String = String.Concat(GetPicturePath, "\sample.bmp")

        ' イメージの読み込み 
        Dim img As Image = Image.FromFile(strImgPath)

        ' 徐々に透過 
        Dim j As Integer = 1

        For i = 9 To 0 Step -1
            ImageChange(g, img, i * 0.1F)
            System.Threading.Thread.Sleep(300)
            ImageChange(g, j * 0.1F)
            System.Threading.Thread.Sleep(300)
            j += 1
        Next

        ' リソース解放処理 
        img.Dispose()
        g.Dispose()
    End Sub


    ''' <summary> 
    ''' (ポリモフィズム)イメージを切り替える。 
    ''' </summary> 
    ''' <param name="g">グラフィックスメソッド</param> 
    ''' <param name="alpha">アルファ値</param> 
    Public Shared Sub ImageChange(ByVal g As Graphics, ByVal alpha As Single)
        ' パス 
        Dim strImgPath As String = Form1.GetPicturePath + "\sample2.bmp"
        ' 読み込むイメージ 
        Dim img As Image = Image.FromFile(strImgPath)
        ImageChange(g, img, alpha)
    End Sub

    ''' <summary> 
    ''' イメージを切り替える。 
    ''' </summary> 
    ''' <param name="g">グラフィックスメソッド</param> 
    ''' <param name="img">イメージ</param> 
    ''' <param name="alpha">アルファ値</param> 
    ''' <remarks></remarks> 
    Public Shared Sub ImageChange(ByVal g As Graphics, _
            ByVal img As Image, ByVal alpha As Single)

        ' 読み込む画像 
        Dim back As New Bitmap(img.Width, img.Height)

        ' グラフィックス 
        Dim bg As Graphics = Graphics.FromImage(back)

        ' 透過に必要な値 
        Dim cm As New System.Drawing.Imaging.ColorMatrix

        cm.Matrix00 = 1
        cm.Matrix11 = 1
        cm.Matrix22 = 1
        cm.Matrix33 = alpha
        cm.Matrix44 = 1

        ' cmの値をカラーマトリックスとして設定 
        Dim attr As New System.Drawing.Imaging.ImageAttributes
        attr.SetColorMatrix(cm)

        bg.DrawImage(img, New Rectangle(0, 0, img.Width, img.Height), _
                     0, 0, img.Width, img.Height, GraphicsUnit.Pixel, attr)

        g.DrawImage(back, 0, 0)

        ' リソース解放 
        bg.Dispose()
        back.Dispose()
    End Sub
End Class

投稿者 葉月  (社会人) 投稿日時 2010/5/25 01:38:23
間違えました。

画像は――
sample.bmpとsample2.bmpを用意する必要があります。

投稿者 (削除されました)  () 投稿日時 2010/5/25 10:13:32
(削除されました)
投稿者 くらうど  (社会人) 投稿日時 2010/5/25 10:15:28
うまく説明できないのもかかわらずたくさんのアドバイスいただき感謝しております

http://www.harikonotora.net/main.html
作りたいものは上のサイトのアニメのようなイメージです
(こちらのサイトはVBとは関係がなく、なにかと色々と問題もあるようですが、それらは無視してください)

教えていただきましたことは、これから試してみたいと思っています。

 
 

投稿者 魔界の仮面弁士  (社会人) 投稿日時 2010/5/25 14:38:51
> 作りたいものは上のサイトのアニメのようなイメージです
amazon の「くるくるウィジェット」の部分でしょうか?
http://hyper-text.org/archives/2008/04/amazon_kurukuru_widget.shtml

実装するとすれば、Timer を使って画像のサイズと位置を調整していくことに
なると思います。必要な位置等は、三角関数計算で求めてください。
投稿者 葉流  (社会人) 投稿日時 2010/5/25 18:36:07
> http://www.harikonotora.net/main.html
なるほど、百聞は一軒にしかず、ですな。あれと同等に行おうとすれば、3D仮想空間を想定し、
個々の仮想板を3D的に回転させ、透視変換して板の2D座標を求めれば良く、視点からの距離
に応じて板のサイズを変えれば良い。出来なくはないが、幾らか面倒でもありますね。視点から
の距離の、遠い順に画像表示すれば陰面処理も行われます。徐々に半透明にする必要は無く、
画像回転の必要も無く、必要なのは陰面処理ですね。詳しく無いですが、IEとFlashの世界かな?
VB.Netなどのアプリでも出来なくはないでしょうが、苦労の割には報われない予感が...
投稿者 葉月  (社会人) 投稿日時 2010/5/25 19:38:40
こんばんは。

リンク先は、Gifアニメのような気が(汗)
ファイル名:Character1.gifですよね?
イメージは、パラパラアニメや紙芝居なのでプログラミング
の世界からは外れます。
詳しくはGifアニメでググってください。

.NETでGifアニメのようにしたいだけなら、静止画をパラパラ
漫画のように連結するだけです。
ただ、Gifの規格に合わせて作るとなると面倒です。
その場合は、Bitmapのフォーマットから勉強することをお勧
めします。

>Gifのフォーマット
http://www.tohoho-web.com/wwwgif.htm

サンプルの話に戻ります。
ちらつきが気になったので、改良しようと思いましたが止め
ときます。
最後に修正版を載せます。

コメントの明らかな間違えを修正済みです。
Sleepの値をいじったら前よりはよくなりました。
サンプルを読める方や試した方はわかると思いますが、画像の
入れ替わりは問題なくできています。


>サンプル(修正版)
Public Class Form1

#Region "プロパティ"

    ''' <summary> 
    ''' マイピクチャーのパス 
    ''' </summary> 
    ''' <returns>パス</returns> 
    Private ReadOnly Property GetPicturePath()
        Get
            Dim strImgPath As String
            strImgPath = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures)

            Return strImgPath
        End Get
    End Property

#End Region

    Private Sub PictureBox1_Click(ByVal sender As System.ObjectByVal e As System.EventArgs) Handles PictureBox1.Click

        ' グラフィックス 
        Dim g As Graphics = PictureBox1.CreateGraphics()

        ' イメージのパス 
        Dim strImgPath As String = String.Concat(GetPicturePath, "\sample.bmp")

        ' イメージの読み込み 
        Dim img As Image = Image.FromFile(strImgPath)

        ' 徐々に透過を解く 
        Dim j As Integer = 1

        For i = 9 To 0 Step -1
            ImageChange(g, img, i * 0.1F)
            System.Threading.Thread.Sleep(200)
            ImageChange(g, j * 0.1F)
            System.Threading.Thread.Sleep(500)
            j += 1
        Next

        ' リソース解放処理 
        img.Dispose()
        g.Dispose()
    End Sub


    ''' <summary> 
    ''' (ポリモフィズム)イメージを切り替える。 
    ''' </summary> 
    ''' <param name="g">グラフィックスメソッド</param> 
    ''' <param name="alpha">アルファ値</param> 
    Private Sub ImageChange(ByVal g As Graphics, ByVal alpha As Single)
        ' イメージのパス 
        Dim strImgPath As String = Me.GetPicturePath + "\sample2.bmp"
        ' 読み込むイメージ 
        Dim img As Image = Image.FromFile(strImgPath)
        ImageChange(g, img, alpha)
    End Sub

    ''' <summary> 
    ''' イメージを切り替える。 
    ''' </summary> 
    ''' <param name="g">グラフィックス</param> 
    ''' <param name="img">イメージ</param> 
    ''' <param name="alpha">アルファ値</param> 
    ''' <remarks></remarks> 
    Private Sub ImageChange(ByVal g As Graphics, _
            ByVal img As Image, ByVal alpha As Single)

        ' 読み込む画像 
        Dim back As New Bitmap(img.Width, img.Height)

        ' グラフィックス 
        Dim bg As Graphics = Graphics.FromImage(back)

        ' 透過で変更する値 
        Dim cm As New System.Drawing.Imaging.ColorMatrix
        cm.Matrix00 = 1
        cm.Matrix11 = 1
        cm.Matrix22 = 1
        cm.Matrix33 = alpha
        cm.Matrix44 = 1

        ' cmの値をカラーマトリックスとして設定 
        Dim attr As New System.Drawing.Imaging.ImageAttributes
        attr.SetColorMatrix(cm)

        bg.DrawImage(img, New Rectangle(0, 0, img.Width, img.Height), _
                     0, 0, img.Width, img.Height, GraphicsUnit.Pixel, attr)

        g.DrawImage(back, 0, 0)

        ' リソース解放 
        bg.Dispose()
        back.Dispose()
    End Sub


End Class

投稿者 魔界の仮面弁士  (社会人) 投稿日時 2010/5/25 21:22:47
葉月さん宛:

> リンク先は、Gifアニメのような気が(汗)
> ファイル名:Character1.gifですよね?
そちらではなく、その下の円筒方向に周回する Amazon の売れ筋 DVD を表示している
ガジェットの事であろうかと思います。
(広告ブロッカーの類を使っている場合は、Off にしないと見えないかも)

Flash で似たような実装を行っている物もありますね。
http://dispersalblog.blog90.fc2.com/blog-entry-173.html
投稿者 葉月  (社会人) 投稿日時 2010/5/25 21:56:31
魔界の仮面弁士さん、フォローありがとうございます。
マウスカーソルを画像に合わせて、
現象を確認しました。

他の皆さん申し訳ありません。
Gifの話は、関連がありませんのでよろしくお願いします。
投稿者 (削除されました)  () 投稿日時 2010/5/27 20:44:23
(削除されました)