Neverending terrain

Feb 1, 2010 at 10:51 AM

I was going to make a neverending terrain by creating/destroying terrain objects on the fly but got stumped when I found that it ignores the Position property.  Is it not possible to move or rotate terrain objects?  My ultimate aim is a long halfpipe (or a full tube if that's possible) made of a grid.  I also investigated the idea of making my own mesh direct with XNA but couldn't see any way to make use of generated meshes with Ox models, since they all require a model filename.  Is there any options in Ox that I'm missing or would I have to dig into raw XNA to achieve this kind of thing?

 

Editor
Feb 1, 2010 at 11:53 AM

why would you want to move or rotate a terrain object? Maybe im on the wrong angle here but you could consider destroying/creating terrain when the camera object (or whatever you are using as a player) get to a defined point in the terrain.

pseudocode as im at work and certain syntax eludes me

"if camera position z is greater than 1400 then destroy old scene and load the new terrain, "

this *might* give the elusion of neverending terrain. ill see if i can write a small program later if its going to be a help.

 

are you using a script for your terrain? or just loading it in using the editor?.

if you just want something like a halfpipe or full pipe, i would recommend finding or creating a 3d model of this yourself and importing this into the engine, its much easier to move around. and probably less intensive than destroying and recreating terrain objects. as im assuming you dont want the player to experience the 2 second delay while the engine performs these functions.  let me know how you get on.

-bubzy.

Coordinator
Feb 1, 2010 at 12:53 PM
Edited Feb 1, 2010 at 1:05 PM

>> I was going to make a neverending terrain by creating/destroying terrain objects on the fly but got stumped when I found that it ignores the Position property.  Is it not possible to move or rotate terrain objects?  My ultimate aim is a long halfpipe (or a full tube if that's possible) made of a grid.

The reason why terrain is unmovable is because JigLibX terrain physics can only be created in the center of world space. JigLibX would have to be patched before this becomes feasible.

>> I also investigated the idea of making my own mesh direct with XNA but couldn't see any way to make use of generated meshes with Ox models, since they all require a model filename.  Is there any options in Ox that I'm missing or would I have to dig into raw XNA to achieve this kind of thing?

You are correct that neither BasicModel nor StandardModel are meant to work in this case.

You need to create a new component type by inheriting from I/SingleSurfaceComponent (since, like the terrain, your component will only have a single physical surface) as well as creating a rendering surface that inherits from BaseSurface. You'll likely also need to reuse the ShadowReceiverEffect or create a custom effect by inheriting from it. You would likely either reuse oxShadowReceiver.fx directly or create a new shader content file by copy-paste-modifying it. You should consider creating your geometry object(s) with either VerticesPositionNormalTexture or VertexPositionNormalTextureBinormalTangent, or even creating a new vertex type in the vein of VertexPositionNormalTexture and by creating a new vertices type by implementing IVertices. You'll be leveraging the Geometry object to actually draw the vertices.

To expose you component in the editor, you'll need to create a document token that inherits from SingleSurfaceComponentToken and to follow the relevant directions in "Engine Overview.doc".

As you can see, there are several things to do to make a totally new 3D component type, but the boring, repetitive work is done for you by Ox's framework. If you haven't already, download Ox's source and use the existing components as a guide to creating 3D components. Your component is most similar to the Terrain component, so look at that one first. Also post here if you have any questions about the process.

Good luck!

Feb 2, 2010 at 10:24 AM

>>why would you want to move or rotate a terrain object? Maybe im on the wrong angle here but you could consider destroying/creating terrain when the camera object (or whatever you are using as a player) get to a defined point in the terrain.

The idea here was to create a second terrain object and offset it so that it was already there when the player arrived to avoid delays like you described.  I've been thinking of the terrain as just another mesh and didn't realise it was a "special" object so it's definately not going to suit my purpose.

>>are you using a script for your terrain? or just loading it in using the editor?.

I'm creating everything in code atm.  The idea is to keep things dynamic so it needs to be built as needed.  This is for sections of track so your idea of using existing models would also work, but then I'm limited to a predefined set.  If I can generate them myself I can make them with different angles and curvatures by just changing properties.

So it seems I need to do what Bryan is describing, and in fact I started down that path a couple of days ago but stopped short of doing the actual surface implementation.  I had another go at it tonight but the end result was a surface that does a whole lotta nothin.  Pretty sure the bit I haven't got right is the actual creation of the geometry.  I've run out of time tonite but I think I'm beginning to see the relationship between the vertices, geometry and primitive more clearly now so I'll have another go at it tomorrow.  I really need to just get a more basic surface that creates a flat grid of quads working first.

Could you confirm if the list below all seems correct?  Still a bit new to dealing with 3d at this low level so I wanna make sure I'm getting the basics right.

  • I could use QuadGeometry.Create to create the geometry, and that will return me a quad with 4 vertices from -0.5,-0.5 to 0.5,0.5.  Essentially a quad sized 1 all round.
  • I will have to create a BoundingBox for each quad (is this for JigLibX physics or something else?)
  • I will have to create a BoxPrimitive for each quad.
  • The primitive defines the position, rotation and scale that will be applied to the vertices when the geometry is drawn to the screen.

 

Coordinator
Feb 2, 2010 at 2:38 PM

Have you read the terrain's code in full? If not, do that first as its your best reference. Like the terrain, your surface will also have to be split into patches in order to get good performance, so read closely.

 

Feb 2, 2010 at 10:29 PM
Edited Feb 2, 2010 at 10:30 PM

Yes, I've read all that code.  I've tried to pull pieces from the terrain code into my own classes bit by bit so I only got the parts I needed and could make adjustments as I go.  What I ended up with was almost an exact duplicate of the terrain minus the heightmap and diffuse texture stuff.  As far as I can see the other piece I need to change (and the key to what makes my surface different from a terrain) is in CreatePatch where I need to replace TerrainPatchGeometry.Create with something.  However when I replaced that with a call to QuadGeometry.Create that I thought would at least produce something, it seemed to be drawing nothing at all.  So I'm trying to simplify it back so I can see the minimum required to create and draw a basic flat surface, then when I understand that properly I can add all the management of patches etc back in.  I suspect I've missed something in the mass copy/paste that has broken it.

Coordinator
Feb 2, 2010 at 11:13 PM

I wouldn't copy and paste as that doesn't really promote understanding of the code :)

I think it is a good idea to start from scratch though.

QuadGeometry.Create works as you describe.

You won't be creating any BoundingBoxes directly. Rather, you create a Primitive of some sort which generates the relevant bounding boxes for you. The generated bounding boxes are mostly for scene clipping. An object need be rendered only when its (generated) BoundingBoxWorld is in the camera's frustum.

To make sure the bounding boxes are generated correctly so the object is clipped properly, you want your BoxPrimitive to just cover all points in a piece of geometry. Since the geometry is currently limited to [-0.5, -0.5 ] to [0.5, 0.5], the BoxPrimitive should be created like -

new BoxPrimitive(Vector3.Zero, new Vector3(0.5f, 0.5f, 0.5f));

This covers fatter area than needs be (since a quad is really 2D), but having volume in 3 dimensions won't hurt.

IPrimitives such as BoxPrimitive generate bounding boxes for you on the fly in three spaces; Source (the values you pass in the constructor), Local (the bounding box after local properties like Position, Scale, Orientation are applied), and World (the bounding box after hierarchical transformations are applied).

In your case, you'll just need one primitve for each piece of geometry. There's no need to create a primitive for SingleSurfaceComponent's constructor since you want the component itself to be 'boundless'. Boundless means that a component gets its Draw() method called no matter where the camera is. The SkyCube does this as well. The difference between a terrain and a sky cube though is that a terrain iterates through its patches during its Draw() call and manually draws only the patches whose matching primitive's BoundingBoxWorld is in the rendering Camera's frustum.

Lastly, the IPrimitive does not dictate where a piece of geometry is drawn. IPrimitive are merely for generating bounding boxes. Its the scene component's transform properties (Position, Scale, Orientation) applied to the vertices's positions that dictate where geometry is drawn.

Hopefully this will get you a little further along :)

