天天看點

Silverlight C# 遊戲開發:L5 3D基本的燈光

我們在設計和開發3D的時候最常用的就是燈光,它有的時候比錄影機還要重要,一些花哨漂亮的表現主要通過燈光實作,相比場景中隻有一個的主要錄影機以外,燈光的類型和内容更加豐富,今天暫用小段時間一起研究一下Silverlight3D當中的燈光。下圖是具體實作的預覽效果:

<a target="_blank" href="http://blog.51cto.com/attachment/201111/113359983.jpg"></a>

在開始之前,需要了解一下基本的燈光類型,Balder3D裡有三種燈光類型,分别是OmniLight、ViewLight、DirectionalLight,如果玩過3Dmax的朋友應該是相當的熟悉,這些光的表現形式組合構成了遊戲世界的絢麗多彩,沒有光的世界大家可以通過最後程式實驗一下,看看會如何呢。

OmniLight:也稱泛光燈或者點光,比較清楚了解,它就是一個點發出的光源

ViewLight:有了方向和目标,除了這個方向方位之内的都不會被照亮

DirectionalLight:是方向光,它是一個方向的照亮

具體内容可以參考下面的圖檔說明來了解他們,圖檔截取自3DMAX,資源來源于網絡。

<a target="_blank" href="http://blog.51cto.com/attachment/201111/113411751.jpg"></a>

有一個好看的燈光,固然重要,但是我們要先學會如何控制它們,今次的代碼比較多,涉及到了界面的操作,我将Lesson05代碼全部貼上,我的建議還是下載下傳源檔案看比較好一些:)

首先建立Lesson05這個控件,XAML代碼如下:(下述代碼使用Blend工具制作生成)

Lesson05.xaml

&lt;UserControl x:Class="Balder_Studio.Lesson05" 

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 

xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 

xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 

mc:Ignorable="d" 

d:DesignHeight="300" d:DesignWidth="400"&gt; 

&lt;Grid Background="White"&gt; 

&lt;Grid x:Name="LayoutRoot"/&gt; 

&lt;StackPanel HorizontalAlignment="Left" Orientation="Vertical" VerticalAlignment="Top" Width="199" Height="132"&gt; 

&lt;StackPanel Orientation="Horizontal"&gt; 

&lt;TextBlock TextWrapping="Wrap" Text="X軸" Width="38" Height="14"/&gt; 

&lt;Slider Height="23" x:Name="slider_axis_x" SmallChange="1" Maximum="100" LargeChange="10" Margin="0" Width="100" Minimum="-100" /&gt; 

&lt;TextBlock x:Name="axis_x" TextWrapping="Wrap" Width="38" Height="14" Text="0"/&gt; 

&lt;/StackPanel&gt; 

&lt;TextBlock TextWrapping="Wrap" Width="38" Height="14"&gt;&lt;Run Text="Y"/&gt;&lt;Run Text="軸"/&gt;&lt;/TextBlock&gt; 

&lt;Slider Height="23" x:Name="slider_axis_y" SmallChange="1" Maximum="100" LargeChange="10" Margin="0" Width="100" Minimum="-100" /&gt; 

&lt;TextBlock x:Name="axis_y" TextWrapping="Wrap" Width="38" Height="14" Text="0"/&gt; 

&lt;TextBlock TextWrapping="Wrap" Width="38" Height="14"&gt;&lt;Run Text="Z"/&gt;&lt;Run Text="軸"/&gt;&lt;/TextBlock&gt; 

&lt;Slider Height="23" x:Name="slider_axis_z" SmallChange="1" Maximum="100" LargeChange="10" Margin="0" Width="100" Minimum="-100" /&gt; 

&lt;TextBlock x:Name="axis_z" TextWrapping="Wrap" Width="38" Height="14" Text="0"/&gt; 

&lt;TextBlock TextWrapping="Wrap" Width="38" Height="14" Text="亮度"/&gt; 

&lt;Slider Height="23" x:Name="slider_Strength" Maximum="2" LargeChange="0.1" Margin="0" Width="100" Value="1" /&gt; 

&lt;TextBlock x:Name="StrengthText" Width="38" Height="14" Text="1"/&gt; 

&lt;TextBlock TextWrapping="Wrap" Width="38" Height="14" Text="類型"/&gt; 

&lt;ComboBox x:Name="LightType" Width="98"/&gt; 

&lt;StackPanel x:Name="LightExSetting" HorizontalAlignment="Left" Orientation="Vertical" VerticalAlignment="Top" Width="199" Height="132" Margin="198,0,-2,0" Visibility="Collapsed"&gt; 

