Autor Wątek: Problem z wyświetlaniem modelu w XNA 4  (Przeczytany 5281 razy)

Offline VillageRaper

  • Użytkownik

# Kwiecień 20, 2013, 13:46:02
Cześć
Mam pewien problem z wyświetlaniem mojego modelu w XNA 4.0.
Tak wygląda mój aktualny kod:
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace Aplikacja3D2
{
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        AlphaTestEffect pixelShader;
        Model model;
        Vector3 modelPosition = Vector3.Zero;
        Vector3 cameraPosition = new Vector3(500f, 250.0f, -350.0f);
        float modelRotation = 0.0f;
        float aspectRatio;
        MouseState state;
        int fullscreen;
        int windowed;
        //  int hold;
        public Game1()
        {

            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
            fullscreen = 1;
            windowed = 0;
            // hold = 0;
        }
        protected override void Initialize()
        {
            base.Initialize();

            spriteBatch = new SpriteBatch(GraphicsDevice);

            pixelShader = new AlphaTestEffect(graphics.GraphicsDevice);


            model = Content.Load<Model>("Models\\fiat");

            this.graphics.PreferredBackBufferWidth = GraphicsDevice.DisplayMode.Width;
            this.graphics.PreferredBackBufferHeight = GraphicsDevice.DisplayMode.Height;
            this.graphics.IsFullScreen = true;
            this.graphics.ApplyChanges();
            aspectRatio = graphics.GraphicsDevice.Viewport.AspectRatio;
            Window.Title = "Aplikacja 3D";
        }
        protected override void LoadContent()
        {
        }
        protected override void UnloadContent()
        {
        }
        protected override void Update(GameTime gameTime)
        {
            if (Keyboard.GetState().IsKeyDown(Keys.Escape))
                this.Exit();

            if (Mouse.GetState().ScrollWheelValue > state.ScrollWheelValue)
            {
                cameraPosition += new Vector3(0.0f, -5.0f, 0.0f);
            }
            if (Mouse.GetState().ScrollWheelValue < state.ScrollWheelValue)
            {
                cameraPosition += new Vector3(0.0f, 5.0f, 0.0f);
            }

            if (Keyboard.GetState().IsKeyDown(Keys.A))
                this.modelPosition += new Vector3(0.0f, 0.0f, 5.0f);
            if (Keyboard.GetState().IsKeyDown(Keys.D))
                this.modelPosition += new Vector3(0.0f, 0.0f, -5.0f);

            if (Keyboard.GetState().IsKeyDown(Keys.Down))
                this.cameraPosition += new Vector3(5.0f, 0.0f, 0.0f);
            if (Keyboard.GetState().IsKeyDown(Keys.Up))
                this.cameraPosition += new Vector3(-5.0f, 0.0f, 0.0f);

            if ((Keyboard.GetState().IsKeyDown(Keys.W)) && (windowed == 0))
            {
                this.graphics.IsFullScreen = false;
                this.graphics.PreferredBackBufferWidth = 800;
                this.graphics.PreferredBackBufferHeight = 600;
                this.graphics.ApplyChanges();
                aspectRatio = graphics.GraphicsDevice.Viewport.AspectRatio;
                fullscreen = 0;
                windowed = 1;
            }
            if ((Keyboard.GetState().IsKeyDown(Keys.F)) && (fullscreen == 0))
            {
                this.graphics.IsFullScreen = true;
                this.graphics.PreferredBackBufferWidth = GraphicsDevice.DisplayMode.Width;
                this.graphics.PreferredBackBufferHeight = GraphicsDevice.DisplayMode.Height;
                this.graphics.ApplyChanges();
                aspectRatio = graphics.GraphicsDevice.Viewport.AspectRatio;
                fullscreen = 1;
                windowed = 0;
            }
            GraphicsDevice.Clear(Color.CornflowerBlue);
            GraphicsDevice.BlendState = BlendState.AlphaBlend;
            GraphicsDevice.DepthStencilState = DepthStencilState.Default;
           
            Matrix[] transforms = new Matrix[model.Bones.Count];
            model.CopyAbsoluteBoneTransformsTo(transforms);

            foreach (ModelMesh mesh in model.Meshes)
            {
                foreach (BasicEffect effect in mesh.Effects)
                {
                    effect.EnableDefaultLighting();
                    effect.PreferPerPixelLighting = true;
                    effect.TextureEnabled = true;
                    effect.DiffuseColor = new Vector3(1.0f, 1.0f, 1.0f);
                    effect.World = transforms[mesh.ParentBone.Index] * Matrix.CreateRotationY(modelRotation) * Matrix.CreateTranslation(modelPosition);
                    effect.View = Matrix.CreateLookAt(cameraPosition, modelPosition, Vector3.Up);
                    effect.Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45.0f), aspectRatio, 1.0f, 10000.0f);
                }

                mesh.Draw();
            }

            state = Mouse.GetState();

            base.Update(gameTime);

        }
    }
}

