Поделиться через


Все мы – один маленький мир… как показано на 3D-примере Silverlight 5, Solar Wind

Грег Дункан

Что мне нравится в этом примере, так это его простота, сфокусированность на одной главной теме и то, что он прекрасно выглядит. И есть что-то в рассматривании из космоса нашего маленького шарика из пыли и камней, который взывает к расстроенному космическому путешественнику во мне. [Внести комментарий «Взгляни! Я вижу свой дом отсюда!»]

Solar Wind 3D Sample

clip_image002

Этот пример для Silverlight 5 использует новые трехмерные возможности для создания изображения Земли с переходами дня и ночи, слоями атмосферы и наложениями плотности населения. Он демонстрирует современные концепции множественных отображений, смешения текстур, множественные проходы при рисовании, состояния дискретизатора и освещение.

Прочтите раздел «Построение примера» (чего я, конечно же, не сделал, пока не попытался запустить пример в первый раз… На заметку: RTFP [Read The Fine Post – прочти это прекрасное сообщение]... clip_image004

Построение примера

Чтобы скомпилировать решение необходимо установить DirectX SDK и HLSL Shader Build Task. После чего можно открыть решение в Visual Studio для построения.

Вот другой снимок, показывающий некоторые другие возможности, такие как вращение и наложение магнитного поля.

clip_image006

Решение достаточно прямолинейное, в нем больше файлов с шейдерами и текстурами, чем с кодом...

clip_image008

Вот класс Earth (Земля):

 public Earth()
        {
            Transform = Matrix.CreateWorld(new Vector3(), Vector3.Forward, Vector3.Up);
 
            AtmosphereVisible = true;
            MagneticFieldVisible = false;
            PopulationDensityVisible = false;
            ShowWireframe = false;
        }

Теперь загрузим шейдеры и текстуры:

 void LoadEarthContent()
        {
            // Load mesh
            mesh = new SpherePrimitive(10.0f, 50);
 
            //
            // Load shaders
            //
            earthVertexShader = ContentManager.LoadVertexShader("Shaders/Earth_vs.vs");
            earthPixelShader = ContentManager.LoadPixelShader("Shaders/Earth_ps.ps");
            //
            // Load textures
            //
            dayTexture = ContentManager.LoadTexture("Textures/Earth/EarthDay.png", true);
            nightTexture = ContentManager.LoadTexture("Textures/Earth/EarthNight.png", true);
            nightLightsTexture = ContentManager.LoadTexture("Textures/Earth/EarthNightLights.png", true);
            normalTexture = ContentManager.LoadTexture("Textures/Earth/EarthNormal.png", true);
            maskTexture = ContentManager.LoadTexture("Textures/Earth/EarthMask.png", true);
        }

Вот часть этих текстур:

clip_image010

Рисуем мир…

 public void Draw(GraphicsDevice device, SceneTime time, Camera camera)
        {
            // All Earth pass shaders use the same constants so update them each frame
            UpdateEarthShaderConstants(device, time, camera);
 
            //
            // Pass 1 - Draw Earth
            //
 
            // Set textures in order of samplers
            device.Textures[0] = dayTexture;
            device.Textures[1] = nightTexture;
            device.Textures[2] = nightLightsTexture;
            device.Textures[3] = normalTexture;
            device.Textures[4] = maskTexture;
 
            // Set states to control sampling
            device.SamplerStates[0] = SamplerState.AnisotropicClamp;
            device.SamplerStates[1] = SamplerState.AnisotropicClamp;
            device.SamplerStates[2] = SamplerState.AnisotropicClamp;
            device.SamplerStates[3] = SamplerState.AnisotropicClamp;
            device.SamplerStates[4] = SamplerState.AnisotropicClamp;            
            // Set device states
            device.BlendState = BlendState.Opaque;
            device.RasterizerState = rasterizerState;
 
            // Configure shading pipeline
            device.SetVertexShader(earthVertexShader);
            device.SetPixelShader(earthPixelShader);
 
            // Draw the main earth pass
            mesh.Draw(device);
 
            // Draw atmosphere layer
            if (AtmosphereVisible)
                atmosphereLayer.Draw(device);
 
            // Draw population layer
            if (PopulationDensityVisible)
                populationLayer.Draw(device);
 
            // Draw magnetic field
            if (MagneticFieldVisible)
                field.Draw(device, time, camera);
        }

И, наконец, обновляем по мере вращения мира.

 void UpdateEarthShaderConstants(GraphicsDevice device, SceneTime time, Camera camera)
        {            
            // Get the inverse transpose matrix
            Matrix WorldInverseTransposeMatrix = Matrix.Invert(Transform);
            WorldInverseTransposeMatrix = Matrix.Transpose(WorldInverseTransposeMatrix);
 
            // Set the primary vertex constants
            earthConstants.WorldMatrix = Transform;
            earthConstants.WorldInverseTransposeMatrix = Matrix.Transpose(Matrix.Invert(Transform));
            earthConstants.WorldViewProjectionMatrix = Transform * camera.ViewTransform * camera.ProjectionTransform;
            earthConstants.ViewInverseMatrix = Matrix.Invert(camera.ViewTransform);
            earthConstants.TotalSeconds.X = (float)time.TotalTime.TotalSeconds;
            device.SetVertexShaderConstantFloat4(0, ref earthConstants);
 
            // Set the pixel shader constants (to achieve solid lighting in wireframe mode)
            if(ShowWireframe)
                device.SetPixelShaderConstantFloat4(0, ref showWireframeValue);
            else
                device.SetPixelShaderConstantFloat4(0, ref hideWireframeValue);
        }

Если вы хотите взглянуть на трехмерные возможности Silverlight 5, то этот или другие примеры из сессии MIX11 Silverlight 3D должны быть полезны…

Несколько ссылок, которые могут оказаться интересными: