Create Custom Geometry

rated by 0 users
This post has 21 Replies | 3 Followers

Top 10 Contributor
Posts 1,289
SunBurn_Community_Licensee
SunBurn_Contributor
SunBurn_Pro_Licensee
Philippe Da Silva Posted: 02-12-2010 12:23 PM

Hi,

I am trying to create a starfield using individual vertexes positionned randomly and uniformly on the surface of a sphere.

I already used this technique with XNA but it seems that since 1.3, I cannot see how to do it anymore.

http://www.synapsegaming.com/wikis/sunburn_1_0_docs/custom-geometry.aspx

The above link points to a resource that is targeting 1.2 Submit techniques but it doesn't work anymore for 1.3 (I guess).

Could someone points me to the right information? ;)

Thanks

Philippe

Top 10 Contributor
Posts 1,289
SunBurn_Community_Licensee
SunBurn_Contributor
SunBurn_Pro_Licensee
Top 50 Contributor
Posts 136
SunBurn_Community_Licensee
SunBurn_Contributor

The 1.3.1 version is still a preview so you're right that the docs above are not targeting it.

In 1.3, I noticed the methods are similar, taking in an Effect along with the index and vertex buffers, etc. and submitting that. However, anything is open to changes in 1.3 so unless you're testing out stuff and experimenting, I would recommend you work with 1.2 until the final version of 1.3 is released. The SunBurn guys seem to be very design-oriented and it was pretty easy for me to migrate my engine from 1.2 to the 1.3 preview so I suspect the final version will be just as easy if not easier.

Top 10 Contributor
Posts 1,289
SunBurn_Community_Licensee
SunBurn_Contributor
SunBurn_Pro_Licensee

Thanks again.

I'm not that comfortable with using 1.2 knowing that I'll have to port my game engine design to 1.3 that changes drastically how Scene objects are managed.

I'll wait for someone from Synapsegaming to give me some advice on how they see custom geomtry implemented with 1.3 before making any other move ;)

Top 10 Contributor
Posts 1,289
SunBurn_Community_Licensee
SunBurn_Contributor
SunBurn_Pro_Licensee

Ok, I couldn't wait longer as I want to make my decision on using SunBurn or not for my next game.

Therefore, here is my current implementation (slightly modified as my game engine structure makes use of Game states that are out of topic and would only confuse the message ;) )

So, I have a Starfield class such as:

using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace Moon.Cosmos.Graphics
{
    public class Starfield
    {
        private VertexPositionColor[] __Vertices;
        private BasicEffect __Shader;

        public Starfield(GraphicsDevice device)
        {
            this.GenerateStars(42, 1000);

            __Shader = new BasicEffect(device, null);
            __Shader.AmbientLightColor = Color.White.ToVector3();
            __Shader.DiffuseColor = Color.White.ToVector3();
            __Shader.VertexColorEnabled = true;
            __Shader.EnableDefaultLighting();
            __Shader.CommitChanges();
        }

        #region Methods
        /// <summary>
        /// Generates the stars of the Starfield.
        /// </summary>
        private void GenerateStars(int seed, int numberOfStars)
        {
            Random dice = new Random(seed);

            __Vertices = new VertexPositionColor[numberOfStars];

            for (int i = 0; i < numberOfStars; i++)
            {
                float color = Math.Max((float)dice.NextDouble(), 0.5f);

                Vector3 position = Procedural.RandomGeometry.GetRandomPointOnSphere(dice, 10);
                __Vertices[i] = new VertexPositionColor(position, new Color(color, color, color, color));
            }
        }

        public void Draw(GraphicsDevice device)
        {
            __Shader.Begin();
            foreach (EffectPass pass in __Shader.CurrentTechnique.Passes)
            {
                pass.Begin();
                device.DrawUserPrimitives<VertexPositionColor>(PrimitiveType.PointList, __Vertices, 0, 1000);
                pass.End();
            }
            __Shader.End();
        }
        #endregion
    }
}

And I call the Starfield.Draw() method just after SceneState.BeginFrameRendering(...) and SceneInterface.BeginFrameRendering(...)

I do not draw anything else.

The result: Black screen.

Any idea why I cannot see my stars? :p

Top 10 Contributor
Posts 338
SunBurn_Community_Licensee
SunBurn_Pro_Licensee

well... your screen is black, which means something is being drawn, else it would be cornflower blue !!

have you checked your camera?

Top 10 Contributor
Posts 1,289
SunBurn_Community_Licensee
SunBurn_Contributor
SunBurn_Pro_Licensee

I'm using a simple camera positioned at 0.0.0 coordinates looking the Vector3.forward direction and calculating a simple Projection matrix (using a simple 1.0f fov, near plane at 0.01f and far plane at 100000.0f and an aspect ratio calculated on the Viewport).

So I don't think my camera is the issue.

Top 10 Contributor
Posts 5,368
Employee
SunBurn_Studio_Licensee

Hi Philippe,

