📜 ⬆️ ⬇️

u-nebula: first date

Just want to apologize for the delay with the review article on the engine and thank you for your support and comments to the previous post . Deviation from previous commitments was caused by fussing with our art and the desire to make an introductory article using Lisp . Unfortunately, Lisp support is still very raw for us, so that we use reliable Tcl . At the end of the way, we should get a visualization of the meditative-relaxing plan (to apply in case of winter depression).

Under the cut text, code and pictures.

Part I. Earth

First you need to download and install the latest SDK . You do not need to install into Program Files, since much is generated on the fly in scenes and you may have problems with access rights.

For those who want to independently assemble the engine from source, there is a reminder , but there is no need for it - everything can be done in a running demonstration of CityGen.
What may be useful from the memo is the generation of documentation for the engine commands, for this you need to run autodoc.py from the bin folder and open index.html in the doc / autodoc folder (hereafter all folders will be specified relative to the nebula folder defined during installation) .

Let's get started Perhaps it's about time.
Launch CityGen from the start menu and see a picture with a landscape generated on the go. Yes, the landscape let us down a little, but this is student work and its purpose is to test what we have built up, so sour facial expressions, in this case, need nothing.
Generated town
Now we have 2 ways to work / experiment:
1. Call the console by pressing Esc. It will appear on the background of the picture.
2. Click on F2 to call nbrowser. Here is what it looks like:
nbrowser - running engine guide
We will not describe nbrowser in this article (it has a fairly simple interface and, if it’s willing, we will jot down a short post describing its capabilities), and therefore we will use the built-in console.
')
So fearlessly press Esc and get, after various logs, a command line like this: / usr / scene>

It should be noted that in nebul all objects of the engine are instances of C ++ classes, heirs of the nroot class, and during execution are organized into a hierarchical tree-like system with paths like file systems. Paths can be both absolute and relative. The tree node with which the rendering begins (rendering) the root of the scene, in nebul, is traditionally located in / usr / scene, where we are, judging by the promp, and we are. Commands (functions), with the exception of a few basic ones, are calls to the original methods of the original classes and can be given to both the current node and an arbitrary object with the specified path.
As an example, glamorous ladies can change the color of the letters of the console to pink:

/sys/servers/console.seticolor 255 10 100 255 


After we enjoyed the picturesque view of the current scene, let's erase it quickly, just carefully so as not to remove the excess (for example, the user's camera will collapse without it).

To find out what we have in the current node, use the dir command.

 /usr/scene>dir cam skybox sun city landscape lights machine 


We will probably leave the camera, the sun and the light, and the rest will be destroyed with a hand that does not tremble:
 delete machine delete city delete landscape delete skybox 


