베이직 이펙트 머티리얼
요약
BasicEffect의 재질 부분과 관련된 매개 변수를 조작하여 모델이 어떻게 보이는지 확인합니다.
운영 환경
필수 구성 요소
지원되는 XNA 버전 |
|
지원되는 플랫폼 |
|
Windows 필수 버텍스 셰이더 버전 | 2.0 |
Windows 필수 픽셀 셰이더 버전 | 2.0 |
운영 환경
플랫폼 |
|
샘플로 작업하는 방법
작동 키보드Xbox | 360 컨트롤러마우스 | 터치 | ||
---|---|---|---|---|
변경할 매개 변수를 선택합니다 | ↑、↓ | 왼쪽 스틱 ↑, ↓ | 왼쪽 버튼 | - |
파라미터 변경 | ←、→ | 왼쪽 스틱 ←, → | ←→ 드래그 | - |
물질
베이직이펙트란?
XNA에서 3D 다각형을 표시하려면 셰이더 프로그램을 작성하여 다각형을 그리고 그리는 방법을 결정해야 합니다. 이렇게 하려면 별도의 효과 파일을 만들고, 프로그램을 작성하고, 효과 클래스(Effect)로 읽고, 셰이더 프로그램을 실행합니다.
다만, 특별한 그리기 효과가 필요하지 않은 경우가 많고, 그런 경우에도 Effect가 필요하기 때문에, 쉐이더 프로그램을 굳이 구현하는 것은 의외로 번거롭습니다.
따라서 소재와 조명 등의 기본 파라미터를 속성으로 미리 준비하여 효과를 쉽게 처리 할 수 있도록 "BasicEffect"를 준비하고 있습니다. 효과 파일을 만들 필요가 없기 때문에 매우 쉽고 클래스의 인스턴스를 만들기만 하면 처리할 수 있습니다.
콘텐츠에서 Model 데이터를 로드하더라도 BasicEffect가 기본적으로 설정되어 있으므로 인스턴스를 만들 필요도 없습니다.
재료
재질은 주로 물질의 재질의 특성을 말하며 물질의 색상, 반사 정도, 강도를 지정하는 데 사용됩니다. 셰이더 프로그램에서는 독립적으로 표현할 수 있게 되었기 때문에 재질의 정의는 고정되지 않고 대략적인 의미를 가질 수 있지만, BasicEffect에는 다음과 같은 파라미터가 있습니다.
알파 | 불투명도. 값 1.0은 불투명도를 나타내고 값 0.0은 완전한 투명도를 나타냅니다. |
디퓨즈 컬러(DiffuseColor) | 표시할 개체의 물질 색상입니다. RGB로 색상을 나타냅니다. 재료의 음영은 빛의 상태에 따라 반사됩니다. |
이미시브 컬러(EmissiveColor) | 표시할 개체의 방사된 색상입니다. RGB로 색상을 나타냅니다. 스스로 빛을 발하는 색이기 때문에 빛의 영향을받지 않고 색이 더해집니다. |
스페큘러 컬러(SpecularColor) | 표시할 개체의 반사 색상입니다. RGB로 색상을 나타냅니다. 빛의 방향과 관점에 따라 재료가 반사되는 것처럼 보입니다. |
스페큘러 파워 | 표시할 물체의 반사 강도입니다. 값이 높을수록 반사되는 영역이 작아집니다. |
소재 변경 이미지
아래 이미지는 재질의 다양한 값을 보여줍니다.
초기 상태
샘플 모델 데이터를 로드한 직후의 상태입니다.
알파 | 1 |
확산(빨간색) | 0.8 |
확산(녹색) | 0.8 |
확산(파란색) | 0 |
이미시브(빨간색) | 0 |
이미시브(초록색) | 0 |
이미시브(파란색) | 0 |
스페큘러(빨간색) | 0 |
스페큘러(녹색) | 0 |
스페큘러(파란색) | 0 |
스페큘러 파워 | 5 |
불투명도(알파) 변경
불투명도를 변경할 때입니다. 배경의 파란색이 희미하게 보입니다.
알파 | 0.31 |
확산(빨간색) | 0.8 |
확산(녹색) | 0.8 |
확산(파란색) | 0 |
이미시브(빨간색) | 0 |
이미시브(초록색) | 0 |
이미시브(파란색) | 0 |
스페큘러(빨간색) | 0 |
스페큘러(녹색) | 0 |
스페큘러(파란색) | 0 |
스페큘러 파워 | 5 |
디퓨즈 수정(Diffuse Modifications)
물질의 색상이 변경되어 푸르스름해집니다.
알파 | 1 |
확산(빨간색) | 0.05 |
확산(녹색) | 0.71 |
확산(파란색) | 1 |
이미시브(빨간색) | 0 |
이미시브(초록색) | 0 |
이미시브(파란색) | 0 |
스페큘러(빨간색) | 0 |
스페큘러(녹색) | 0 |
스페큘러(파란색) | 0 |
스페큘러 파워 | 5 |
이미시브 수정(Emissive Modifications)
이미시브의 빨강과 파랑 요소가 최대화됩니다. 빛의 상태에 관계없이 적어도 보라색 상태는 유지됩니다.
알파 | 1 |
확산(빨간색) | 0.8 |
확산(녹색) | 0.8 |
확산(파란색) | 0 |
이미시브(빨간색) | 1 |
이미시브(초록색) | 0 |
이미시브(파란색) | 1 |
스페큘러(빨간색) | 0 |
스페큘러(녹색) | 0 |
스페큘러(파란색) | 0 |
스페큘러 파워 | 5 |
스페큘러 변경 사항
스페큘러를 설정하면 재질이 반사되어 나타납니다.
알파 | 1 |
확산(빨간색) | 0.8 |
확산(녹색) | 0.8 |
확산(파란색) | 0 |
이미시브(빨간색) | 0 |
이미시브(초록색) | 0 |
이미시브(파란색) | 0 |
스페큘러(빨간색) | 1 |
스페큘러(녹색) | 1 |
스페큘러(파란색) | 1 |
스페큘러 파워 | 5 |
스페큘러 파워 수정
스페큘러 파워를 변경하면 반사면의 범위가 변경됩니다.
알파 | 1 |
확산(빨간색) | 0.8 |
확산(녹색) | 0.8 |
확산(파란색) | 0 |
이미시브(빨간색) | 0 |
이미시브(초록색) | 0 |
이미시브(파란색) | 0 |
스페큘러(빨간색) | 1 |
스페큘러(녹색) | 1 |
스페큘러(파란색) | 1 |
스페큘러 파워 | 20 |
밭
이 필드에는 BasicEffect로 설정할 재질 정보가 있습니다. 또한 메뉴 선택을위한 매개 변수가 있지만 조작을위한 매개 변수이기 때문에 자세한 내용은 생략합니다.
<summary>
不透明度
</summary>
private float alpha = 1.0f;
<summary>
ディフーズ
</summary>
private Vector3 diffuse = Vector3.One;
<summary>
エミッシブ
</summary>
private Vector3 emissive = Vector3.Zero;
<summary>
スペキュラー
</summary>
private Vector3 specular = Vector3.Zero;
<summary>
スペキュラーの強さ
</summary>
private float specularPower = 5.0f;
모델의 재질 검색
모델에 초기 값으로 설정된 재질의 값이 검색됩니다. 이 샘플에서는 모델에 하나의 효과 집합만 있다는 가정 하에 코드가 작성되었습니다.
// ライトとビュー、プロジェクションはあらかじめ設定しておく
foreach (ModelMesh mesh in this.model.Meshes)
{
foreach (BasicEffect effect in mesh.Effects)
{
// デフォルトのライト適用
effect.EnableDefaultLighting();
// ビューマトリックスをあらかじめ設定 ((0, 0, 6) から原点を見る)
effect.View = Matrix.CreateLookAt(
new Vector3(0.0f, 0.0f, 6.0f),
Vector3.Zero,
Vector3.Up
);
// プロジェクションマトリックスをあらかじめ設定
effect.Projection = Matrix.CreatePerspectiveFieldOfView(
MathHelper.ToRadians(45.0f),
(float)this.GraphicsDevice.Viewport.Width /
(float)this.GraphicsDevice.Viewport.Height,
1.0f,
100.0f
);
// モデルのマテリアルを取得 //
// アルファ
this.alpha = effect.Alpha;
// ディフーズ
this.diffuse = effect.DiffuseColor;
// エミッシブ
this.emissive = effect.EmissiveColor;
// スペキュラー
this.specular = effect.SpecularColor;
// スペキュラーの強さ
this.specularPower = effect.SpecularPower;
}
}
머티리얼 설정
이 샘플에서는 값을 모델의 BasicEffect로 설정합니다. "DiffuseColor", "EmissiveColor" 및 "SpecularColor"의 경우 Color 구조체가 아닌 Vector3에 설정합니다. X는 빨간색, Y는 녹색, Z는 파란색으로 요소를 0.0~1.0 값으로 지정합니다.
// マテリアルを設定
foreach (ModelMesh mesh in this.model.Meshes)
{
foreach (BasicEffect effect in mesh.Effects)
{
// 不透明度
effect.Alpha = this.alpha;
// ディフーズ
effect.DiffuseColor = this.diffuse;
// エミッシブ
effect.EmissiveColor = this.emissive;
// スペキュラー
effect.SpecularColor = this.specular;
// スペキュラーの強さ
effect.SpecularPower = this.specularPower;
}
}
샘플에서는 머티리얼 연산 코드나 값의 문자열 표시 등의 코드가 있습니다만, BasicMaterial과 직접 관련되지 않는 부분도 있기 때문에 설명은 생략하겠습니다. 샘플을 다운로드하거나 전체 코드를 확인할 수 있습니다.
BasicEffect.Alpha
재산
불투명도를 가져오고 설정합니다. 0.0~1.0 범위의 값을 지정합니다. | 뜨다 | get, set |
BasicEffect.DiffuseColor
재산
분산 색을 가져오고 설정합니다. X는 빨간색, Y는 녹색, Z는 파란색이며 각 값은 0.0~1.0 범위입니다. | 벡터3 | get, set |
BasicEffect.EmissiveColor
재산
내보낸 색을 가져오고 설정합니다. X는 빨간색, Y는 녹색, Z는 파란색이며 각 값은 0.0~1.0 범위입니다. | 벡터3 | get, set |
BasicEffect.SpecularColor
재산
반사된 색을 가져오고 설정합니다. X는 빨간색, Y는 녹색, Z는 파란색이며 각 값은 0.0~1.0 범위입니다. | 벡터3 | get, set |
BasicEffect.SpecularPower
재산
반사의 강도를 가져오고 설정합니다. 값은 0.0~으로 지정됩니다. | 뜨다 | get, set |
모든 코드
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
#if WINDOWS_PHONE
using Microsoft.Xna.Framework.Input.Touch;
#endif
namespace BasicEffectMaterial
{
<summary>
ゲームメインクラス
</summary>
public class GameMain : Microsoft.Xna.Framework.Game
{
<summary>
グラフィックデバイス管理クラス
</summary>
private GraphicsDeviceManager graphics = null;
<summary>
スプライトのバッチ化クラス
</summary>
private SpriteBatch spriteBatch = null;
<summary>
スプライトでテキストを描画するためのフォント
</summary>
private SpriteFont font = null;
<summary>
直前のキーボード入力の状態
</summary>
private KeyboardState oldKeyboardState = new KeyboardState();
<summary>
直前のマウスの状態
</summary>
private MouseState oldMouseState = new MouseState();
<summary>
直前のゲームパッド入力の状態
</summary>
private GamePadState oldGamePadState = new GamePadState();
<summary>
モデル
</summary>
private Model model = null;
<summary>
不透明度
</summary>
private float alpha = 1.0f;
<summary>
ディフーズ
</summary>
private Vector3 diffuse = Vector3.One;
<summary>
エミッシブ
</summary>
private Vector3 emissive = Vector3.Zero;
<summary>
スペキュラー
</summary>
private Vector3 specular = Vector3.Zero;
<summary>
スペキュラーの強さ
</summary>
private float specularPower = 5.0f;
<summary>
選択しているメニューのインデックス
</summary>
private int selectedMenuIndex = 0;
<summary>
パラメータの最大数
</summary>
private static int MaxParameterCount = 11;
<summary>
メニューリスト
</summary>
private static string[] MenuNameList = new string[]
{
"Alpha",
"Diffuse (Red)",
"Diffuse (Green)",
"Diffuse (Blue)",
"Emissive (Red)",
"Emissive (Green)",
"Emissive (Blue)",
"Specular (Red)",
"Specular (Green)",
"Specular (Blue)",
"SpecularPower"
};
<summary>
パラメータテキストリスト
</summary>
private string[] parameters = new string[MaxParameterCount];
<summary>
GameMain コンストラクタ
</summary>
public GameMain()
{
// グラフィックデバイス管理クラスの作成
this.graphics = new GraphicsDeviceManager(this);
// ゲームコンテンツのルートディレクトリを設定
this.Content.RootDirectory = "Content";
#if WINDOWS_PHONE
// Windows Phone のデフォルトのフレームレートは 30 FPS
this.TargetElapsedTime = TimeSpan.FromTicks(333333);
// バックバッファサイズの設定
this.graphics.PreferredBackBufferWidth = 480;
this.graphics.PreferredBackBufferHeight = 800;
// フルスクリーン表示
this.graphics.IsFullScreen = true;
#endif
// ウインドウ上でマウスのポインタを表示するようにする
this.IsMouseVisible = true;
}
<summary>
ゲームが始まる前の初期化処理を行うメソッド
グラフィック以外のデータの読み込み、コンポーネントの初期化を行う
</summary>
protected override void Initialize()
{
// コンポーネントの初期化などを行います
base.Initialize();
}
<summary>
ゲームが始まるときに一回だけ呼ばれ
すべてのゲームコンテンツを読み込みます
</summary>
protected override void LoadContent()
{
// テクスチャーを描画するためのスプライトバッチクラスを作成します
this.spriteBatch = new SpriteBatch(this.GraphicsDevice);
// フォントをコンテンツパイプラインから読み込む
this.font = this.Content.Load<SpriteFont>("Font");
// モデルを作成
this.model = this.Content.Load<Model>("Model");
// ライトとビュー、プロジェクションはあらかじめ設定しておく
foreach (ModelMesh mesh in this.model.Meshes)
{
foreach (BasicEffect effect in mesh.Effects)
{
// デフォルトのライト適用
effect.EnableDefaultLighting();
// ビューマトリックスをあらかじめ設定 ((0, 0, 6) から原点を見る)
effect.View = Matrix.CreateLookAt(
new Vector3(0.0f, 0.0f, 6.0f),
Vector3.Zero,
Vector3.Up
);
// プロジェクションマトリックスをあらかじめ設定
effect.Projection = Matrix.CreatePerspectiveFieldOfView(
MathHelper.ToRadians(45.0f),
(float)this.GraphicsDevice.Viewport.Width /
(float)this.GraphicsDevice.Viewport.Height,
1.0f,
100.0f
);
// モデルのマテリアルを取得 //
// アルファ
this.alpha = effect.Alpha;
// ディフーズ
this.diffuse = effect.DiffuseColor;
// エミッシブ
this.emissive = effect.EmissiveColor;
// スペキュラー
this.specular = effect.SpecularColor;
// スペキュラーの強さ
this.specularPower = effect.SpecularPower;
}
}
}
<summary>
ゲームが終了するときに一回だけ呼ばれ
すべてのゲームコンテンツをアンロードします
</summary>
protected override void UnloadContent()
{
// TODO: ContentManager で管理されていないコンテンツを
// ここでアンロードしてください
}
<summary>
描画以外のデータ更新等の処理を行うメソッド
主に入力処理、衝突判定などの物理計算、オーディオの再生など
</summary>
<param name="gameTime">このメソッドが呼ばれたときのゲーム時間</param>
protected override void Update(GameTime gameTime)
{
// 入力デバイスの状態取得
KeyboardState keyboardState = Keyboard.GetState();
MouseState mouseState = Mouse.GetState();
GamePadState gamePadState = GamePad.GetState(PlayerIndex.One);
// Xbox 360 コントローラ、Windows Phone の BACK ボタンを押したときに
// ゲームを終了させます
if (gamePadState.Buttons.Back == ButtonState.Pressed)
{
this.Exit();
}
// メニューの選択
if ((keyboardState.IsKeyDown(Keys.Up) && this.oldKeyboardState.IsKeyUp(Keys.Up)) ||
(gamePadState.ThumbSticks.Left.Y >= 0.5f &&
this.oldGamePadState.ThumbSticks.Left.Y < 0.5f))
{
// 選択メニューをひとつ上に移動
this.selectedMenuIndex =
(this.selectedMenuIndex + this.parameters.Length - 1) % this.parameters.Length;
}
if ((keyboardState.IsKeyDown(Keys.Down) && this.oldKeyboardState.IsKeyUp(Keys.Down)) ||
(gamePadState.ThumbSticks.Left.Y <= -0.5f &&
this.oldGamePadState.ThumbSticks.Left.Y > -0.5f) ||
(this.oldMouseState.LeftButton == ButtonState.Pressed &&
mouseState.LeftButton == ButtonState.Released))
{
// 選択メニューをひとつ下に移動
this.selectedMenuIndex =
(this.selectedMenuIndex + this.parameters.Length + 1) % this.parameters.Length;
}
// 各マテリアルの値を操作
float moveValue = 0.0f;
if (keyboardState.IsKeyDown(Keys.Left))
{
moveValue -= (float)gameTime.ElapsedGameTime.TotalSeconds;
}
if (keyboardState.IsKeyDown(Keys.Right))
{
moveValue += (float)gameTime.ElapsedGameTime.TotalSeconds;
}
if (mouseState.LeftButton == ButtonState.Pressed)
{
moveValue += (mouseState.X - this.oldMouseState.X) * 0.005f;
}
if (gamePadState.IsConnected)
{
moveValue += gamePadState.ThumbSticks.Left.X *
(float)gameTime.ElapsedGameTime.TotalSeconds;
}
switch (this.selectedMenuIndex)
{
case 0: // 不透明度
this.alpha = MathHelper.Clamp(this.alpha + moveValue,
0.0f,
1.0f);
break;
case 1: // ディフューズ (赤)
this.diffuse.X = MathHelper.Clamp(this.diffuse.X + moveValue,
0.0f,
1.0f);
break;
case 2: // ディフューズ (緑)
this.diffuse.Y = MathHelper.Clamp(this.diffuse.Y + moveValue,
0.0f,
1.0f);
break;
case 3: // ディフューズ (青)
this.diffuse.Z = MathHelper.Clamp(this.diffuse.Z + moveValue,
0.0f,
1.0f);
break;
case 4: // エミッシブ (赤)
this.emissive.X = MathHelper.Clamp(this.emissive.X + moveValue,
0.0f,
1.0f);
break;
case 5: // エミッシブ (緑)
this.emissive.Y = MathHelper.Clamp(this.emissive.Y + moveValue,
0.0f,
1.0f);
break;
case 6: // エミッシブ (青)
this.emissive.Z = MathHelper.Clamp(this.emissive.Z + moveValue,
0.0f,
1.0f);
break;
case 7: // スペキュラー (赤)
this.specular.X = MathHelper.Clamp(this.specular.X + moveValue,
0.0f,
1.0f);
break;
case 8: // スペキュラー (緑)
this.specular.Y = MathHelper.Clamp(this.specular.Y + moveValue,
0.0f,
1.0f);
break;
case 9: // スペキュラー (青)
this.specular.Z = MathHelper.Clamp(this.specular.Z + moveValue,
0.0f,
1.0f);
break;
case 10: // スペキュラーの強さ
moveValue *= 5.0f;
this.specularPower = MathHelper.Clamp(this.specularPower + moveValue,
0.0f,
100.0f);
break;
}
// マテリアルを設定
foreach (ModelMesh mesh in this.model.Meshes)
{
foreach (BasicEffect effect in mesh.Effects)
{
// 不透明度
effect.Alpha = this.alpha;
// ディフーズ
effect.DiffuseColor = this.diffuse;
// エミッシブ
effect.EmissiveColor = this.emissive;
// スペキュラー
effect.SpecularColor = this.specular;
// スペキュラーの強さ
effect.SpecularPower = this.specularPower;
}
}
// 入力情報を記憶
this.oldKeyboardState = keyboardState;
this.oldMouseState = mouseState;
this.oldGamePadState = gamePadState;
// 登録された GameComponent を更新する
base.Update(gameTime);
}
<summary>
描画処理を行うメソッド
</summary>
<param name="gameTime">このメソッドが呼ばれたときのゲーム時間</param>
protected override void Draw(GameTime gameTime)
{
// 画面を指定した色でクリアします
this.GraphicsDevice.Clear(Color.CornflowerBlue);
// 深度バッファを有効にする
this.GraphicsDevice.DepthStencilState = DepthStencilState.Default;
// モデルを描画
foreach (ModelMesh mesh in this.model.Meshes)
{
mesh.Draw();
}
// スプライトの描画準備
this.spriteBatch.Begin();
// 操作
this.spriteBatch.DrawString(this.font,
"Up, Down : Select Menu",
new Vector2(20.0f, 20.0f), Color.White);
this.spriteBatch.DrawString(this.font,
"Left, right : Change Value",
new Vector2(20.0f, 45.0f), Color.White);
this.spriteBatch.DrawString(this.font,
"MouseClick & Drag :",
new Vector2(20.0f, 70.0f), Color.White);
this.spriteBatch.DrawString(this.font,
" Select Menu & Change Value",
new Vector2(20.0f, 95.0f), Color.White);
// 各メニュー //
for (int i = 0; i < MenuNameList.Length; i++)
{
this.spriteBatch.DrawString(this.font,
MenuNameList[i],
new Vector2(40.0f, 120.0f + i * 24.0f), Color.White);
}
// 各パラメータ //
// 不透明度
this.parameters[0] = this.alpha.ToString();
// ディフューズ (赤)
this.parameters[1] = this.diffuse.X.ToString();
// ディフューズ (緑)
this.parameters[2] = this.diffuse.Y.ToString();
// ディフューズ (青)
this.parameters[3] = this.diffuse.Z.ToString();
// エミッシブ (赤)
this.parameters[4] = this.emissive.X.ToString();
// エミッシブ (緑)
this.parameters[5] = this.emissive.Y.ToString();
// エミッシブ (青)
this.parameters[6] = this.emissive.Z.ToString();
// スペキュラー (赤)
this.parameters[7] = this.specular.X.ToString();
// スペキュラー (緑)
this.parameters[8] = this.specular.Y.ToString();
// スペキュラー (青)
this.parameters[9] = this.specular.Z.ToString();
// スペキュラーの強さ
this.parameters[10] = this.specularPower.ToString();
for (int i = 0; i < this.parameters.Length; i++)
{
this.spriteBatch.DrawString(this.font,
this.parameters[i],
new Vector2(250.0f, 120.0f + i * 24.0f), Color.White);
}
// 選択インデックス
this.spriteBatch.DrawString(this.font, "*",
new Vector2(20.0f, 124.0f + this.selectedMenuIndex * 24.0f), Color.White);
// スプライトの一括描画
this.spriteBatch.End();
// 登録された DrawableGameComponent を描画する
base.Draw(gameTime);
}
}
}