It doesn't look like the BasicEffect's World, View, and Projection matrices are being set.  Make sure these are set to Identity, the view rotation, and the projection transform respectively.

Let me know if this helps!

Follow me on Twitter – development and personal tweets
Awesome XNA Videos – Lighting, Rendering, and game videos

Top 10 Contributor
Posts 1,289
SunBurn_Community_Licensee
SunBurn_Contributor
SunBurn_Pro_Licensee

Hi JohnK,

Congrats on the job done so far... The road is still long but this is taking the right direction ;)

So, you were right, my code was missing these Matrices but once declared and setup, still nothing rendered.

And then I felt really dummy: my code was working properly BUT I forgot to add a call to my Draw method sometime in between the SceneInterface.BeginFrameRendering and SceneInterface.End()... :p

Won't bother you anymore... [Leaves the room sneaky...]

Top 10 Contributor
Posts 1,289
SunBurn_Community_Licensee
SunBurn_Contributor
SunBurn_Pro_Licensee

Just a quick addition:

Actually, my cusom geometry renders but while I'm using the exact same code on an Xna project and Sunburn project, I don't get the same results:

On Xna, it seems that my starfield is placed at the center of the sphere on which I place my Vertices while on Sunburn, it seems that I am looking at a distant point (probably the sphere of vertices) far away from my Camera view...

JohnK, is there a way for me to send you a test case for you to look at quickly and give me back your insights on what I am doing wrong?

Thanks

Philippe

Top 10 Contributor
Posts 5,368
Employee
SunBurn_Studio_Licensee

Hi Philippe,

No worries, it's easy to miss a line or two during an integration.

Philippe Da Silva:
Actually, my cusom geometry renders but while I'm using the exact same code on an Xna project and Sunburn project, I don't get the same results:

In both cases it's rendered using GraphicsDevice.Draw<...>Primitives?  This is the recommended way to render custom geometry, ui, on-screen effects, ... that do not use lighting (ie: outside of SunBurn), and is compatible with SunBurn.

It sounds like either the World or View matrix given to the star field's BasicEffect are different from the XNA version of the code, this would cause the star field to be off in the distance rather than centered around the camera.

You can also check out the HDR example, it renders a skybox which uses the same type of camera-centered view matrix.

You can reply with a test case to one of the automated email notifications from this thread, add "Attn: JohnK" or something similar so it's routed to me.  Make sure to include a working xna test case for comparison.

Let me know if this helps!

Follow me on Twitter – development and personal tweets
Awesome XNA Videos – Lighting, Rendering, and game videos

Top 10 Contributor
Posts 1,289
SunBurn_Community_Licensee
SunBurn_Contributor
SunBurn_Pro_Licensee

Ok, now I'm done with my Starfield rendering (which you can have a quickly made video here: http://www.vimeo.com/9678484

Now, I want to render my planetary bodies and since their size will vary I didn't want to rely on meshes rather use my own Custom geometry.

Outside of the SunBurn rendering pipeline, my code works just as intended. However, as soon as I try to make it a SceneObject, it doesn't render anything.

I read a long discussion between JonhK and Uber about opening RenderableMesh through a set of writable properties but to avoid that, I tried to simply recreate the RenderableMeshCollection and assigning it to my SceneObject instance. I see my issues coming from this as using a model, it draws normally.

Here is my current implementation. Does anyone see anything obviously wrong that I would have missed? :)

My SphereGeometryFactory which returns a RenderableMesh:

public static class SphereGeometryFactory
    {
        public static RenderableMesh CreateSphere(GraphicsDevice device, ISceneObject sceneObject, Effect effect, float size, int tesselation, bool hemisphere)
        {
            if (tesselation <= 1)
                throw new ArgumentException("tesselation is too small");

            float tes = tesselation;
            int prevCount = -1;
            int startIndex = 0;
            int prevStartIndex = 0;
            List<VertexPositionNormalTexture> verts = new List<VertexPositionNormalTexture>();
            List<Vector3> vertsPos = new List<Vector3>();
            List<ushort> inds = new List<ushort>();

            int y_count = tesselation / (hemisphere ? 2 : 1);
            for (int y = 0; y <= y_count; y++)
            {
                float ay = y / tes * (float)Math.PI;
                int div = (int)(tesselation * 2 * (float)Math.Sin(ay)) + 1;

                for (int x = 0; x < div; x++)
                {
                    float ax = x / (float)div * (float)Math.PI * 2.0f;

                    float s = (float)Math.Sin(ay);
                    Vector3 norm = new Vector3((float)Math.Cos(ax) * s, (float)Math.Sin(ax) * s, (float)Math.Cos(ay));

                    verts.Add(new VertexPositionNormalTexture(norm * size, norm, new Vector2(ax / (float)Math.PI * 0.5f, ay / (float)Math.PI)));
                }

                if (prevCount != -1)
                {
                    int p = 0, c = 0;
                    while (p != prevCount || c != div)
                    {
                        if (p / (float)prevCount > c / (float)div)
                        {
                            inds.Add((ushort)(c % div + startIndex));
                            inds.Add((ushort)(p % prevCount + prevStartIndex));
                            inds.Add((ushort)((++c) % div + startIndex));
                        }
                        else
                        {
                            inds.Add((ushort)(c % div + startIndex));
                            inds.Add((ushort)(p % prevCount + prevStartIndex));
                            inds.Add((ushort)((++p) % prevCount + prevStartIndex));
                        }
                    }
                }

                prevCount = div;
                prevStartIndex = startIndex;
                startIndex += div;
            }

            VertexDeclaration vertexDeclaration = new VertexDeclaration(device, VertexPositionNormalTexture.VertexElements);
            VertexBuffer vertexBuffer = new VertexBuffer(device, typeof(VertexPositionNormalTexture), verts.Count, BufferUsage.None);
            vertexBuffer.SetData(verts.ToArray());

            IndexBuffer indexBuffer = new IndexBuffer(device, typeof(ushort), inds.Count, BufferUsage.None);
            indexBuffer.SetData(inds.ToArray());

            return new RenderableMesh(
                sceneObject,
                effect,
                Matrix.Identity,
                indexBuffer,
                vertexBuffer,
                vertexDeclaration,
                0,
                PrimitiveType.TriangleList,
                inds.Count / 3,
                0,
                verts.Count,
                0,
                VertexPositionNormalTexture.SizeInBytes);
        }
    }

 

