We will now load a 3D model from file using the
and display it.
Note that a 3D model doesn't have to be static. It can include animated stuff, interactions, 3D sounds, scripts, and more. Our scene graph based on X3D is really quite powerful.
A sample 3D model may be found inside the engine examples,
My advice is to copy now the whole directory
data from there into your
own project directory (so you have files like
data for a directory name is special,
content there can be loaded using the castle-data:/xxx URL.
And if you want to make your own 3D model, go ahead — generally use any 3D modeler and export to any 3D format we can handle, preferably X3D. See our guide to creating game data for more information about preparing 3D data.
If you use TCastleWindowBase: To load a 3D model, change your program code to this:
uses CastleWindow, CastleSceneCore, CastleScene, CastleViewport; var Window: TCastleWindowBase; Viewport: TCastleViewport; Scene: TCastleScene; begin Window := TCastleWindowBase.Create(Application); Window.Open; Viewport := TCastleViewport.Create(Application); Viewport.FullSize := true; Viewport.AutoCamera := true; // instead of this, you could do "Viewport.Camera.SetView(...)" Viewport.AutoNavigation := true; // instead of this, you could do "Viewport.Navigation := ..." Window.Controls.InsertFront(Viewport); Scene := TCastleScene.Create(Application); Scene.Load('car.x3d'); Scene.Spatial := [ssRendering, ssDynamicCollisions]; Scene.ProcessEvents := true; Viewport.Items.Add(Scene); Viewport.Items.MainScene := Scene; Application.Run; end.
If you use Lazarus form with
To load a 3D model, double click to create an event
TForm1 class, and put there the following code:
// also add to your uses clauses these units: CastleSceneCore, CastleScene, CastleViewport; procedure TForm1.FormCreate(Sender: TObject); var Viewport: TCastleViewport; Scene: TCastleScene; begin Viewport := TCastleViewport.Create(Application); Viewport.FullSize := true; Viewport.AutoCamera := true; // instead of this, you could do "Viewport.Camera.SetView(...)" Viewport.AutoNavigation := true; // instead of this, you could do "Viewport.Navigation := ..." CastleControlBase1.Controls.InsertFront(Viewport); Scene := TCastleScene.Create(Application); Scene.Load('car.x3d'); Scene.Spatial := [ssRendering, ssDynamicCollisions]; Scene.ProcessEvents := true; Viewport.Items.Add(Scene); Viewport.Items.MainScene := Scene; end;
At the beginning we create a new instance of
TCastleScene, and load
it's contents from a file.
Scene.Spatial determines what spatial
structures (octrees for now) are created, the value
ssDynamicCollisions] is the most flexible one (it allows to speed up
the rendering by frustum culling, detect collisions between player and
level, and it adapts to a dynamic level that may have some animated
Scene.ProcessEvents activates animating VRML/X3D models (you
can remove it if you know that your level is, and always will be, static).
Then we create a viewport, which is a 2D rectangular area in a window that will show the world.
The model is added to the viewport. The model is also set as the MainScene, this means that some central settings (like initial camera position, initial headlight status and such) can be obtained from this scene.
As the comments in the above examples indicate,
Viewport.AutoCamera := true
Viewport.AutoNavigation := true is only one way to configure
camera and navigation.
To control the initial camera view:
Set the camera by code: use the Viewport.Camera.SetView method. This takes three vectors — position, look direction and look up vector. Simply add the CastleVectors unit to your uses clause, and call this:
Viewport.Camera.SetView( Vector3(-7.83, 6.15, -7.55), Vector3( 0.47, -0.30, 0.82), Vector3( 0.16, 0.95, 0.25) );
In this case, you want to leave
false (otherwise the auto-detection, done at the first render,
would override what you set).
Alternatively initialize the camera defaults (including position / direction / up) based on the model size / nodes.
To make it work, set
Viewport.AutoCamera := true.
If a model file (set as
car.x3d in the example above)
OrthoViewpoint X3D node,
then this node will determine the initial camera. You can generate such
Viewpoint using the
"Console -> Print Current Camera (Viewpoint)",
or by setting the camera in Blender before exporting this X3D file.
Otherwise (if there is no
or you didn't even set
then the camera will be auto-detected to look at the world bounding box.
To can also control the navigation ("how does the camera change based on input"):
You can assign a specific TCastleNavigation descendant to Viewport.Navigation.
You can auto-detect the suitable navigation method.
To do this, leave
Viewport.AutoNavigation := true.
Then the navigation instance will be automatically created before rendering.
You can change the navigation type by setting Viewport.NavigationType.
To control the camera only from your code
nil. By default,
the engine does not automatically
interpret any keys/mouse to handle the navigation.
You can also control the initial navigation type using the
X3D node. It determines e.g. whether we are in EXAMINE, WALK, FLY, NONE or other modes.
Note that, in order for the "bindable" nodes (like
NavigationInfo) to work,
they must be within a scene set as
is automatically used, just like the first
You can always call explicitly
to activate (jump to) a specific Viewpoint node.
The camera and navigation settings (position, direction, up, navigation type, avatar height
and many others) set in X3D file (by nodes like
NavigationInfo) serve as defaults when we create a camera instance.
You can override them all by code, as documented above.
Viewport allows to display and interact with the 3D world. It is essential to add all your 3D stuff to a viewport.
Viewport is a user interface control, which means that it occupies
some space on a 2D window on user screen.
Viewport.FullSize := true in examples above we
say that the position and size of the viewport is such that it fills the entire parent,
which in this case means that viewport fills the entire window.
In more complex scenarios you can have multiple viewports inside your window showing the same world from many cameras. For examples of this, see:
An important strength of our engine is that you can express a lot of stuff inside your data, that is inside VRML/X3D models. So many features of our engine (shaders, screen effects, mirrors and many many more) don't have any special Object Pascal examples, because they are simply not needed. For simple uses, you just define what you need inside VRML/X3D file (of course, for advanced usage you can do a lot more with Object Pascal code, and you can always build/modify VRML/X3D graph by Object Pascal code). So be sure to grab our demo VRML/X3D models and try opening them with any engine example program (like the one you just created, or even our view3dscene) — you will find that everything just works, not requiring a single line of Object Pascal code.
Our model viewer view3dscene allows to test your models before loading them to your games.
Copyright Michalis Kamburelis and other Castle Game Engine developers.
Thank you to Paweł Wojciechowicz from Cat-astrophe Games for various graphics.
This documentation is also open-source and you can even redistribute it on open-source terms.