Silverlight C# 游戏开发:L5 3D基本的灯光

我们在设计和开发3D的时候最常用的就是灯光,它有的时候比摄像机还要重要,一些花哨漂亮的表现主要通过灯光实现,相比场景中只有一个的主要摄像机以外,灯光的类型和内容更加丰富,今天暂用小段时间一起研究一下Silverlight3D当中的灯光。下图是具体实现的预览效果:

Silverlight C# 游戏开发:L5 3D基本的灯光

在开始之前,需要了解一下基本的灯光类型,Balder3D里有三种灯光类型,分别是OmniLight、ViewLight、DirectionalLight,如果玩过3Dmax的朋友应该是相当的熟悉,这些光的表现形式组合构成了游戏世界的绚丽多彩,没有光的世界大家可以通过最后程序实验一下,看看会如何呢。

OmniLight:也称泛光灯或者点光,比较清楚理解,它就是一个点发出的光源

ViewLight:有了方向和目标,除了这个方向方位之内的都不会被照亮

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

具体内容可以参考下面的图片说明来理解他们,图片截取自3DMAX,资源来源于网络。

Silverlight C# 游戏开发:L5 3D基本的灯光

有一个好看的灯光,固然重要,但是我们要先学会如何控制它们,今次的代码比较多,涉及到了界面的操作,我将Lesson05代码全部贴上,我的建议还是下载源文件看比较好一些:)

首先新建Lesson05这个控件,XAML代码如下:(下述代码使用Blend工具制作生成) 

Lesson05.xaml
< 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" >
    
    
< Grid  Background ="White" >
        
< Grid  x:Name ="LayoutRoot" />
        
< StackPanel  HorizontalAlignment ="Left"  Orientation ="Vertical"  VerticalAlignment ="Top"  Width ="199"  Height ="132" >
            
< StackPanel  Orientation ="Horizontal" >
                
< TextBlock  TextWrapping ="Wrap"  Text ="X轴"  Width ="38"  Height ="14" />
                
< Slider  Height ="23"  x:Name ="slider_axis_x"  SmallChange ="1"  Maximum ="100"  LargeChange ="10"  Margin ="0"  Width ="100"  Minimum ="-100"   />
                
< TextBlock  x:Name ="axis_x"  TextWrapping ="Wrap"  Width ="38"  Height ="14"  Text ="0" />
            
</ StackPanel >
            
< StackPanel  Orientation ="Horizontal" >
                
< TextBlock  TextWrapping ="Wrap"  Width ="38"  Height ="14" >< Run  Text ="Y" />< Run  Text ="轴" /></ TextBlock >
                
< Slider  Height ="23"  x:Name ="slider_axis_y"  SmallChange ="1"  Maximum ="100"  LargeChange ="10"  Margin ="0"  Width ="100"  Minimum ="-100"   />
                
< TextBlock  x:Name ="axis_y"  TextWrapping ="Wrap"  Width ="38"  Height ="14"  Text ="0" />
            
</ StackPanel >
            
< StackPanel  Orientation ="Horizontal" >
                
< TextBlock  TextWrapping ="Wrap"  Width ="38"  Height ="14" >< Run  Text ="Z" />< Run  Text ="轴" /></ TextBlock >
                
< Slider  Height ="23"  x:Name ="slider_axis_z"  SmallChange ="1"  Maximum ="100"  LargeChange ="10"  Margin ="0"  Width ="100"  Minimum ="-100"   />
                
< TextBlock  x:Name ="axis_z"  TextWrapping ="Wrap"  Width ="38"  Height ="14"  Text ="0" />
            
</ StackPanel >
            
< StackPanel  Orientation ="Horizontal" >
                
< TextBlock  TextWrapping ="Wrap"  Width ="38"  Height ="14"  Text ="亮度" />
                
< Slider  Height ="23"  x:Name ="slider_Strength"  Maximum ="2"  LargeChange ="0.1"  Margin ="0"  Width ="100"  Value ="1"   />
                
< TextBlock  x:Name ="StrengthText"  Width ="38"  Height ="14"  Text ="1" />
            
</ StackPanel >
            
< StackPanel  Orientation ="Horizontal" >
                
< TextBlock  TextWrapping ="Wrap"  Width ="38"  Height ="14"  Text ="类型" />
                
< ComboBox  x:Name ="LightType"  Width ="98" />
            
</ StackPanel >
        
</ StackPanel >
        
< StackPanel  x:Name ="LightExSetting"  HorizontalAlignment ="Left"  Orientation ="Vertical"  VerticalAlignment ="Top"  Width ="199"  Height ="132"  Margin ="198,0,-2,0"  Visibility ="Collapsed" >
            