Taki uzyskuje efekt w XNA 4.0:


A taki chciałbym uzyskać efekt:


Ma ktoś może jakiś pomysł?

Offline Mr. Spam

  • Miłośnik przetworów mięsnych

Offline Avaj

  • Użytkownik

  • +2
# Kwiecień 20, 2013, 13:59:30
Dwa rozwiązania:
1. proste - Włącz alpha test
2. skomplikowane - Rysuj wszystko nieprzezroczyste, wyłącz zapis głębi i rysuj wszystko przezroczyste od tyłu do przodu

Offline VillageRaper

  • Użytkownik

# Kwiecień 20, 2013, 18:30:32
Avaj, czy mógłbyś przeprowadzić mnie np. przez punkt nr 1?
Nie wiem jak tego dokonać.

Offline flexi

  • Użytkownik

  • +3
# Kwiecień 20, 2013, 18:43:03
Avaj, czy mógłbyś przeprowadzić mnie np. przez punkt nr 1?
Nie wiem jak tego dokonać.

http://lmgtfy.com/?q=xna+4.0+enable+alpha+test

Offline VillageRaper

  • Użytkownik

# Kwiecień 20, 2013, 23:43:00
Dziękuję drugiemu koledze za chęć niesienia pomocy, ale bardziej niż wskazówki dotyczącej korzystania z wyszukiwarki internetowej liczyłem na realną możliwość rozwiązania problemu. Nie ukrywam tym samym, że wcześniej przeszukiwałem internet w celu znalezienia przydanych mi informacji i o dziwo znalazłem je, chociaż niestety nie potrafiłem ich odpowiednio wykorzystać. Najprawdopodobniej stało się tak, ponieważ nie jestem programistą, ani osobą zagłębioną w tematykę programowania.

Dlatego też za wszelką możliwie mi udzieloną pomoc, będę niezmiernie wdzięczny.
Pozdrawiam
VillageRaper


Offline VillageRaper

  • Użytkownik

# Kwiecień 21, 2013, 23:09:57
Dzięki Avaj
Praktycznie cały dzień nad tym siedziałem. Niestety nic nie zdziałałem.

Zobacz na tym zdjęciu niektóre elementy widać za przezroczystością:
http://img706.imageshack.us/img706/2029/problemprzeswit.jpg
« Ostatnia zmiana: Kwiecień 21, 2013, 23:16:59 wysłana przez VillageRaper »

Offline fn2000

  • Użytkownik

# Kwiecień 22, 2013, 02:33:39
Dwa rozwiązania:
1. proste - Włącz alpha test
2. skomplikowane - Rysuj wszystko nieprzezroczyste, wyłącz zapis głębi i rysuj wszystko przezroczyste od tyłu do przodu

A czym to się różni?

Offline voytech

  • Użytkownik

# Kwiecień 22, 2013, 04:24:06
1. Alfa test co coś podobnego do "key color" w dawnych czasach grafiki 2D, gdzie kolor różowy oznaczał przezroczystą powierzchnie. Kolor różowy zastąpiono wartością alfa, której próg można regulować. Np. zapodajesz próg 0.25 w DX/OGL oraz funkcję LESS (<), włączasz alfa test i tylko piksele mające w kanale alfa wartość mniejszą od 0.25 będą rysowane (color, depth, ect.). Reszta pikseli niespełniająca warunku zostanie zignorowana.

wady: daje postrzępione brzegi
zalety: szybki, nie potrzebuje czytać z bufora kolorów, nie trzeba sortować.

2. Blending to operacja miksująca bieżący piksel z pikselem znajdującym się w buforze kolorów.

zalety: ładnie wygląda :)
wady: wolniejsza od poprzedniej wersji, trzeba dodatkowo odczytać wartość z bufora kolorów, elementy przezroczyste trzeba przed narysowaniem posortować i rysować jako ostatnie.

Jak popatrzysz na nieudany render VillageRapera to zauważ, że szyba samochodu, bok opony oraz lampa to quad z teksturą zawierającą kanał alfa. Niektóre z nich zostały narysowane zbyt wcześnie i miejsca przezroczyste zmiksowały się z niebieskim tłem lub innymi wcześniej narysowanymi częściami samochodu. Przy rysowaniu tego quada nastąpiło miksowanie kolorów i zapis buforów Color oraz Depth. Na kolorze nie widać, że to quad, tylko okrągła lampa i jest to wynik miksowania. Gdybyś popatrzył na Depth bufor to było by widać w nim quada. Ten quad w Depth buforze już nigdy nie pozwoli aby cokolwiek zostało narysowane za nim narysowane. Efekty widać na obrazku.