&lt;TextBlock TextWrapping="Wrap" Text="偏移/方向X" Width="64" Height="14"/&gt; 

&lt;Slider Height="23" x:Name="slider_axis_x1" SmallChange="1" Maximum="100" LargeChange="10" Margin="0" Width="100" Minimum="-100" /&gt; 

&lt;TextBlock x:Name="axis_x1" TextWrapping="Wrap" Width="38" Height="14" Text="0"/&gt; 

&lt;TextBlock TextWrapping="Wrap" Width="64" Height="14"&gt;&lt;Run Text="偏移/方向"/&gt;&lt;Run Text="Y"/&gt;&lt;/TextBlock&gt; 

&lt;Slider Height="23" x:Name="slider_axis_y1" SmallChange="1" Maximum="100" LargeChange="10" Margin="0" Width="100" Minimum="-100" /&gt; 

&lt;TextBlock x:Name="axis_y1" TextWrapping="Wrap" Width="38" Height="14" Text="0"/&gt; 

&lt;TextBlock TextWrapping="Wrap" Width="64" Height="14"&gt;&lt;Run FontFamily="Verdana, Arial, Arial Unicode MS, Lucida Sans Unicode, Lucida Grande" Text="偏移/方向"/&gt;&lt;Run FontFamily="Verdana, Arial, Arial Unicode MS, Lucida Sans Unicode, Lucida Grande" Text="Z"/&gt;&lt;/TextBlock&gt; 

&lt;Slider Height="23" x:Name="slider_axis_z1" SmallChange="1" Maximum="100" LargeChange="10" Margin="0" Width="100" Minimum="-100" /&gt; 

&lt;TextBlock x:Name="axis_z1" TextWrapping="Wrap" Width="38" Height="14" Text="0"/&gt; 

&lt;StackPanel Orientation="Horizontal" Visibility="Collapsed"&gt; 

&lt;Slider Height="23" x:Name="slider_Strength1" Maximum="1" LargeChange="0.1" Margin="0" Width="100" Value="1" /&gt; 

&lt;TextBlock x:Name="StrengthText1" Width="38" Height="14" Text="1"/&gt; 

&lt;/Grid&gt; 

&lt;/UserControl&gt; 

Lesson05.xaml.cs   

using System;  

using System.Windows.Threading;  

using System.Windows.Controls;  

using System.Windows.Media;  

using Balder.Math;  

using Balder.Objects.Geometries;  

using Balder.View;  

using Balder.Lighting;  

using Balder.Execution;  

namespace Balder_Studio  

{  

public partial class Lesson05 : UserControl  

//選擇的燈光  

Light _SelectedLight = null;  

public Lesson05()  

InitializeComponent();   

slider_axis_x.ValueChanged += new System.Windows.RoutedPropertyChangedEventHandler&lt;double&gt;(slider_axis_ValueChanged);  

slider_axis_y.ValueChanged += new System.Windows.RoutedPropertyChangedEventHandler&lt;double&gt;(slider_axis_ValueChanged);  

slider_axis_z.ValueChanged += new System.Windows.RoutedPropertyChangedEventHandler&lt;double&gt;(slider_axis_ValueChanged);  

slider_Strength.ValueChanged += new System.Windows.RoutedPropertyChangedEventHandler&lt;double&gt;(slider_axis_ValueChanged);  

slider_axis_x1.ValueChanged += new System.Windows.RoutedPropertyChangedEventHandler&lt;double&gt;(slider_Offset_ValueChanged);  

slider_axis_y1.ValueChanged += new System.Windows.RoutedPropertyChangedEventHandler&lt;double&gt;(slider_Offset_ValueChanged);  

slider_axis_z1.ValueChanged += new System.Windows.RoutedPropertyChangedEventHandler&lt;double&gt;(slider_Offset_ValueChanged);  

OmniLight _OmniLight = new OmniLight();  

ViewLight _ViewLight = new ViewLight();  

DirectionalLight _DirectionalLight = new DirectionalLight() {Direction=new Coordinate(-1,-1,0) };  

//設定在同一個預設位置  

_OmniLight.Position = _ViewLight.Position = _DirectionalLight.Position = new Coordinate(0, 0, 0);  

//最開始的時候都不會亮  

_OmniLight.IsEnabled = _ViewLight.IsEnabled = _DirectionalLight.IsEnabled = false;  

LightType.Items.Add(new TextBlock() { Text = "點光源", Tag = _OmniLight });  

LightType.Items.Add(new TextBlock() { Text = "聚光源", Tag = _ViewLight });  

LightType.Items.Add(new TextBlock() { Text = "方向光", Tag = _DirectionalLight });  

LightType.SelectedIndex = 0;  

LightType.SelectionChanged += new SelectionChangedEventHandler(LightType_SelectionChanged);  

#region L1 - L4的代碼  

//L1  

Game game = new Game() { Width = 600, Height = 400 };  

game.Camera = new Camera();  

game.Camera.Position = new Coordinate(100, 120, 150);  

game.Camera.Target = new Coordinate(0, 0, 0);  

#endregion  

game.Children.Add(_OmniLight);  

_OmniLight.IsEnabled = true;  

_SelectedLight = _OmniLight;  

game.Children.Add(_ViewLight);  

game.Children.Add(_DirectionalLight);  

//L3  

Game_Axis axis_x = new Game_Axis(new Vertex(-300, 0, 0), new Vertex(300, 0, 0), Colors.Red);  

Game_Axis axis_y = new Game_Axis(new Vertex(0, -300, 0), new Vertex(0, 300, 0), Colors.Blue);  

Game_Axis axis_z = new Game_Axis(new Vertex(0, 0, -300), new Vertex(0, 0, 300), Colors.Green);  

//L4  

Balder.Objects.Geometries.Geometry group = new Balder.Objects.Geometries.Geometry() { Name = "MeshGroup" };  

group.InteractionEnabled = true;  

group.Children.Add(axis_x);  

group.Children.Add(axis_y);  

group.Children.Add(axis_z);  

//L2  

Mesh Teapot = new Mesh();  

Teapot.Position = new Coordinate(0, 0, 0);  

Teapot.AssetName = new Uri("/Balder_Studio;component/Res/teapot.ase", UriKind.Relative);  

group.Children.Add(Teapot);  

group.Children.Add(new Box() { Dimension = new Coordinate(10, 20, 30), Position = new Coordinate(100, 10, 0), Name = "MyBox" });  

group.Children.Add(new Box() { Dimension = new Coordinate(10, 30, 10), Position = new Coordinate(10, 10, -100) });  

game.Children.Add(group);  

LayoutRoot.Children.Add(game);  

}  