< StackPanel  Orientation ="Horizontal" >
                
< TextBlock  TextWrapping ="Wrap"  Text ="偏移/方向X"  Width ="64"  Height ="14" />
                
< Slider  Height ="23"  x:Name ="slider_axis_x1"  SmallChange ="1"  Maximum ="100"  LargeChange ="10"  Margin ="0"  Width ="100"  Minimum ="-100"   />
                
< TextBlock  x:Name ="axis_x1"  TextWrapping ="Wrap"  Width ="38"  Height ="14"  Text ="0" />
            
</ StackPanel >
            
< StackPanel  Orientation ="Horizontal" >
                
< TextBlock  TextWrapping ="Wrap"  Width ="64"  Height ="14" >< Run  Text ="偏移/方向" />< Run  Text ="Y" /></ TextBlock >
                
< Slider  Height ="23"  x:Name ="slider_axis_y1"  SmallChange ="1"  Maximum ="100"  LargeChange ="10"  Margin ="0"  Width ="100"  Minimum ="-100"   />
                
< TextBlock  x:Name ="axis_y1"  TextWrapping ="Wrap"  Width ="38"  Height ="14"  Text ="0" />
            
</ StackPanel >
            
< StackPanel  Orientation ="Horizontal" >
                
< TextBlock  TextWrapping ="Wrap"  Width ="64"  Height ="14" >< Run  FontFamily ="Verdana, Arial, Arial Unicode MS, Lucida Sans Unicode, Lucida Grande"  Text ="偏移/方向" />< Run  FontFamily ="Verdana, Arial, Arial Unicode MS, Lucida Sans Unicode, Lucida Grande"  Text ="Z" /></ TextBlock >
                
< Slider  Height ="23"  x:Name ="slider_axis_z1"  SmallChange ="1"  Maximum ="100"  LargeChange ="10"  Margin ="0"  Width ="100"  Minimum ="-100"   />
                
< TextBlock  x:Name ="axis_z1"  TextWrapping ="Wrap"  Width ="38"  Height ="14"  Text ="0" />
            
</ StackPanel >
            
< StackPanel  Orientation ="Horizontal"  Visibility ="Collapsed" >
                
< TextBlock  TextWrapping ="Wrap"  Width ="38"  Height ="14"  Text ="亮度" />
                
< Slider  Height ="23"  x:Name ="slider_Strength1"  Maximum ="1"  LargeChange ="0.1"  Margin ="0"  Width ="100"  Value ="1"   />
                
< TextBlock  x:Name ="StrengthText1"  Width ="38"  Height ="14"  Text ="1" />
            
</ StackPanel >
        
</ StackPanel >
    
</ Grid >
</ UserControl >

 

Lesson05.xaml.cs代码如下,具体实现请参照Lesson04的讲述

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 < double > (slider_axis_ValueChanged);
            slider_axis_y.ValueChanged 
+=   new  System.Windows.RoutedPropertyChangedEventHandler < double > (slider_axis_ValueChanged);
            slider_axis_z.ValueChanged 
+=   new  System.Windows.RoutedPropertyChangedEventHandler < double > (slider_axis_ValueChanged);
            slider_Strength.ValueChanged 
+=   new  System.Windows.RoutedPropertyChangedEventHandler < double > (slider_axis_ValueChanged);

            slider_axis_x1.ValueChanged 
+=   new  System.Windows.RoutedPropertyChangedEventHandler < double > (slider_Offset_ValueChanged);
            slider_axis_y1.ValueChanged 
+=   new  System.Windows.RoutedPropertyChangedEventHandler < double > (slider_Offset_ValueChanged);
            slider_axis_z1.ValueChanged 
+=   new  System.Windows.RoutedPropertyChangedEventHandler < double > (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);
            
#region  L1 - L4的代码
            
// 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);
            
// L4
            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);
            
#endregion

        }
        
#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 < double >  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 < double >  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;
            }
            
else
            {
                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);
            }
        }

        
#endregion
    }
}

 

我在其中加入了一些注释,希望有用:)细心的朋友可能会发现,这次没有讲解有关灯光颜色的问题,下次我专门写一篇有关颜色的部分,这样看起来更加直观,期望各位能够对Silverlight3D产生一些兴趣,加入这个开发方向上来。

好吧下一步让我们看看运行效果,同时附送本文章的源代码点击这里下载。

获取 Microsoft Silverlight

工程中如果缺少Balder.dll请在这里快速下载:SL4_Balder.rar

推荐Silverlight游戏开发博客:深蓝色右手

free counters 

你可能感兴趣的:(silverlight)