Feb 3, 2010 at 1:19 AM

I think I understand everything you're saying, but I'm still unable to get it to draw anything.  I'm using a structure based on the TerrainSurface, but I've modified CreatePatches so I get just one patch for now.  I've also commented out the 'if' in DrawHook that limits drawing to the camera view.  The expected result would be a single quad at 0,0.
I suspect my problem now is the effect.  I'm using oxShadowReceiver directly but it's ocurred to me that nowhere am I specifying what texture to use, because that effect doesn't have any parameters for diffuse textures like the terrain and skybox effects do.  Should I be getting a flat color texture in this case, or could that be why nothing is being drawn?

Coordinator
Feb 3, 2010 at 2:40 AM

ShadowReceiverEffect has a property called DiffuseMap (I think). Follow the #includes in the oxShadowReceiver.fx file and you'll see the effect exposes it as xDiffuseMap (again, I think). Of course, you'll need to make sure the DiffuseMap property is set before drawing.

I'm not real sure how a quad without a diffuse texture would render - probably pure black or white, but maybe nothing at all. I think it's implementation-defined. You might create a SkyBox just to make sure there's enough contrast to see a black quad.

Also, are you orienting the camera around to make sure you're looking at the visible side? If you're looking at the back or from the side, you won't see anything.

Also, make sure the camera is not so close to the quad as to be clipped by the near plane nor so far as to be clipped by the far plane. It would likely help to set the component's Scale to 10,10,10 or even 100,100,100 to make it easier to see from a proper distance.