#region 控制燈光的界面事件  

void LightType_SelectionChanged(object sender, SelectionChangedEventArgs e)  

//選擇一個新的光源之時  

if (_SelectedLight != null)  

_SelectedLight.IsEnabled = false;  

_SelectedLight = ((LightType.SelectedItem as TextBlock).Tag as Light);  

_SelectedLight.IsEnabled = true;  

if (_SelectedLight is OmniLight)  

LightExSetting.Visibility = System.Windows.Visibility.Collapsed;  

else  

LightExSetting.Visibility = System.Windows.Visibility.Visible;  

void slider_axis_ValueChanged(object sender, System.Windows.RoutedPropertyChangedEventArgs&lt;double&gt; e)  

axis_z.Text = ((int)slider_axis_z.Value).ToString();  

_SelectedLight.Position.Z = slider_axis_z.Value;  

axis_y.Text = ((int)slider_axis_y.Value).ToString();  

_SelectedLight.Position.Y = slider_axis_y.Value;  

axis_x.Text = ((int)slider_axis_x.Value).ToString();  

_SelectedLight.Position.X = slider_axis_x.Value;  

StrengthText.Text = slider_Strength.Value.ToString();  

_SelectedLight.Strength = slider_Strength.Value;  

void slider_Offset_ValueChanged(object sender, System.Windows.RoutedPropertyChangedEventArgs&lt;double&gt; e)  

axis_z1.Text = ((int)slider_axis_z1.Value).ToString();   

axis_y1.Text = ((int)slider_axis_y1.Value).ToString();   

axis_x1.Text = ((int)slider_axis_x1.Value).ToString();  

if (_SelectedLight is ViewLight)  

var l = _SelectedLight as ViewLight;  

l.XAngleOffset = slider_axis_x1.Value;  

l.YAngleOffset = slider_axis_y1.Value;  

l.ZAngleOffset = slider_axis_z1.Value;  

var l = _SelectedLight as DirectionalLight;  

var X = slider_axis_x1.Value / slider_axis_x1.Maximum;  

var Y = slider_axis_y1.Value / slider_axis_y1.Maximum;  

var Z = slider_axis_z1.Value / slider_axis_z1.Maximum;  

l.Direction = new Coordinate(X, Y, Z);  

我在其中加入了一些注釋,希望有用:)細心的朋友可能會發現,這次沒有講解有關燈光顔色的問題,下次我專門寫一篇有關顔色的部分,這樣看起來更加直覺,期望各位能夠對Silverlight3D産生一些興趣,加入這個開發方向上來。

本文轉自nowpaper 51CTO部落格,原文連結:http://blog.51cto.com/nowpaper/712291