背景を歪ませる方法

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
忍ノ一字

背景を歪ませる方法

#1

投稿記事 by 忍ノ一字 » 7年前

どなたかこの動画の背景の歪みってどうやって描画しているかわかりますか?
動画とにらめっこしながらずっと考えているんですがさっぱりわかりません。
サインカーブを使ってるっぽいけど…


jay
記事: 314
登録日時: 9年前
住所: 大阪市
連絡を取る:

Re: 背景を歪ませる方法

#2

投稿記事 by jay » 7年前

まぁ、内部でどんなことやってるのかなんて分かりませんが

とりあえず実装する方法として僕が思いついたのは

①、元からああいうアニメーションを用意しておいてループ再生している

②、シェーダプログラミングのテクニックを使っている


のどちらかですね
どちらでもアレに近いものは実装可能だと思います
♪僕たちは まだ森の中 抜け出そう 陽のあたる場所へ

忍ノ一字

Re: 背景を歪ませる方法

#3

投稿記事 by 忍ノ一字 » 7年前

返信ありがとうございます。

>①、元からああいうアニメーションを用意しておいてループ再生している

元のテクスチャが一枚絵なのでそれはないですね。

>②、シェーダプログラミングのテクニックを使っている

スーパーファミコンですからシェーダなんてものはない(はず)のでそれもないですね。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 9年前
住所: 東海地方
連絡を取る:

Re: 背景を歪ませる方法

#4

投稿記事 by softya(ソフト屋) » 7年前

Romancing SaGa3だとスーパーファミコンですから、ラスター処理を行っていると思います。
ドラクエの旅の扉などで有名なラスタースクロールの応用ですね、

「ラスタースクロール - Wikipedia」
http://ja.wikipedia.org/wiki/%E3%83%A9% ... C%E3%83%AB

使っていると思われる技術。

・ラスター毎の拡縮。これをsinで揺らしています。
単純のなのだとF-ZEROの道路とかFFの飛行船のシーンとか。
https://www.youtube.com/watch?v=_srSfeqNCU0
背景がラスター拡縮で奥に倒れている感じをだしています。

・上下の引き伸ばすもラスターの応用ですが、これもsinで揺らしています。
同じラインを何度も描画することで引き伸ばして見せています。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 9年前
住所: 東海地方
連絡を取る:

Re: 背景を歪ませる方法

#5

投稿記事 by softya(ソフト屋) » 7年前

DXライブラリのサンプル。ラスター横だけ拡縮。

元の画像
moon.png
moon.png (6.18 KiB) 閲覧数: 1179 回

コード:

#include "DxLib.h"
#include <math.h>

int Key[256]; // キーが押されているフレーム数を格納する

// キーの入力状態を更新する
int gpUpdateKey() {
	char tmpKey[256]; // 現在のキーの入力状態を格納する
	GetHitKeyStateAll( tmpKey ); // 全てのキーの入力状態を得る
	for( int i = 0; i < 256; i++ ) {
		if( tmpKey[i] != 0 ) { // i番のキーコードに対応するキーが押されていたら
			Key[i]++;     // 加算
		} else {              // 押されていなければ
			Key[i] = 0;   // 0にする
		}
	}
	return 0;
}

#define PI 3.14159265358979323846
#define SIZEX 640
#define SIZEY 480

int WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR, int ) {
	ChangeWindowMode( TRUE ), DxLib_Init(), SetDrawScreen( DX_SCREEN_BACK ); //ウィンドウモード変更と初期化と裏画面設定

	int Handle = LoadGraph( "moon.png" );
	int pos = 0;
	
	// while(裏画面を表画面に反映, メッセージ処理, 画面クリア, キーの更新)
	while( ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0 && gpUpdateKey() == 0 ) {
		
		//	横sin拡縮ラスター
		const int height=2;
		for( int y=0 ; y<SIZEY ; y+=height ) {
			double rate = 1.0 + 0.7 * sin( (double)(y+pos) * PI / 90.0 );//ラジアン変換と拡大率への変換
			//	スライスして描画する
			int x1 = (SIZEX / 2) - ( (double)(SIZEX / 2) * rate );
			int x2 = (SIZEX / 2) + ( (double)(SIZEX / 2) * rate );
			DrawRectExtendGraph( x1,y,x2,y+height, 0,y,SIZEX,height,Handle,TRUE);
		}
		
		//	位置をずらします。
		pos++;
	}

	DxLib_End(); // DXライブラリ終了処理
	return 0;
}
実行結果:
ラスター.png
ラスター.png (37.42 KiB) 閲覧数: 1179 回
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