If you pass a BoxPrimitive to the SingleSurfaceComponent's constructor, the component will not longer be boundless. Just use the same parameters you use to construct the Geometry BoxPrimitive. If you do this and also enable bounding box viewing by adding this in your code -

            new BoundingBoxVisualizer(engine, domainName, true) { Parent = engine.Root };

- you will see the bounding boxes for everything in the scene, including (hopefully) your component.

Also, if you're willing, send me what you have to take a look. Probably be easier to diagnose by looking at actual code. My e-mail is bryanedds@yahoo.com .

cheers!

Feb 3, 2010 at 3:53 AM

Yep, I found the xDiffuseMap parameter.  I went looking for it, but just didn't follow the inheritance chain far enough last time.  It's defined right at the top in baseStandard.fx.   I just stuck the skyCubeMap texture in there as a test, and bingo, the quad is now visible with that texture.

FYI I have some basic joystick camera control in there based on bubzy's very first html tutorial, and a sphere model offset above the origin a bit to give me a point of reference, and the tube component was scaled up to 10.  The BoundingBoxVisualizer also works and I'm sure will be very useful later.

So now I have the rendering working I just need to work out the necessary calcs to get the vertices where I want them, which should be pretty trivial for me compared to what I've just done.  I'll probably make something similar to TerrainPatchGeometry to build the complete shape.  I gotta say, thanks heaps for your help on this.  Your explanations are very informative.  I'm pretty impressed with the general structure and coding style you've used in Ox too.  The only complaint I would have so far (which I'm sure you've heard before) is lack of documentation.  Some sort of API reference that describes what each object does and how they relate would be really useful.  Like for example, what is the difference between a BasicModel and a SimpleModel, and in what cases should I use each?

 

Coordinator
Feb 3, 2010 at 11:40 AM

>> the quad is now visible with that texture.

booyah!

Of course, you have to be careful using a 3D cube map as a 2D diffuse texture - I'm surprised it works at all actually. Could become confusing later if you keep using it.

>> which should be pretty trivial for me compared to what I've just done.

Yep, you've got the most difficult part out of the way. I'm glad you stuck with it.

As to the documentation, I'm trying to find the resources to write it up. Resources are extremely scarce right now though, so I have to call on the users to contribute where they can.

The difference between a BasicModel and a StandardModel is that the BasicModel uses XNA's BasicEffect rendering. It is adequate for those who want to target less powerful hardware, but not recommended generally. StandardModel uses Ox's StandardEffect rendering. It's use is recommended in the general case.

Great job seeing it through!

- bryan

Feb 5, 2010 at 7:16 AM

Woohoo!  Now we're really cookin!  Screenshot here.  I only have 8x8 patches and one quad per patch for now, but I'm planning on smoothing it out by breaking up those patches eventually.

Another quick question... Currently my tube is only visible from the inside.  Is there an easy way to make the quads draw on the other side too, or would I have to actually create additional quads for the outside faces?

 

Coordinator
Feb 5, 2010 at 2:22 PM

Great job Kermitt :D

>> Is there an easy way to make the quads draw on the other side too...?

Just set the surface's FaceMode to FaceMode.AllFaces.

Cheers!

Feb 8, 2010 at 6:38 AM

>> Just set the surface's FaceMode to FaceMode.AllFaces.

I was hoping it would be something simple like that.  Works great.  Thanx.

 

Apr 16, 2010 at 12:29 AM

It would be nice to see your final code for that Kermitt...