zoukankan      html  css  js  c++  java
  • Silverlight C# 游戏开发:L8 材质和贴图

    对于3D来说,主要的组成要素是:模型、灯光、摄像机,模型中的贴图部分不容忽视,贴图为模型带来生命力,在游戏开发当中非常重要,了解贴图的方式可以帮助我们作出,这一篇主要是说有关于贴图方面的内容。下面是今天的实例:

    记得有一位朋友曾经说过,3D世界总会回归到2D当中,此话很有道理,无论我们怎么构建3D世界仍然还只是在面前的屏幕上显示,而这个就是典型的3D到2D,其实,我们都被欺骗了,所有看到的都不是真正意义上的3D世界,是通过计算出来的结果,伟大的数学在这里发挥到了极致,就如Balder就是典型的通过计算的方式将3D控件渲染到Silverlight的平面上,只要对3D数学有一定的了解,都可以作出一个3D世界,说了这些有什么用呢?和贴图有很大的关系,大部分的开发者可能只是知道“贴”却对其原理一知半解,贴图的英文一般称之是Texture,贴图仅仅是另外一个子集下面的一个部分,而这个更大的集合是材质Material,要知道,世间万物并非仅仅只有纹理,它包含了诸如漫反射(diffuse)和反射(reflection)的属性,所以你仔细看某一个事物的时候,在不同的时空看到的结果不是一样。如果讨论3D世界,我想可能也非一时之事,今天咱们就之说说材质。

    下面展示了一个3D世界中的典型材质赋予方式:

     

    在Balder当中,Balder.Objects.Geometries对象都带有Material属性,只要对这个属性进行设置即可。

    material = new Material();
    Balder.Imaging.Image image = Runtime.Instance.ContentManager.Load<Balder.Imaging.Image>("/Balder_Studio;component/Res/map01.jpg");
    material.DiffuseMap 
    = new ImageMap(image) ;
    material.DiffuseMapOpacity 
    = 1;
    material.Opacity 
    = 1;
    material.DoubleSided 
    = true;

    上面的代码是创建一个基本的材质,然后从资源中读取一个贴图给Diffuse上,上次有位朋友问我如何在Balder中读取一个图片,其方式就是上面的方式,需要提醒的是,现在这种方法只能读取自身工程的文件,如果是外部的话,就会报错。

    好吧,其实今天所有的核心就在上面的几行代码当中,下面仅仅是做了控制,现在我们弄一个UI控制界面,来操作材质和贴图使我们更加直观。

     

    为了方便起见,这次用上了属性绑定,界面的XAML如下:

    界面
    <UserControl
        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"
        xmlns:local
    ="clr-namespace:Balder_Studio" x:Class="Balder_Studio.Lesson08"
        mc:Ignorable
    ="d"
        d:DesignHeight
    ="441" d:DesignWidth="550">    
        
    <Grid>        
            
    <Grid x:Name="LayoutRoot" Background="White" d:IsLocked="True"/>
            
    <StackPanel Margin="12,8,0,0" HorizontalAlignment="Left" Height="218" VerticalAlignment="Top">
                
    <StackPanel Margin="0" Orientation="Horizontal" Visibility="Collapsed">
                    
    <TextBlock Margin="0,9,0,0" FontSize="12" Width="118"><Run Text="贴图透明度"/></TextBlock>
                    
    <Slider x:Name="SliderOpacity" Value="1" Width="140" Maximum="1" LargeChange="0.2"/>
                    
    <TextBlock x:Name="TextValue" Text="{Binding Value, ElementName=SliderOpacity}" Margin="0,9,0,0" FontSize="12" Width="71"/>
                
    </StackPanel>
                
    <StackPanel Height="28" Orientation="Horizontal" VerticalAlignment="Bottom">
                    
    <TextBlock Margin="0,8,0,0" FontSize="12" Width="118" Text="贴图"/>
                    
    <ComboBox x:Name="DiffuseMapSel" Width="140">
                    
    </ComboBox>
                    
    <Button Content="清理贴图" Width="60" Click="Button_Click_ClearDiffuseMap"></Button>
                
    </StackPanel>
                
    <StackPanel Margin="0" Orientation="Horizontal">
                    
    <TextBlock Margin="0,9,0,0" FontSize="12" Width="118"><Run Text="贴图"/><Run Text="透明度"/></TextBlock>
                    
    <Slider x:Name="SliderDOpacity" Width="140" Maximum="1" Value="1" LargeChange="0.2"/>
                    
    <TextBlock Text="{Binding Value, ElementName=SliderDOpacity}" Margin="0,9,0,0" FontSize="12" Width="71"/>
                
    </StackPanel>
                
    <StackPanel Height="28" Orientation="Horizontal" VerticalAlignment="Bottom">
                    
    <TextBlock Margin="0,8,0,0" FontSize="12" Width="118" Text="反射贴图"/>
                    
    <ComboBox x:Name="ReflectionMapSel" Width="140"/>
                    
    <Button Content="清理贴图" Width="60" Click="Button_Click_ClearReflectionMap"></Button>
                
    </StackPanel>
                
    <StackPanel Margin="0" Orientation="Horizontal">
                    
    <TextBlock Margin="0,9,0,0" FontSize="12" Width="118"><Run Text="反射"/><Run Text="贴图"/><Run Text="透明度"/></TextBlock>
                    
    <Slider x:Name="SliderROpacity" Width="140" Maximum="1" Value="1" LargeChange="0.2"/>
                    
    <TextBlock Text="{Binding Value, ElementName=SliderROpacity}" Margin="0,9,0,0" FontSize="12" Width="71"/>
                
    </StackPanel>
            
    </StackPanel>        
        
    </Grid>
    </UserControl>

    然后后台代码如下,做了简单的注释,相信各位高手会明白的。

    后台代码
    //////////////////////////////////////////////////
    // Silvery Night
    // Nowpaper原创Silverlight Balder3D文章,共同研究和探讨:)
    // 
    // http://www.nowpaper.net
    // http://www.cnblogs.com/nowpaper
    //////////////////////////////////////////////////
    using System;
    using System.Windows.Threading;
    using System.Windows.Controls;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using Balder.Math;
    using Balder.Objects.Geometries;
    using Balder.View;
    using Balder.Lighting;
    using Balder.Execution;
    using System.Windows;
    using System.Windows.Resources;
    using Balder.Materials;
    using Balder.Assets;
    using System.Windows.Data;
    using System.Collections.Generic;

    namespace Balder_Studio
    {
        
    public partial class Lesson08 : UserControl
        {
            
    //Heightmap
            Heightmap heightmap = new Heightmap();
            Camera camera 
    = new Camera();
            
    //材质
            Material material = new Material();
            
    //贴图文件列表
            public List<string> ImageList = new List<string>()
            {
                
    "/Balder_Studio;component/Res/map01.jpg",
                
    "/Balder_Studio;component/Res/map02.jpg",
                
    "/Balder_Studio;component/Res/map03.jpg",
                
    "/Balder_Studio;component/Res/map04.jpg"
            };
            
    public Lesson08()
            {
                InitializeComponent();

                InitializeUILogic();

                
    //L1
                Game game = new Game() { Width = 600, Height = 400 };
                game.Camera 
    = camera;
                game.Camera.Position 
    = new Coordinate(100120150);
                game.Camera.Target 
    = new Coordinate(000);
                game.Children.Add(
    new OmniLight()
                {
                    Position 
    = new Coordinate(01000),
                    Ambient 
    = Colors.Transparent,
                    Specular 
    = Colors.Transparent,
                    Diffuse 
    = Colors.Transparent,
                    Strength 
    = 0.55,
                });
                
    //L3
                Game_Axis axis_x = new Game_Axis(new Vertex(-30000), new Vertex(30000), Colors.Red);
                Game_Axis axis_y 
    = new Game_Axis(new Vertex(0-3000), new Vertex(03000), Colors.Blue);
                Game_Axis axis_z 
    = new Game_Axis(new Vertex(00-300), new Vertex(00300), Colors.Green);
                game.Children.Add(axis_x);
                game.Children.Add(axis_y);
                game.Children.Add(axis_z);

                
                heightmap.Dimension 
    = new Dimension() { Width = 128, Height = 128 };
                heightmap.LengthSegments 
    = 2;
                heightmap.HeightSegments 
    = 2;
                heightmap.InteractionEnabled 
    = true;

                
    //L8
                
    //从位图中创建高度图
                CreateHeightMapFormBitmap(new Uri("/Balder_Studio;component/Res/heightmap.jpg", UriKind.Relative));
                
    //通过ContentManager读取指定贴图
                Balder.Imaging.Image image = Runtime.Instance.ContentManager.Load<Balder.Imaging.Image>("/Balder_Studio;component/Res/map01.jpg");
                
    //漫反射贴图
                material.DiffuseMap = new ImageMap(image) ;
                
    //漫射贴图透明度
                material.DiffuseMapOpacity = 1;
                
    //材质透明度
                material.Opacity = 1;
                
    //双面材质
                material.DoubleSided = true;
                
    //将材质附上
                heightmap.Material = material;

                game.Children.Add(heightmap);

                LayoutRoot.Children.Add(game);

                
    this.KeyDown += new System.Windows.Input.KeyEventHandler(Lesson08_KeyDown);            
            }
            
    //初始化UI
            private void InitializeUILogic()
            {            
                
    foreach (var item in ImageList)
                {
                    Image image 
    = new Image() { Width = 128, Height = 128 };
                    Image image1 
    = new Image() { Width = 128, Height = 128 };
                    image1.Source 
    = image.Source = new BitmapImage(new Uri(item, UriKind.Relative));
                    DiffuseMapSel.Items.Add(image);
                    ReflectionMapSel.Items.Add(image1);
                }
                DiffuseMapSel.SelectionChanged 
    += new SelectionChangedEventHandler(MapSel_SelectionChanged);
                ReflectionMapSel.SelectionChanged 
    += new SelectionChangedEventHandler(MapSel_SelectionChanged);
                SliderOpacity.ValueChanged 
    += new RoutedPropertyChangedEventHandler<double>(SliderOpacity_ValueChanged);
                SliderDOpacity.ValueChanged 
    += new RoutedPropertyChangedEventHandler<double>(SliderOpacity_ValueChanged);
                SliderROpacity.ValueChanged 
    += new RoutedPropertyChangedEventHandler<double>(SliderOpacity_ValueChanged);
            }        

            
    void MapSel_SelectionChanged(object sender, SelectionChangedEventArgs e)
            {
                var comboBox 
    = sender as ComboBox;
                
    if(comboBox.SelectedIndex == -1)
                    
    return;
                var filename 
    = ImageList[comboBox.SelectedIndex];
                Balder.Imaging.Image image;
                image 
    = Runtime.Instance.ContentManager.Load<Balder.Imaging.Image>(filename);
                
    if (sender == DiffuseMapSel)
                {
                    material.DiffuseMap 
    = new ImageMap(image);
                }
                
    else
                {
                    
    if (ReflectionMapSel == sender) 
                    {
                        material.ReflectionMap 
    = new ImageMap(image);
                    }
                }
            }       

            
    void SliderOpacity_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
            {
                
    if (sender == SliderOpacity)
                {
                    material.Opacity 
    = e.NewValue;
                }
                
    else
                {
                    
    if (sender == SliderDOpacity)
                    {
                        material.DiffuseMapOpacity 
    = e.NewValue;
                    }
                    
    else
                    {
                        
    if (sender == SliderROpacity)
                        {
                            material.ReflectionMapOpacity 
    = e.NewValue;
                        }
                    }
                }
            }
            
            
    void Lesson08_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
            {
                
    switch (e.Key)
                {
                    
    case System.Windows.Input.Key.W:
                        {
                            var c 
    = camera.Target - camera.Position;
                            camera.Position 
    += c / 10;
                            camera.Target 
    += c / 10;
                        }
                        
    break;
                    
    case System.Windows.Input.Key.S:
                        {
                            var c 
    = camera.Target - camera.Position;
                            camera.Position 
    -= c / 10;
                            camera.Target 
    -= c / 10;
                        }
                        
    break;
                }
            }

            

            
    //从位图中创建高度图
            void CreateHeightMapFormBitmap(Uri uri)
            {
                BitmapImage bitmap 
    = new BitmapImage();
                
    //从资源中取得BitmapStream
                StreamResourceInfo sri = Application.GetResourceStream(uri);
                bitmap.SetSource(sri.Stream);
                
    //生成WriteableBitmap
                WriteableBitmap writeablebitmap = new WriteableBitmap(bitmap);
                
    //创建高度图数组
                float[,] HeightmapArray = new float[bitmap.PixelHeight, bitmap.PixelWidth];
                
    //将数组拷贝到高度图数组
                for (int i = 0; i < bitmap.PixelHeight; i++)
                {
                    
    for (int j = 0; j < bitmap.PixelWidth; j++)
                    {
                        
    int index = bitmap.PixelWidth * i + j;
                        
    int pixel = writeablebitmap.Pixels[index];
                        
    byte[] bytes = BitConverter.GetBytes(pixel);
                        
    //计算:颜色越深则越低,颜色月浅则越高,50是最高的高度值
                        HeightmapArray[i, j] = ((float)(bytes[0+ bytes[1+ bytes[2]) / 3/ 255 * 50;
                    }
                }
                
    //赋值
                heightmap.HeightmapArray = HeightmapArray;
            }

            
    private void Button_Click_ClearDiffuseMap(object sender, RoutedEventArgs e)
            {
                heightmap.Material.DiffuseMap 
    = null;
            }

            
    private void Button_Click_ClearReflectionMap(object sender, RoutedEventArgs e)
            {
                heightmap.Material.ReflectionMap 
    = null;
            }
        }
    }

    好了,我们下面看看效果,使用上述代码实现即可,可以点击直接下载工程浏览和测试,那么运行的预览效果如下:

    获取 Microsoft Silverlight

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

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

  • 相关阅读:
    2019.1.10英语笔记
    2019.1.9专业课笔记
    团队触发器
    团队脚本备份
    导表
    oslo.config
    nginx启动、重启、关闭
    常见的awk内建变量
    LVM
    Django, one-to-many, many-to-many
  • 原文地址:https://www.cnblogs.com/nowpaper/p/1942354.html
Copyright © 2011-2022 走看看