Offline VillageRaper

  • Użytkownik

# Kwiecień 22, 2013, 16:02:09
Voytech czy mógłbyś mi udzielić wskazówki, jak włączyć alpha test?
Utknąłem na tym etapie i ni jak nie mogę ruszyć.
Myślałem, że to rzeczywiście będzie proste i ograniczy się do alphaTest = enable, czy czegoś takiego, tak ja ma to miejsce przy włączaniu chociażby antyaliasingu "graphics.PreferMultiSampling = true".

Mam kilka tropów, ale jak na razie tylko strasznie błądzę. Mógłbyś mi coś doradzić?

Update#1  23.04.2013
Voytech czytam cały czas Twój ostatni komentarz i chyba coś zaczyna mi się przejaśniać.
Dodatkowo aktualnie czytam o:
http://pl.wikipedia.org/wiki/Bufor_Z
http://pl.wikipedia.org/wiki/Bufor_szablonowy
http://pl.wikipedia.org/wiki/Usuwanie_niewidocznych_powierzchni
« Ostatnia zmiana: Kwiecień 23, 2013, 04:22:37 wysłana przez VillageRaper »

Offline voytech

  • Użytkownik

# Kwiecień 23, 2013, 13:40:30
w starym OGL wystarczyło:
glAlphaFunc(GL_GREATER, 0.5);
glEnable(GL_ALPHA_TEST);

ale w nowszym już tego testu nie ma. Teraz robi się to prosto w piksel szaderze:
uniform float alpha_cutoff;
vec4 color = ...
if (color.a < alpha_cutoff) discard;

w HLSL chyba polecenie jest pod nazwą killpixel? Nie jestem pewien

Offline Avaj

  • Użytkownik

# Kwiecień 23, 2013, 14:48:24
@up

w HLSL jest texkill ale w XNA nie masz dostępu do shaderów :)

Offline voytech

  • Użytkownik

# Kwiecień 24, 2013, 10:07:10
@up: :-O, naprawdę nie można nawet ładować jakiś plików efektów *.fx, które są faktycznie szaderami?


@VR:
Tak sobie przeglądam dokumentacje i tutaj znalazłem parę stron o teście alfa:
http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.graphics.renderstate.alphatestenable(v=xnagamestudio.31).aspx
http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.graphics.renderstate.alphafunction(v=xnagamestudio.31).aspx
http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.graphics.comparefunction(v=xnagamestudio.31).aspx
http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.graphics.renderstate.referencealpha(v=xnagamestudio.31).aspx

Kompletnie nie znam xna, ale może coś takiego pomóc częściowo:
GraphicsDevice.RenderState.AlphaTestEnable = true;
GraphicsDevice.RenderState.AlphaFunction = CompareFunction.Greater;
GraphicsDevice.RenderState.ReferenceAlpha = 128;

Jeszcze inny pomysł jaki mi przyszedł do głowy, to próba renderingu dwuprzebiegowo.
foreach (ModelMesh mesh in model.Meshes)
{
    if (mesh.Name != "lamp" and mesh.Name != "glass" ... "wheel") ...
    rendering bez blendingu
}

foreach (ModelMesh mesh in model.Meshes)
{
    if (mesh.Name == "lamp" "glass" "wheel" ...)
    rendering z włączonym blendingiem

Tylko, że musiałbyś mieć model, który jest podzielony na podobiekty, bo jak wszystkie trójkąty są w jednym worku to nie zadziała. Najlepiej jakbyś mógł ten model jakimś programie 3d poprawić, czyli dodać trochę geometrii dla przednich lamp i boków kół, bo to coś widać to porażka.

Offline Charibo

  • Redaktor

# Kwiecień 24, 2013, 14:17:08
@up: :-O, naprawdę nie można nawet ładować jakiś plików efektów *.fx, które są faktycznie szaderami?
Nie programowałem w XNA od jakiegoś czasu, ale kiedy jeszcze programowałem, to można było pisać szadery i je używać bez ograniczeń :)

Offline VillageRaper

  • Użytkownik

# Kwiecień 24, 2013, 22:22:18
Udało się osiągnąć pierwszy sukces. Alphatesteffect został włączony. Niestety efekt odbiega od tego jak go sobie wyobrażałem. W dodatku wciąż nie widać niektórych rzeczy za przezroczystością.

Co zostało osiągnięte:
http://img838.imageshack.us/img838/236/postep1.jpg

A co chcę osiągnąć:
http://img854.imageshack.us/img854/9856/problemlr.jpg

Macie jakieś pomysły?