Solar Wind 3D Sample

This sample for Silverilght 5 uses the new 3D features to draw the Earth with day and night transitions, atmosphere layers, and population density overlays. It demonstrates advanced concepts like mipmaps, texture blending, multiple drawing passes, sampler states...

C# (10.4 MB)
 
 
 
 
 
4.4 Star
(8)
9,128 times
Add to favorites
9/12/2011
E-mail Twitter del.icio.us Digg Facebook
// ===================================================================================
//  Copyright (c) Microsoft Corporation.  All rights reserved.
//  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
//  OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
//  LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
//  FITNESS FOR A PARTICULAR PURPOSE.
// ===================================================================================
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Media.Imaging;
using System.Windows.Resources;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Primitives3D;

namespace SolarWind
{
    /// <summary>
    /// An overlay showing population data around the globe
    /// </summary>
    public class EarthPopulationLayer
    {
        /// <summary>
        /// The slightly more dense mesh representing the population overlay
        /// </summary>
        SpherePrimitive populationMesh;

        /// <summary>
        /// Vertex shader
        /// </summary>
        VertexShader vertexShader;

        /// <summary>
        /// Pixel shader
        /// </summary>
        PixelShader pixelShader;

        /// <summary>
        /// Population texture
        /// </summary>
        Texture2D populationTexture;

        public EarthPopulationLayer()
        {
        }

        /// <summary>
        /// Creates the overlay mesh, extrudes it from a bitmap containing
        /// population data, and loads the texture and shaders
        /// </summary>
        public void LoadContent()
        {
            // Load bitmap for texture sampling on the CPU.
            // SM2 doesn't support texture sampling in vertex
            // shaders or it would have been better to do this there.
            var stream = ContentManager.GetResourceStream("Textures/Earth/EarthPopulation.png");
            BitmapImage bitmap = new BitmapImage();
            bitmap.SetSource(stream);
            var populationBitmap = new WriteableBitmap(bitmap);

            // Create population mesh
            populationMesh = new SpherePrimitive(10.01f, 120);

            // Extrude population normals
            const float densityFactor = 0.25f;
            var vertices = populationMesh.Vertices;
            for (int i = 0; i < vertices.Count; i++)
            {
                // copy vertex
                var vertex = vertices[i];

                // sample texture
                int x = (int)((float)(populationBitmap.PixelWidth - 1) * vertex.TextureCoordinate.X);
                int y = (int)((float)(populationBitmap.PixelHeight - 1) * vertex.TextureCoordinate.Y);

                int pixel = populationBitmap.Pixels[y * populationBitmap.PixelWidth + x];
                int r = (pixel >> 16) & 255;
                int g = (pixel >> 8)  & 255;
                int b = (pixel >> 0)  & 255;
                int a = (pixel >> 24) & 255;

                // calculate density from 0.0 to 1.0 based on color value
                float density = 0.0f;
                int color = ((255 - r) + (227 - g) + (141 - b));
                density = (float)color / 454.0f; // 454 is the max density color value (169,0,0) plugged in above 

                // apply alpha mask
                float alpha = (float)a / (float)255;
                if (a < 200) alpha = 0.0f;
                density *= alpha;

                // move vertex along normal according to population density
                vertex.Position += vertex.Normal * density * densityFactor;

                // update vertex
                vertices[i] = vertex;
            }
            populationMesh.Reload();

            // Load shaders
            pixelShader = ContentManager.LoadPixelShader("Shaders/Population_ps.ps");
            vertexShader = ContentManager.LoadVertexShader("Shaders/Earth_vs.vs");

            // Load texture and mipmap
            populationTexture = ContentManager.LoadTexture("Textures/Earth/EarthPopulation.png", true);
        }

        /// <summary>
        /// Draws the population overlay. Shader constants are the same as earlier passes.
        /// </summary>
        /// <param name="device">Graphics device</param>
        public void Draw(GraphicsDevice device)
        {
            device.SetVertexShader(vertexShader);
            device.SetPixelShader(pixelShader);
            device.Textures[0] = populationTexture;
            device.SamplerStates[0] = SamplerState.LinearClamp;
            device.BlendState = BlendState.Additive;
            
            populationMesh.Draw(device);
        }
    }
}