UVTexIntegra 310.0.0.3

- メインページ
- 関連ページ
- モジュール
- ネームスペース
- クラス
- ファイル

全て クラス ネームスペース 関数 変数 列挙型 プロパティ イベント グループ ページ
実装例（EdgeBake.cs）

これまでのトピックを踏まえて、「頂点法線と面法線の角度差が大きいほど黒ずむ」鋭角ベイクのサンプルコードを示します。

﻿// このコードではコメントがdoxygenスタイルになっていますが、作者がUVTexIntegraの作成時にdoxygenを使っていただけですので、とくに気にしないで下さい。
using System;
using System.ComponentModel;
using UVTexIntegra.Scripting;
[Serializable, UVTexIntegra.Scripting.SerializeSave(true)]
public class EdgeBake :
UVTexIntegra.Scripting.ScriptMain, // ScriptMainを継承してください。
System.Runtime.Serialization.ISerializable // パラメータを保存する時は必要
{
public enum InteropMode
{
Linear,
Angle
};
public enum SmoothMode
{
None,
Max,
Min,
Average
}
public override string Name
{
get
{
return "鋭角ベイク";
}
}
[DefaultValue(InteropMode.Linear)]
[Description("ホワイトアウト/ブラックアウトの補間モードを指定します。")]
public InteropMode Interop { get; set; }
[DefaultValue(180.0f)]
[Description("ブラックアウト角を設定します。頂点の法線と面の法線の角度差がこの角度より大きい時、焼きこむ頂点色がブラックアウトします。0～180度以内で、かつホワイトアウト角より大きい値を設定してください。")]
public float BlackoutAngle
{
get { return m_blackoutAngle; }
set
{
value = Math.Min(Math.Max(value, 0.0f), 180.0f);
m_blackoutAngle = value;
m_whiteoutAngle = System.Math.Min(value, m_whiteoutAngle);
OnResetParams();
}
}
[DefaultValue(SmoothMode.Average)]
[Description("同じUV座標を共有する時のスムージングモードを指定します。None-無効/Max-明るい最大値/Min-暗い最小値/Average-単純な相加平均")]
public SmoothMode Smooth { get; set; }
[DefaultValue(0.0f)]
[Description("ホワイトアウト角を設定します。頂点の法線と面の法線の角度差がこの角度より小さい時、焼きこむ頂点色がホワイトアウトします。0～180度以内で、かつブラックアウト角より小さい値を設定してください。")]
public float WhiteoutAngle
{
get { return m_whiteoutAngle; }
set
{
value = Math.Min(Math.Max(value, 0.0f), 180.0f);
m_whiteoutAngle = value;
m_blackoutAngle = System.Math.Max(value, m_blackoutAngle);
OnResetParams();
}
}
public EdgeBake()
{
Interop = InteropMode.Linear;
m_blackoutAngle = 180.0f;
m_whiteoutAngle = 0.0f;
Smooth = SmoothMode.Average;
OnResetParams();
}
public EdgeBake(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext stream)
: this()
{
try
{
Interop = (InteropMode)(info.GetValue("Interop", typeof(InteropMode)));
}
catch (System.Exception)
{
}
try
{
m_blackoutAngle = info.GetSingle("bkout");
}
catch (System.Exception)
{
}
try
{
m_whiteoutAngle = info.GetSingle("whout");
}
catch (System.Exception)
{
}
try
{
Smooth = (SmoothMode)(info.GetValue("Smooth", typeof(SmoothMode)));
}
catch (System.Exception) { }
OnResetParams();
}
public void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext stream)
{
info.AddValue("Interop", Interop);
info.AddValue("bkout", m_blackoutAngle);
info.AddValue("whout", m_whiteoutAngle);
info.AddValue("Smooth", Smooth);
}
public override void OnUVOperation(ScriptMain.Face[] faces)
{
// 面法線と頂点法線の角度差を計算して色に変換
foreach (ScriptMain.Face face in faces)
{
for (int index = 0; index < face.Points.Length; index++)
{
// 面法線と頂点法線で内積。内積が角度差をcosで表すので、それを0～1にマップします。
double dot_f = OpenTK.Vector3.Dot(face.Normal, face.Points[index].Normal) * 0.5 + 0.5;
// 事前計算済みのパラメータを使ってブラックアウトとホワイトアウトを調整します。
dot_f = System.Math.Max(System.Math.Min(dot_f / m_div + m_ofs, 1.0), 0.0);
// InteropMode.Angleが指定される時は、0-1の直線補間からゆるやかなS字（コサインカーブ）に置換し、再び0-1に再マップ。
if (Interop == InteropMode.Angle) dot_f = System.Math.Cos((1.0 + dot_f) * System.Math.PI) * 0.5 + 0.5;
// RGBに変換
int dot = System.Math.Max(System.Math.Min((int)(255.0 * dot_f), 255), 0);
// １つの頂点ごとに計算結果を反映
face.Points[index].Color = System.Drawing.Color.FromArgb(0xFF, dot, dot, dot);
}
}
// 基本的にはUV座標情報の書き換えフックはここまでです。
// ただ頂点色ベイクという処理の都合上スムージングした方が良いのでスムージング処理も書いておきます。
// スムージング処理
if (Smooth != SmoothMode.None)
{
// ScriptMain.Face.ShareRelation.GetRelationsSnap()メソッドを使うと、
// その時点で、ほとんど同じ座標（座標の差がきわめて小さい）のUV頂点を並べたデータを返します。
// (*1) 作った時点でのスナップショットなので、UV座標を書き換えると関連性は正しくない状態になります。
// UV座標を書き換えるときはそれが終わってからGetRelationsSnapするか、その都度作り直さないと整合性がなくなります。
// (*2) ここでは同じ座標とみなす許容誤差にfloat.Epsilon * 4.0fをとりあえず設定しています(この数値にとくに論拠はありません)。
// (*3) UV頂点はひとつのShareRelationにしか属さないので、重複登録されたりはしません。
System.Collections.ObjectModel.ReadOnlyCollection<ScriptMain.Face.ShareRelation> shareSnap =
ScriptMain.Face.ShareRelation.GetRelationsSnap(faces, float.Epsilon * 4.0f);
switch (Smooth)
{
// 相加平均モード。いわゆる普通の平均値
case SmoothMode.Average:
// まとめられたUV情報(ScriptMain.Face.ShareRelation)を総当り
foreach (ScriptMain.Face.ShareRelation rel in shareSnap)
{
if (1 < rel.Owners.Count)
{
int sum = 0;
// このShareRelationでUVを共有する全てのオーナーのR要素だけ全部合計
foreach (Face.ShareRelation.IReference reference in rel.Owners) sum += reference.Point.Color.R;
// 要素数で割って平均値。一応オーバーフローしないようにしてるけどいらないかも
sum = System.Math.Min((int)(sum / rel.Owners.Count), 0xFF);
// このShareRelationでUVを共有する全てのオーナーのカラーを平均値で更新
System.Drawing.Color color = System.Drawing.Color.FromArgb(0xFF, sum, sum, sum);
foreach (Face.ShareRelation.IReference reference in rel.Owners) reference.Point.Color = color;
}
}
// おしまい。
break;
// 最大値モード
case SmoothMode.Max:
// まとめられたUV情報(ScriptMain.Face.ShareRelation)を総当り
foreach (ScriptMain.Face.ShareRelation rel in shareSnap)
{
if (1 < rel.Owners.Count)
{
int max = 0;
// このShareRelationでUVを共有する全てのオーナーのR要素の最大値をゲット
foreach (Face.ShareRelation.IReference reference in rel.Owners) max = System.Math.Max(reference.Point.Color.R, max);
// このShareRelationでUVを共有する全てのオーナーのカラーを最大値で更新
System.Drawing.Color color = System.Drawing.Color.FromArgb(0xFF, max, max, max);
foreach (Face.ShareRelation.IReference reference in rel.Owners) reference.Point.Color = color;
}
}
// おしまい。
break;
// 最小値モード
case SmoothMode.Min:
// まとめられたUV情報(ScriptMain.Face.ShareRelation)を総当り
foreach (ScriptMain.Face.ShareRelation rel in shareSnap)
{
if (1 < rel.Owners.Count)
{
int min = 0xFF;
// このShareRelationでUVを共有する全てのオーナーのR要素の最小値をゲット
foreach (Face.ShareRelation.IReference reference in rel.Owners) min = System.Math.Min(reference.Point.Color.R, min);
System.Drawing.Color color = System.Drawing.Color.FromArgb(0xFF, min, min, min);
// このShareRelationでUVを共有する全てのオーナーのカラーを最小値で更新
foreach (Face.ShareRelation.IReference reference in rel.Owners) reference.Point.Color = color;
}
}
// おしまい。
break;
}
}
}
private float m_whiteoutAngle;
private float m_blackoutAngle;
private double m_div;
private double m_ofs;
private void OnResetParams()
{
double wout = 1.0 - (m_whiteoutAngle / 180.0);
double bout = 1.0 - (m_blackoutAngle / 180.0);
m_div = wout - bout;
m_ofs = 1.0 - wout / m_div;
}
}

EdgeBake.cs は、EdgeBakeフォルダにあるEdgeBake.slnに含まれています。