And we deleted the sky and the earth ... and it became empty ... (but it's light because the light was left).

Well, now you can create something. Only here we begin with music - mood, type, and everything else. Let's go to the folder where the prepared in advance (because their creation lies outside of this article) meshes, textures and music. To navigate through the current file system, tcl uses the usual cd command. We need to get into the tutorials folder.

 cd ../tutorials 


Create a sound node:
 new nsoundnode music sel music .setlooping 1 .setfile Souls_of_Gaia_V.2_Sotano_Sellado.ogg sel .. 

In order not to enter into the console a difficult-long sound file name, you can use the technical trick - .setfile [glob * .ogg] , since * .ogg file we have only one - no problems foreseen.

For the above commands, a small explanation is required. Going through the nodes of the tree is done using sel (from select) in the same way as the cd command; accordingly, sel .. will rise to the level up. With the new nsoundnode music command, we created a sound node called music. new takes the class as the first argument, in this case, nsoundnode , the second is the path, it is the name of the object, in this case, local music and returns the created object, in the case of tcl, it is a string with a path. The current node is returned by the psel command. With the .setlooping 1 command, we asked the music not to leave us while the appliqué is running. And finally, the .setfile command indicated which sound file we want to play (ogg / vorbis and wav formats are supported).

So we have fun. Thanks to the author PeerGynt Lobogris and the jamendo website for this work and encouraged to go ahead.
It would not hurt to somehow begin to orient in the emptiness and blackness that we have put together, and of course the grid will help us in this, for the creation of which we have a ready-made team:
 ::visual_debug::create_grid 30 60 

the first parameter (30) - sets the size of the grid plane;
the second (60) is the number of cells;
Additionally, you can set the color, for example:
 ::visual_debug::create_grid 30 60 {0.75 0.3 0.0 1.0} 

Spatial navigation takes place using the AWSD gaming keys, arrows (with the console turned off) and the mouse with the left pressed, to move with a drag, or the right, for turns, with buttons (available to setup enthusiasts in the script / cityviewer / input.tcl). Turn off the console (Esc). Looking around ...
Grid console

It's time for us to return the sky. And again the ready command comes to the rescue:
 create_skybox stars1 

The sky is created - on the line Earth. This case is more serious, there will be more teams ( ; and, of course, it is not necessary to enter the comments following it):
 sel [new n3dnode shape] ; #-       n3dnode   shape. .tz -10; # -        0, 0, -10    [new nmeshnode mesh].setfilename sphere.n3d ; # -    shape    ( ,  ). sel [new nshadernode shader]; #- ,   ,    .setnumstages 1; #-    .setcolorop 0 "replace tex"; #-   ,     .begintunit 0; #-     .settexcoordsrc "uv0"; #-       0 (    ) .endtunit; #-      sel ..; #-    [new ntexarraynode tex].settexture 0 "globe.jpg" none; #-         ,   

Well, it should be somewhere here - we are looking on the grid, mouse, buttons, we are looking for everyone. If we do not find, do not despair, press the spacebar. And here we have the Earth (in the window, the Earth in the window is visible, aaaa).
And here we have the Earth
What have we actually done? We look at the code:
sel [new n3dnode shape] - create and immediately select a node of type n3dnode with the name shape.
In general, the visible object in our engine is a subtree, the root of which is the node containing the geometric transformation, relative to the parent. Such a node belongs to a class of type n3dnode or its heirs. Methods of this class can be found on the page of documentation that we generated at the beginning. Now we need only one .tz -10 command, which will put our object at the point with coordinates 0, 0, -10 relative to the parent node, i.e. scenes.
The following command [new nmeshnode mesh] .setfilename sphere.n3d will create a node with a mesh under the shape node (a geometric model defined by triangles). In this case, we use an object of the nmeshnode class with the name mesh and immediately assign to it a file with a sphere model - sphere.n3d. A file of type .n3d is a readable file in ASCII format. There is also a binary .nvx format.
sel [new nshadernode shader] is the next subnode of the shape node, describes the parameters of the material, lighting, and texturing of our model for a fixed conveyor (our engine also supports software shaders). For simplicity, here is the most basic and "poor" shader, without the parameters of lighting and material.
Finally, the texture node [new ntexarraynode tex] .settexture 0 “globe.jpg” none , the last subnode of our shape .
And so we repeat once again the model of a visible object in general:
T - transformation relative to the parent - n3dnode , with subnodes:
| - M - geometric model, static or dynamic - nmeshnode, nmeshcluster, nmeshipol , etc.
| - S (optional) - shader, simple or software - nshadernode, nshaderprogramnode
| - T (optional) - texture, ntexarraynode, pdtexarraynode

Stop! Something is clearly not enough. What is there Galileo muttering on the commission ...?
Make sure that we are still in the shape node
 sel /usr/scene/shape sel [new nipol rot] .connect ry .addkey1f 0 0 .addkey1f 15 360 sel .. 

Yes, here, now “it turns”!

Let's save the result of our work:
 sel /usr/scene .saveas earth 

Now in the data / tutorials folder you can find a Tcl script called earth.n. You can read it. To make sure that everything is preserved, we erase our creation with a firm hand:
 delete shape 

And load it again, but as a file:
 .parse earth.n 


In principle, one could stop at this and, after thanking the patient reader-experimenter for his attention, modestly leave the stage, but the New Year is on its way, and no one has canceled a small holiday miracle. So let's create it.

Part II. Not earth


Shake the dust of the earth, already familiar teams:
 sel /usr/scene delete shape 

We are again waiting for a lot of work, but do not rush to enter all the commands from the console - at the end we will write how to download this tutorial, part 1 or 2, without typing all the text manually.

 set mesh_files [glob *.n3d];# -      set meshes {};# -      foreach m $mesh_files { lappend meshes [file rootname [file tail $m]] ;# -       } sel [new n3dnode shape];# -      .txyz 0 1 -10;# -    sel [new nspriterender sr];# -      sel [new nstaticmeshemitter me];# -           sel [new nmeshipol mesh];# -      () # -              #    foreach   ; -   ,  foreach m $meshes { new nmeshnode $m; $m.setfilename $m.n3d; $m.setreadonly true; # -  ,    ,   ,   ; } .setreadonly true;# -     set i 0 .beginkeys [expr [llength $meshes] * 2 + 1];# -  , ""   #     ;    foreach foreach m $meshes { .setkey $i [expr $i*3] $m; # -     3 ,   3     incr i; .setkey $i [expr $i*3] $m; incr i; } .setkey $i [expr $i*3] [lindex $meshes 0];# -   1 ,     .endkeys;# -  ""  .setupdatecoord true;# -    .setupdatenorm true;# -    .setupdateuv0 true;# -   0  sel ..;# -     .setlifetime 10;# -    .setmeshnode mesh;# -  ""     sel ..;# -     set sz 0.075;# -   set bn 0.025;# -  .beginkeys 4;# -   .setkey 0 $sz $bn 1 1 1 1 .setkey 1 $sz 0 1 1 1 1 .setkey 2 $sz 0 1 1 1 1 .setkey 3 $sz 0 1 1 1 1 .endkeys .setemitter "me";# -  ""    sel ..;# -   shape sel [new nshadernode shader];# -     .setnumstages 1;# -    .setcolorop 0 "mul tex const";# -       .setalphaop 0 "replace tex";# -     .setconst 0 1 1 1 1;# - ,     .begintunit 0;# -    .setminmagfilter "linear_mipmap_nearest" "linear" .settexcoordsrc "uv0" .endtunit .setlightenable false;# -      .setalphaenable true;# -    .setzwriteenable false;# -    z-buffer .setcullmode "none";# -   ""  sel [new nipol ipol];# -     -    .connect setconst0 ;# -    setconst0 .addkey4f 0 1 0 0 1; # red .addkey4f 1 1 1 0 1; # yellow .addkey4f 2 0 1 0 1; # green .addkey4f 3 0 1 1 1; # cyan .addkey4f 4 0 0 1 1; # blue .addkey4f 5 1 0 1 1; # magenta .addkey4f 6 1 1 1 1; # white sel .. sel .. [new ntexarraynode tex].settexture 0 "lib:textures/glow-flat-a.png" "none";# -  sel [new nipol rot];# -    Y .connect ry .addkey1f 0 0 .addkey1f 15 360 sel .. sel .. 


A little explanation to this part. The morph that we got as a result uses pre-generated meshes. A necessary condition for morphing is the same number of vertices. The rest of the code is left for self-study. Questions of course welcome!

In order to download the first part of the article, just type:
 cd ../tutorials source tutorial0.tcl 

Then to run the 2nd part:
 part2 


Well that's all!
That's what happened.

:) Congratulations to all Habr's readers, Happy New Year!

PS If you suddenly have problems at startup, then try one of the following options:
1. update DirectX (we use the June SDK)
2. Run CityGen-GL to use OpenGL engine.

Source: https://habr.com/ru/post/110522/


All Articles