And now, my Planet class. (Do not pay attention to the IContentOwner interface which is coming from the great Xen framework I use as an abstraction for common XNA stuff: here Content loading)

public class Planet : SceneObject, IContentOwner
    {
        #region Fields
        #endregion

        #region Initialization
        public Planet(GraphicsDevice device)
            : base()
        {
            RenderableMesh mesh = SphereGeometryFactory.CreateSphere(device, this, new LightingEffect(device), 8f, 8, false);
            List<RenderableMesh> meshList = new List<RenderableMesh>();
            meshList.Add(mesh);
            this.RenderableMeshes = new RenderableMeshCollection(meshList);
        }
        #endregion

        #region IContentOwner Members

        public void LoadContent(ContentRegister content, DrawState state, Microsoft.Xna.Framework.Content.ContentManager manager)
        {
            ((LightingEffect)this.RenderableMeshes[0].Effect).DiffuseMapTexture = manager.Load<Texture2D>("Textures/Planets/planet");
        }

        public void UnloadContent(ContentRegister content, DrawState state)
        {
        }

        #endregion
    }

And my Submit call placed inside my Initiailization code:

__Planet = new Planet(this.Application.GraphicsDeviceManager.GraphicsDevice);
            __Planet.World = Matrix.CreateTranslation(new Vector3(0,0,-20));
            __Planet.ObjectType = SynapseGaming.LightingSystem.Core.ObjectType.Dynamic;
            __Planet.Visibility = SynapseGaming.LightingSystem.Core.ObjectVisibility.RenderedAndCastShadows;
            this.Application.Content.Add(__Planet);
            this.Scene.ObjectManager.Submit(__Planet);

Top 10 Contributor
Posts 1,289
SunBurn_Community_Licensee
SunBurn_Contributor
SunBurn_Pro_Licensee

I don't mean to abuse on bumping threads up but as this was a different problem I want to make sure that it is not missed ;)

Top 50 Contributor
Posts 136
SunBurn_Community_Licensee
SunBurn_Contributor

Not to be rude or anything but copy-pasting pieces of your project here once for review I could accept. I think a second time with a much larger chunk for "anything obvious" is lazy... Could you tell us what you've tried so far?

Top 10 Contributor
Posts 1,289
SunBurn_Community_Licensee
SunBurn_Contributor
SunBurn_Pro_Licensee

Raphael:

Not to be rude or anything but copy-pasting pieces of your project here once for review I could accept. I think a second time with a much larger chunk for "anything obvious" is lazy... Could you tell us what you've tried so far?

I understand that you can think I'm lazy based on my second post sounds but I'm actually far from it as I've tried several things before posting this code ;)

I've first browse the articles on this website to see if I could find any help: no success.

I've then looked at the documentation focusing primarly on the SceneObject, RenderableMesh and RenderableMeshCollection classes to see if I could find any specifics on how to create these objects manually.

I also made some prototypes to create my SceneObjects using custom geometry using the many Constructors available.

As a final research, I took Reflector.Net and tried to understand the inner tasks done by RenderableMesh constructors to see what I was doing wrong (by the way, I may have found what I'd call a small bug where a LightSystemEditor instance must be available to create a RenderableMesh using the VertexBuffer and IndexBuffer constructor: it throws a NullReferenceException if not set)

I think my issue is probably located on filling the RenderableMesh Constructor arguments as it is the only piece of code that isn't documented anywhere.

See, I'm not lazy even if I sounded so :p

Page 1 of 2 (22 items) 1 2 Next > | RSS