I am trying to write a custom Minecraft Classic multiplayer client in XNA 4.0, but I am completely stumped when it comes to actually drawing the world in the game. Each block is a cube in 3D space, and it is possible for it to have different textures on each side. I have been reading around the Internet, and found out that for a cube to have a different texture on each side, each face needs its own set of vertices. That makes a total of 24 vertices for each cube, and if you have a world that consists of 64*64*64 cubes (or possibly even more!), that makes a lot of vertices.
In my original code, I split up the texture map I had into separate textures, and applied these before drawing each side of every cube. I was told that this is a very expensive approach, and that I should keep the textures in the same file, and simply use the UV coordinates to map certain subtextures onto the cube. This didn't do much for performance though, since the sheer amount of vertices is simply too much. I was also told to collect the vertices in a VertexBuffer and draw them all at once, but this didn't help much either, and occasionally causes an exception when the number of vertices exceeds the maximum size of the buffer. Any attempt I've tried to make cubes share vertices has also failed, resulting in massive slowdown and glitchy cubes.
I have no idea what to do with this. I am pretty good at programming in general, but any kind of 3D programming or game development completely escapes me.
Here is the method I use to draw the cubes. I have two global lists List<VertexPositionTexture> and List<int>, one for vertices and one for indices. When drawing, I iterate through all of the cubes in the world and do RenderShape on the ones that aren't empty (like Air). The shape class that I have is pasted below. The commented code in the AddVertices method is the attempt to make cubes share vertices. When all of the cubes' vertices have been added to the list, the data is pasted into a VertexBuffer and IndexBuffer, and DrawIndexedPrimitives is called.
To be honest, I am probably doing it completely wrong, but I really have no idea how to do it, and there are no tutorials that actually describe how to draw lots of objects, only extremely simple ones. I had to figure out how to redo the BasicShape to have several textures myself.
The shape:
http://pastebin.com/zNUFPygP
You can get a copy of the code I wrote with a few other devs called TechCraft:
http://techcraft.codeplex.com
Its free and open source. It should show you how to create an engine similar to Minecrafts.
There are a lot of things you can do to speed this up:
What you want to do is bake a region of cubes into a vertex buffer. What I mean by this is to take all of the cubes in a small area, and put them all into one vertex buffer. Only update this buffer when a cube changes.
In a world like minecraft's, LOTS of faces are occluding each other. The biggest thing you can do is to hide faces that are shared between two cubes. Imagine two cubes sitting right next to each other, you don't really need to draw the face in between, since it can never be seen anyway. In our engine, this resulted in 20 times less vertices.
_ _ _ _
|_|_| == |_ _|
As for your textures, it is a good idea, like you said, to use a texture atlas. This greatly reduces your draw calls.
Good luck! And if you feel like cheating, look at Infiniminer. Infiniminer is the game minecraft was based off. It's written in XNA and is open-source!
You need to think about reducing the size of the problem. How can you produce the same image by doing less work?
If your cubes are spaced at regular intervals and are all the same size, you may not need to store the vertices at all - your shader may be able to calculate the vertex positions as it runs. If they are different sizes and not spaced at regular intervals, then you may still be able to use some for onf instancing (where you supply the position and size of a cube to a shader and it works out where to render the vertices to make a cube appear at that location)
If your cubes obscure anything behnd them, then you only need to draw the front-most cubes - anything behind them is just not visible. A natural approach for this would be to use an octree data structure, which divides 3D space into voxels (cubes). Using an octree you could quickly deternine which cubes are visible, and just draw those cubes - so rather than drawing 64x64x64 cubes, you may find you nly have to draw a few hundred per frame. You will also find that as the camera moves, the set of visible cubes will not change much, so you may be able to use this "temporal coherence" to update your data structures to minimise the work that needs to be done to decide which cubes are visible.
I don't think Minecraft draws all the cubes, all the time. Most of them are interior, and you need to draw only those on the surface. So basically, you need an efficient voxel renderer.
I recently wrote an engine to do this in XNA, the technique you want to look into is called hardware instancing and allows you to pass one model into the shader with a stream of world positions to "instance" that model hundreds (even thousands of times) all over your game world.
I built my engine on top of this example, replacing the instanced model with my own.
http://xbox.create.msdn.com/en-US/education/catalog/sample/mesh_instancing
Once you make it into a re-usable class, it and its accompanying shaders become very useful for rendering thousands of pretty much anything you want (bushes, trees, cubes, swarms of birds, etc).
Once you have a base model (could be one face of the block), its mesh will have an associated texture that you can then replace with whatever you want to allow you to dynamically change block texturing for each side and differing types of blocks.
Related
I have an Unity 3D scene with several cameras looking at the same object (a huge brain mesh ~100k tri) but not necessary with the same point of view.
In the same 3D scene there is a huge number of spheric plots meshes (from 100 to 30000).
In all the cameras i have to display the brain mesh with a part of the plots meshes.
Depending on the camera view, each plot can have a different size (mesh filter and spheric collider), a different material (opaque or transparent) and can be visible or not.
The spheric collider must have the same size than the mesh.
I set up a shared mesh in common for each spheric mesh.
Their material can be one of the several shared materials i have defined.
Before rendering the scene, for each camera view in the OnPreCull function i have to define which plots are visibles and how they look.
This part can be very costly, i tried several things :
setting gameobject inactive : too costly
setting local scale to vector3(0,0,0) : better but i can see that the rendering is still done in the profiler
setting a total transparent material : same result, but the in the profiler the rendering is now transparent instead of opaque
setting a layer not in the cameras layers masks : huge script cost
I don't kwnow if i can make an efficient culling system with all theses cameras looking at the same point...
I welcome any new ideas.
First issue:
Regarding your specific question with the four dots.
Simply set the renderer.enabled = false, that's all there is to it.
Note however that as I mention in a comment, you would never try to "cull yourself" in Unity (unless I have misunderstood your description).
Second issue:
Regarding the small spheres. I suspect you have very many in the scene. You simply can't do that. In video games (the most difficult of all 3D engineering), you just do this with billboarding. It's how say "grass" is done in a scene. You can achieve this nicely with the particle system in Unity, or other techniques. An implementation is beyond the scope of this answer, but you will have to fully investigate billboarding. Simply it's a small flat image which always faces the camera in the render pass.
Issue 2B:
Note however that sphere colliders are wonderful, and you can use as many as you want. I'm sure this is obvious from base mathematical reasons. Side tip: often folks try to "write their own" thinking it will be faster. It's impossible to outwrite the 100? person-years of spatial culling scientific research in PhysX, and moreover they use the metal, the gpu, so you can't beat it.
Issue three:
Is there a chance you're using a mesh collider somewhere in the project? Never use mesh colliders, at all. (It's extremely confusing they are mentioned or used in Unity; they only have one or two very specific limited uses.)
Issue four:
I'm confused about why you are turning things on and off. I have a guess.
I suspect you are not using more than one "stage"!
There's an amazing trick about video games when you have more than one camera. In fact you have "offscreen" scenes! So you may have players in a dungeon or the like. Off "to the side" you may have an entirely duplicate or triplicate setup of the whole thing running (you could "see it if the camera turned the wrong way") for the other cameras. (In the example you would have different qualities on the dopplegangers, coloring, map-style or whatever the case is.) Sometimes you make a whole double just to run physics calculations or address other problems.
Fascinating extreme example of that sort of thing.
In short in your situation,
You likely need one whole 'stage' of a camera and brain for each of the camera views!
Again this can be http://answers.unity3d.com/answers/299823/view.html but it is indeed the everyday thing. In your overall scene you will see eight happy brains sitting in a row, each with their own camera. In each one you would display whatever items/angle etc are relevant. (Obviously, if certain items are "identical, other than the viewing angle" you could use the "same brain with more than one camera": but I would not do that, best to have one-brain-one-camera for each view.)
I believe that could be the fundamental issue you're having!
I am working with C#, Monogame and XNA 4.0. In my scene I have a lot of cubes. Some are connected, some are not. I would like to render the edges of the cube with another shader than the filling. Besides that, I would like to render the outer edges of connected cubes in another color (or thicker) than the edges within the cube-object. Here is a small painting to make clear what I want to do (sorry for my bad painting skills, but I think you will get it).
I know how to render a cube with a specific shader and I am also able to render the wireframe but I was not able to connect both methods. Besids that, the outer lines can not be rendered differently with this approach.
I tried it with post-effects like the edgefinding of comic shaders but in this approach I am not able render only specific edges. Besides that if two cubes are next to each other the shader does not recognize the edges.
I am not searching for a ready-to-use solution from you but I would be glad to get some tips/approaches/tutorials/similar projects/etc on how to achieve my goal. Are there some shader experts out there? I am at my wit's end.
(If you however would like to post a ready to use solution I would not be miffy :D)
It is a shame you're not using deferred shading, this would be pretty straight forward to implement if you were.
If you can access the normal and material for each pixel on screen through a texture lookup you can easily post-process this. You could use a 3x3 filter kernel and search for sufficiently large normal discontinuities (this would catch silhouette edges) and also search for pixels that lie on the transition between material IDs (this would catch the edges between blue and orange cubes). If your filter neighborhood satisfied either of these two conditions, then draw a black pixel to form the outline.
You should be able to do this if you use MRT rendering when you draw your cubes, and encode the normal + material ID into an RGBA texture (x,y,z,material).
The basic theory is described in this paper (pp. 13). In this case instead of using the depth as the secondary characteristic for outlining, you would use the material (or object ID, if you want EVERY cube to have an outline).
So for an assignment I have to morph a cube into a sphere. All that's required is to have a bunch of points along the surface of a cube (don't need to be connected or actually be on a cube, but has to form a cube, though connections would make it easier to look at) and have them smoothly translate into a sphere shape.
The main problem is I never learned how to make points in XNA 4.0 and from what I've seen it's very different to what we did in OpenGL (we learned the old one in a previous class).
Would anyone be able to help me figure out making the cube shape I need? Each side would have 10x10 points with the points on the edge shared by the surfaces of that edge. The structure would need to be easy to copy or modify since I would need to have the start state, end state, and the intermediate state to translate the points between the two states.
If I left out anything that could be important let me know.
First of all, you should familiarise yourself with the Primitives3D sample. It illustrates all of the rendering APIs that you need.
Here is how I would approach this problem (you can look up these classes and methods on MSDN and it will hopefully help you flesh out the details):
Create an array of Vector3[] that represents an appropriately tessellated unit cube around (0,0)
Create a second array of Vector3[] and and use Vector3.Normalize to copy in the vertices from your first array. This will create a unit sphere with vertices that match up with the original cube.
Create an array of VertexPositionColor[]. Fill in the colour data however you like.
Use Vector3.Lerp to loop through the first two arrays, interpolating each element to set positions in the third array. This gives you a parameter you can animate - you will have to do this each frame (in Update is probably best).
Create an array of indices (short[]) that describes a triangle list of the tessellated cube (and, in turn, the sphere and animation between the two).
Set up a BasicEffect for rendering. This involves setting its World, View and Projection matrices and maybe turning on VertexColorEnabled. If you want lighting, see the sample for details (you'll need to use a vertex type with normals, and animate those normals correctly).
The way to render with an effect is: foreach(EffectPass effectPass in effect.CurrentTechnique.Passes) { effectPass.Apply(); /* your stuff here */ }
You could create a DynamicVertexBuffer and IndexBuffer and draw with those. But for something simple like this, DrawUserIndexedPrimitives is much easier (here is a recent answer with some details, and here's another one with a complete example of BasicEffect).
Note that you should only create these objects at startup (LoadContent is a good place). During rendering you're simply using them.
If you have trouble with your 3D rendering, and you're drawing text or sprites, see this article for how to fix it.
Does it make more sense to store the coordinates for a single cube in a VBO and use camera translation/rotation to place each block in its proper place on the map, or does it make more sense to store the entire map in a VBO and just draw from that?
It's not a minecraft clone, but it is a 3rd person top-down camera angle world that builds terrain from cubes
Simply taking the question at face-value, it seems to me the OP is considering a multi-pass render scheme vs rendering large amounts of geometry using VBOs.
If this is correct, then rendering large amounts of geometry will win over a multi-pass rendering scheme. Of course, the correct way to efficiently render many cubes is to batch them by material(s) and perform instanced rendering.
I am making an RPG game using an isometric tile engine that I found here:
http://xnaresources.com/default.asp?page=TUTORIALS
However after completing the tutorial I found myself wanting to do some things with the camera that I am not sure how to do.
Firstly I would like to zoom the camera in more so that it is displaying a 1 to 1 pixel ratio.
Secondly, would it be possible to make this game 2.5d in the way that when the camera moves, the sprite trees and things alike, move properly. By this I mean that the bottom of the sprite is planted while the top moves against the background, making a very 3d like experience. This effect can best be seen in games like diablo 2.
Here is the source code off their website:
http://www.xnaresources.com/downloads/tileengineseries9.zip
Any help would be great, Thanks
Games like Diablo or Sims 1, 2, SimCity 1-3, X-Com 1,2 etc. were actually just 2D games. The 2.5D effect requires that tiles further away are exactly the same size as tiles nearby. Your rotation around these games are restricted to 90 degrees.
How they draw is basically painters algorithm. Drawing what is furthest away first and overdrawing things that are nearer. Diablo is actually pretty simple, it didn't introduce layers or height differences as far as I remember. Just a flat map. So you draw the floor tiles first (in this case back to front isn't too necessary since they are all on the same elevation.) Then drawing back to front the walls, characters effects etc.
Everything in these games were rendered to bitmaps and rendered as bitmaps. Even though their source may have been a 3D textured model.
If you want to add perspective or free rotation then you need everything to be a 3D model. Your rendering will be simpler because depth or render order isn't as critical as you would use z-buffering to solve your issues. The only main issue is to properly render transparent bits in the right order or else you may end up with some odd results. However even if your rendering is simpler, your animation or in memory storage is a bit more difficult. You need to animate 3D models instead of just having an array of bitmaps to do the animation. Selection of items on the screen requires a little more work since position and size of the elements are no longer consistent or easily predictable.
So it depends on which features you want that will dictate which sort of solution you can use. Either way has it's plusses and minuses.