Help again :) SkyBox

Jun 22, 2009 at 10:43 PM

Hello and sorry for this posts :)

I try create a skybox whith a FirstPersonControlledCamera3D. It almost functioned, I am with two problems

How i create a dds file texture? And when i move my camera, skybox hide, see in links above skyboxOn and Hide.

http://cid-86c6502771b482be.skydrive.live.com/self.aspx/XNA -> Images here

Show my source code:

public class Game1 : Application
    {
        private FirstPersonControlledCamera3D camera;
        private DrawTargetScreen drawToScreen;
        GraphicsDevice graphics;
        private TextElement status;

        public string NomeUsuario { get; set; }

        private Stopwatch tempoExecucao = new Stopwatch();
        //private ListaUsuarios usuarios = new ListaUsuarios();

        SpriteBatch spriteBatch;
        Texture2D star;
        private VertexStarSprite[] starArray;

        private Effect spritesEffect;
        private VertexDeclaration starSpriteVertexDeclaration;

        private float currentSparkle = 0.0f;

        private Matrix View, Projection;

        Vector3 camPos;

        SkyBox sky;

        protected override void LoadContent(DrawState state, ContentManager manager)
        {
            sky = new SkyBox(manager, camera);
            drawToScreen.Add(sky);
            graphics = state.BeginGetGraphicsDevice(Xen.Graphics.State.StateFlag.None);
            status.Font = manager.Load<SpriteFont>("Arial");
            #region Teste
            }

        protected override void UnloadContent(DrawState state)
        {
           
            base.UnloadContent(state);
        }

        protected override void Draw(DrawState state)
        {
            status.Text.Clear();
            status.Text += string.Format("{0} FPS", state.ApproximateFrameRate);

            if (camera.Projection.FieldOfView > 3.14f)
                camera.Projection.FieldOfView = 3.14f;

            

            drawToScreen.Draw(state);

            //DrawStars();
        }

        
        protected override void Initialise()
        {
            tempoExecucao.Start();

            //usuarios.Carregar(@"C:\TesteXNA\LFPlanetasUsuarios.xml");
            camera = new FirstPersonControlledCamera3D(this.UpdateManager, Vector3.Zero, true);
            camera.MovementSensitivity *= 0.1f;
            camera.LookAt(new Vector3(20, 0, 0), new Vector3(688, -656, 28), new Vector3(0, 0, 0));
            //camera.LookAt(new Vector3(20, 0, 0), new Vector3(0, 0, 0), new Vector3(0, 0, 0));
            drawToScreen = new DrawTargetScreen(this, camera);
            drawToScreen.ClearBuffer.ClearColour = Color.Black;

            // Sol
            var sol = new SphereDrawer("Sol", new Vector3(-200, 1, 1), new Vector3(200.0f, 200.0f, 200.0f), Content);
            var mercurio = new SphereDrawer("Mercurio", new Vector3(150, 1, 1), new Vector3(2.9f, 2.9f, 2.9f), Content);
            var venus = new SphereDrawer("Venus", new Vector3(200, 1, 1), new Vector3(7.0f, 7.0f, 7.0f), Content);
            var terra = new SphereDrawer("Terra", new Vector3(300, 1, 1), new Vector3(7.3f, 7.3f, 7.3f), Content);
            var marte = new SphereDrawer("Marte", new Vector3(350, 0, 1), new Vector3(3.9f, 3.9f, 3.9f), Content);
            var jupiter = new SphereDrawer("Jupiter", new Vector3(500, 1, 1), new Vector3(82.1f, 82.1f, 82.1f), Content);
            var saturno = new SphereDrawer("Saturno", new Vector3(700, 1, 1), new Vector3(69.0f, 69.0f, 69.0f), Content);
            var urano = new SphereDrawer("Urano", new Vector3(900, 1, 1), new Vector3(29.2f, 29.2f, 29.2f), Content);
            var neturno = new SphereDrawer("Neturno", new Vector3(1000, 1, 1), new Vector3(27.9f, 27.9f, 27.9f), Content);
            var plutao = new SphereDrawer("Plutao", new Vector3(1100, 1, 1), new Vector3(1.3f, 1.3f, 1.3f), Content);

            drawToScreen.Add(sol);
            drawToScreen.Add(mercurio);
            drawToScreen.Add(venus);
            drawToScreen.Add(terra);
            drawToScreen.Add(marte);
            drawToScreen.Add(jupiter);
            drawToScreen.Add(saturno);
            drawToScreen.Add(urano);
            drawToScreen.Add(neturno);
            drawToScreen.Add(plutao);

            status = new TextElement();
            status.Position = new Vector2(10, -10);
            drawToScreen.Add(status);

            //SkyBox skyBox = new SkyBox(Content, new Camera3D());
            //drawToScreen.Add(skyBox);
        }

        protected override void Update(UpdateState state)
        {
            if (state.PlayerInput[PlayerIndex.One].InputState.Buttons.Back.OnPressed)
                Shutdown();

            float wheelDelta = state.MouseState.ScrollWheelDelta;

            if (wheelDelta > 1)
                wheelDelta = -1;
            if (wheelDelta < -1)
                wheelDelta = 1;

            var total = 1.0f + wheelDelta * 0.1f;

            camera.Projection.FieldOfView *= total;


            currentSparkle += 0.04f;
            if (currentSparkle > 1.0f)
            {
                currentSparkle -= 1.0f;
            }
        }

        protected override void SetupGraphicsDeviceManager(GraphicsDeviceManager graphics, ref RenderTargetUsage presentation)
        {
            if (graphics != null)
            {
                graphics.PreferredBackBufferWidth = 800;
                graphics.PreferredBackBufferHeight = 640;
            }
        }
    }