忍ノ一字

Re: 背景を歪ませる方法

#6

投稿記事 by 忍ノ一字 » 7年前

サンプルコードまで添付して頂いてありがとうございます!
自分も初めはサインカーブで引き伸ばして描画しているのかと思いましたが、
よく見てみると、上下が反転しているところがあるんですよね。

サインカーブ一周期毎に上下反転させるとこんな感じになるのかな?

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 9年前
住所: 東海地方
連絡を取る:

Re: 背景を歪ませる方法

#7

投稿記事 by softya(ソフト屋) » 7年前

縦も入れてみました。調整が不十分ですが、調整していけばあんな感じになるかなと。

コード:

#include "DxLib.h"
#include <math.h>

int Key[256]; // キーが押されているフレーム数を格納する

// キーの入力状態を更新する
int gpUpdateKey() {
	char tmpKey[256]; // 現在のキーの入力状態を格納する
	GetHitKeyStateAll( tmpKey ); // 全てのキーの入力状態を得る
	for( int i = 0; i < 256; i++ ) {
		if( tmpKey[i] != 0 ) { // i番のキーコードに対応するキーが押されていたら
			Key[i]++;     // 加算
		} else {              // 押されていなければ
			Key[i] = 0;   // 0にする
		}
	}
	return 0;
}


#define PI 3.14159265358979323846
#define SIZEX 640
#define SIZEY 480

int WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR, int ) {
	ChangeWindowMode( TRUE ), DxLib_Init(), SetDrawScreen( DX_SCREEN_BACK ); //ウィンドウモード変更と初期化と裏画面設定

	int Handle = LoadGraph( "moon.png" );
	int pos = 0;
	double wave = 0;
	
	// while(裏画面を表画面に反映, メッセージ処理, 画面クリア, キーの更新)
	while( ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0 && gpUpdateKey() == 0 ) {
		
		//	拡縮ラスター
		const int height=2;
		for( int y=0 ; y<SIZEY ; y+=height ) {
			double xrate = 1.0 + 0.7 * sin( (double)(y+pos) * PI / 80.0 );//ラジアン変換と拡大率への変換
			double waverate = (1.0 +  sin( ((double)y+wave) * PI / 40.0 ) ) / 2.0;//0から1.0
			
			//	縦方向の揺らぎ
			int srcy = y + waverate * 60.0;
			
			//	スライスして描画する
			int x1 = (SIZEX / 2) - ( (double)(SIZEX / 2) * xrate );//拡大率
			int x2 = (SIZEX / 2) + ( (double)(SIZEX / 2) * xrate );//拡大率
			DrawRectExtendGraph( x1,y,x2,y+height, 0,srcy,SIZEX,height,Handle,TRUE);
		}
		
		//	位置をずらします。
		pos++;
		wave+=1.5;//周期が別になるように
	}

	DxLib_End(); // DXライブラリ終了処理
	return 0;
}
添付ファイル
ラスター2.png
ラスター2.png (47.32 KiB) 閲覧数: 1168 回
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

忍ノ一字

Re: 背景を歪ませる方法

#8

投稿記事 by 忍ノ一字 » 7年前

おおお!
添付のコードから横への揺らぎをなくしたらまさしくそれになりました!

ソース上では上下反転しているようには見えないのですが、
なぜ上下反転していることろがあるように見えるのでしょうか?

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 9年前
住所: 東海地方
連絡を取る:

Re: 背景を歪ませる方法

#9

投稿記事 by softya(ソフト屋) » 7年前

先の画像を手前に転送しているので基本的に逆転しています。
まぁ、waverate を調整すれば正常・反転を取り混ぜたものに出来ると思います。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

忍ノ一字

Re: 背景を歪ませる方法

#10

投稿記事 by 忍ノ一字 » 7年前

>先の画像を手前に転送しているので基本的に逆転しています。

全く理解出来ないです。。。
もう少しソースコードとにらめっこしてみます。

忍ノ一字

Re: 背景を歪ませる方法

#11

投稿記事 by 忍ノ一字 » 7年前

ようやく理解出来ました!
おかげさまで完全に再現することが出来ました

ありがとうございましたm(_ _)m

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 9年前
住所: 東海地方
連絡を取る:

Re: 背景を歪ませる方法

#12

投稿記事 by softya(ソフト屋) » 7年前

忍ノ一字 さんが書きました:ようやく理解出来ました!
おかげさまで完全に再現することが出来ました

ありがとうございましたm(_ _)m
ぜひ、調整した再現コードを貼って下さい。
ここのフォーラムルールでもありますので。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

忍ノ一字

Re: 背景を歪ませる方法

#13

投稿記事 by 忍ノ一字 » 7年前

これは失礼しました。

コード:

        double wave = wave_info.phase;
        for( int y = 0; y < org_size.y; y++ ) {
            double waverate = (1.0 +  sin( ((double)y*wave_info.cycle+wave) * 3.141592 / 60 ) ) / 2.0;//0から1.0

            //  縦方向の揺らぎ
            int srcy = y + waverate * wave_info.amp;
            
            DXLW::getGraphic().DrawRectExtendGraph( 
                    0, y, size.x, y + 1,
                    0, srcy, org_size.x, 1,
                    screen, 0, TRUE);
        }
        
        //  位置をずらします。
        wave_info.phase += wave_info.speed;//周期が別になるように
wave_info.cycle = 2.6
wave_info.amp = 60
wave_info.speed = 2.3
でほぼほぼ動画と同じ感じになりました。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 9年前
住所: 東海地方
連絡を取る:

Re: 背景を歪ませる方法

#14

投稿記事 by softya(ソフト屋) » 7年前

元のに組み込むとこんな感じですかね。
ついでにパラメータをいじって遊べるようにしてみました。
横も加えて遊んみるとおもしろものが出来るかもしれません。

コード:

#include "DxLib.h"
#include <math.h>

int Key[256]; // キーが押されているフレーム数を格納する

// キーの入力状態を更新する
int gpUpdateKey() {
	char tmpKey[256]; // 現在のキーの入力状態を格納する
	GetHitKeyStateAll( tmpKey ); // 全てのキーの入力状態を得る
	for( int i = 0; i < 256; i++ ) {
		if( tmpKey[i] != 0 ) { // i番のキーコードに対応するキーが押されていたら
			Key[i]++;     // 加算
		} else {              // 押されていなければ
			Key[i] = 0;   // 0にする
		}
	}
	return 0;
}


#define PI 3.14159265358979323846
#define SIZEX 640
#define SIZEY 480

int WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR, int ) {
	ChangeWindowMode( TRUE ), DxLib_Init(), SetDrawScreen( DX_SCREEN_BACK ); //ウィンドウモード変更と初期化と裏画面設定

	int Handle = LoadGraph( "moon.png" );
	double wave = 0;
	double cycle = 2.6;
	double amp = 60.0;
	double speed = 2.3;
	
	// while(裏画面を表画面に反映, メッセージ処理, 画面クリア, キーの更新)
	while( ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0 && gpUpdateKey() == 0 ) {
		
		//	拡縮ラスター
		const int height=1;
		for( int y=0 ; y<SIZEY ; y+=height ) {
			double waverate = (1.0 +  sin( ((double)y*cycle+wave) * PI / 60 ) ) / 2.0;//0から1.0
			
			//	縦方向の揺らぎ
			int srcy = y + waverate * amp;
			
			//	スライスして描画する
			DrawRectExtendGraph( 0,y,SIZEX,y+height, 0,srcy,SIZEX,height,Handle,TRUE);
		}
		
		//	パラメータを表示
		DrawFormatString(0,0,GetColor(255,255,255),"cycle=%7.3f ←→", cycle );
		DrawFormatString(0,16,GetColor(255,255,255),"amp=%7.3f ↓↑", amp );
		DrawFormatString(0,32,GetColor(255,255,255),"speed=%7.3f ZX", speed );
		
		//	パラメータの調整
		if( Key[KEY_INPUT_RIGHT] > 0 )	cycle -= 0.01;
		if( Key[KEY_INPUT_LEFT] > 0 )	cycle += 0.01;
		if( Key[KEY_INPUT_DOWN] > 0 )	amp -= 1;
		if( Key[KEY_INPUT_UP] > 0 )		amp += 1;
		if( Key[KEY_INPUT_X] > 0 )		speed -= 0.01;
		if( Key[KEY_INPUT_Z] > 0 )		speed += 0.01;
		
		
		
		//	位置をずらします。
		wave+=speed;//周期が別になるように
	}

	DxLib_End(); // DXライブラリ終了処理
	return 0;
}
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

閉鎖

“C言語何でも質問掲示板” へ戻る