public class SkyBox : IDraw
    {
        Sphere sphere;
        ModelInstance skysphere;
        ICamera camera;
        TextureCube skytexture;
        ContentManager content;
        SkyboxTechnique shader;
        
        Matrix world;

        public SkyBox(ContentManager content, Camera3D camera)
        {
            sphere = new Sphere(new Vector3(1, 1, 1), 32);
            this.camera = camera;
            this.content = content;
            skytexture = content.Load<TextureCube>(@"uffizi_cross");
            skysphere = new ModelInstance();
            skysphere.ModelData = content.Load<ModelData>(@"SphereHighPoly");
            world = Matrix.CreateTranslation(Vector3.Zero);
        }

        public void SetCamera(ICamera camera)
        {
            this.camera = camera;
        }


        public void Draw(DrawState state)
        {
            shader = state.GetShader<SkyboxTechnique>();
            shader.SkyboxTexture = skytexture;
            var provider = new ModelInstanceShaderProvider<SkyboxTechnique>(shader);
            skysphere.SetShaderOverride(provider);

            state.PushRenderState();
            state.RenderState.DepthColourCull.CullMode = CullMode.None;
            state.RenderState.DepthColourCull.DepthWriteEnabled = false;

            skysphere.Draw(state);

            state.PopRenderState();

        }

        public bool CullTest(ICuller culler)
        {
            return true;
        }

    }
TKX

Jun 23, 2009 at 12:28 AM

About creating a DDS file, install the DirectX SDK. right-click on your image file and select the "Convert to file format..." option. By default it'll save as a DDS. That one way of doing it...

Coordinator
Jun 23, 2009 at 1:20 AM

Hi.
Sorry I haven't been able to reply quickly. I've got a nasty cold right now so I'm mostly out of action.

The problem here is pretty simple.
You are drawing the skybox with a ModelInstance, and using a custom shader which ignores the world matrix and projects the vertices to 'infinity' or in this case, the back clip plane.

The problem is a ModelInstance still performs cull tests. Afterall you don't want it drawing when it's offscreen. However it doesn't know that the shader it's using is changing where it's drawn.

To show this more clearly, here is what it looks like without using the custom shader (I've hidden the sun):

That tiny single pixel dot in the centre of the screen? That's the skybox. It's at the origin.

So it should come as no surprise, if you rotate the camera away, the dot eventually goes off screen and the ModelInstance internal geometry culltest fails (even though there is only one piece of geometry - however it makes sense for me to ignore this case as it's redundant to the model CullTest).

So the solution? Well there are a few ways to deal with this problem.
The easiest, however, is to make sure the model is always technically on screen.
This can be done by always drawing it at the same position as the camera. Even though this has no visual impact on how the model is drawn (as it has a shader which ignores the world matrix).

	Vector3 cameraPos;
	state.Camera.GetCameraPosition(out cameraPos);

	state.PushWorldTranslate(ref cameraPos);

	skysphere.Draw(state);

	state.PopWorldMatrix();
Jun 23, 2009 at 11:50 AM

Hello and tkx for all :)

I try directx sdk and this code tonight!

[]´s

Jun 24, 2009 at 3:11 AM

Hello, tkx for all again

Iarus and StatusUnknow, all work´s fine.

\o/

Tkx, tkx, tkx