spec_3d - ryzom/ryzomcore GitHub Wiki


title: 3D Engine Specification (2000) description: Original technical specification for the Ryzom 3D engine published: true date: 2026-03-14T00:00:00.000Z tags: editor: markdown dateCreated: 2026-03-14T00:00:00.000Z

Translated from "fr 2000 3d spec_3d" — the original 3D engine specification document for Ryzom (then called "Rykol"), written in 2000. {.is-info}

1. The Landscape

1.1. Landscape Geometry

1.1.1. Constraints

The territory of Ryzom has the following constraints:

  • It is very extensive (100 km²).
  • You can see far (1 km of vision).
  • It is not randomly generated.
  • It can model more than just mountains (no height maps).

1.1.2. Solutions

The solution is to model the landscape with patches of approximately 16m x 16m. These patches are grouped into zones of 160m x 160m. Patches can be subdivided to generate smaller facets.

1.1.2.1. Patches

Patch Order
  • A zone has a certain number of patches. Each patch is subdivided into a number of tiles. A tile is a basic texture in the Starcraft style. The patch must have a power-of-2 number of tiles in U and V (not necessarily the same). A patch of order 8 has 8x8 tiles. A patch can for example have 8x4 tiles, 8x2 tiles, 4x2 tiles, etc.
  • The default patch is order 8.
  • The minimum order for a patch is 1.
  • The maximum order for a patch is 16.
Adjacent Patches

The adjacency rules are simple and strict. A patch of order N must be adjacent to:

  • one patch of order N, or
  • two patches of order N/2, or
  • four patches of order N/4

19 Bezier patches of different orders (1, 1/2, 1/4) demonstrating adjacency rules in a 3D viewport

Illustration of patch adjacency rules. Here we have 19 patches of different orders.

Patch Size

A base patch should measure approximately 16m x 16m. A patch of order 4 should measure approximately 8m x 8m, etc. The smallest patch is therefore a patch of order 1 and it measures 2m x 2m. To find the ideal size of a patch, multiply its order by 2.

Subdivision

Patches are rendered with a subdivision close to ROAM. This subdivision is "geomorphed" so as not to have popping. This subdivision depends on:

  • The eye/patch distance.
  • The "flatness" of the patch.
  • The order of adjacent patches.
  • The order of the patch. In particular, if the patch is rectangular, the subdivision is special and deviates from the usual ROAM (subdivision in the length first, with UV geomorph).
  • The distance at which the patch must be displayed in "Tile" mode (see Textures).

The subdivision geometry is calculated with the following considerations:

  • Subdivision follows the Bezier patch formula, with a geometric correction applied to the tessellation that forces patches to have a continuous texel ratio on the edges, regardless of the size of the Bezier surface tangents.
  • The resulting point is perturbed by a displacement map, to give it grain. This map is a procedural 3D "Noise" texture whose parameters (frequency, depth, amplitude) are specified per patch and interpolated between them. The vertex is thus displaced according to the value of this perturbation, and in the direction of its normal.
Holes in Patches

It is possible to have apartments/caves embedded in the landscape with a "portal" system (like Quake). A portal is a (cubic) object embedded in the patch (position edited by the artist). It allows an apartment or cave to display over the landscape through this portal. To avoid problems, the sides of the cube must be covered with a door frame.

Portal cube (green face) embedded in landscape, covered by a door frame object (transparent red)

The example above shows the portal (in green) covered by an object (in transparent red), which covers just its sides (the "door frame"). The interior is then visible through the green area.

Code Notes: Depending on the 3D cards (GeForce 1 / GeForce 2 and above), OpenGL USER_CLIPPING will or will not be used. In the worst case, only per-object clipping will be done. The cube MUST encompass the wall/cliff (regardless of its subdivision!!). When outside, only the front face of the cube is displayed (with ZTest=false and ZWrite=BACK). When inside the cube, the 5 other faces are displayed (same, with ZTest=false, ZWrite=BACK, and BackFaceCull=false).

1.1.2.2. Zones

Definition
  • The landscape is divided into zones. A zone is a 160m x 160m square.
Number of Patches
  • A zone must contain a maximum of 150 patches of order 8. A patch of order 8 counts as 4 patches of order 4, etc. For example, you can have in the same zone 75 patches of order 8 and 300 patches of order 4 (subject to being able to have 300 patches in the same zone...).
  • If small patches (order < 8) are used, it is advisable to use large patches (order > 8) to compensate.
Adjacent Zones

Vertices shared between multiple zones must be at the same position in all zones. They will be "merged" during export to the engine. The normals at the edge of zones will be forced during export to be continuous along the zone boundary. There is therefore no normal discontinuity along zone edges.

Number of Zones

The number of zones is limited by the amount of memory used on the DVD and the client's hard drive. Count 400 bytes per patch, i.e. 60 KB per zone. For now we base our calculations on 4800 zones, i.e. 500 MB uncompressed (see the document memory_usage.doc for more details).

1.1.3. Remaining to Define

  • The total number of patches in a zone, regardless of their size.
  • Is the noise OK?

1.2. Textures

1.2.1. Constraints

  • The amount of high quality texture memory must fit in 32 MB of VRAM (cf. memory_usage.doc).
  • The pixel ratio on the ground must be of good quality.
  • A good diversity of ground textures is desired, and the use of texture clamp should be avoided.
  • Textures must tile well with each other.
  • The bilinear effect must be avoided: filtering encounters a discontinuity at the edges of textures.
  • Textures must change with the seasons.
  • Textures must change with the time of day (night, day).
  • A color can be added to "paint" the landscape on top of the textures.

1.2.2. Solutions

Tile Textures

A tile texture is a 128x128 texture. All tile textures are 128x128. There are 1536 of them (cf. memory_usage.doc). They are grouped by terrain type (grass, bark, etc.). Two tile textures are adjoining if they have the same pixels along their joint. It is strongly recommended to use the same pixels along the edges of tile texture joints of the same terrain. If the pixels of two facing joints are symmetric along the joint, then the tile is marked as being flippable along the axis passing through the center of the joint.

Mapping Coordinates

Mapping coordinates are generated on the tiles. Each tile has an entire tile texture mapped to it. Texture coordinates are rounded so that the top of the tile is mapped to the center of the corner pixels of the largest LOD. With the constraint of adjoining tile textures (same pixels at the edge) and this mapping, there is guaranteed to be no bilinear junction problem for the first LOD.

Pixel Ratio

For 2x2 meter tiles with 128x128 tile textures, the pixel ratio will be 1.5 cm.

Multilayer

It is possible to add a second ARGB tile texture on top of the first. This can be useful for modeling roads or other details in the texture. It follows the same constraints as the first tile texture.

Night Textures

At night, tiles can have a different appearance. A second ARGB texture can be added additively on top of the first to have a different pattern at night. It appears only at night.

Seasons

Textures will be processed at load time to be adapted to the season. This takes the form of the appearance of snow and leaves on the ground. The appearance must be possible in real time because the transitions are quite fast (snow). It is therefore necessary to invalidate tile textures from time to time (in addition to the Far texture). The texture change is done only by blending the texture of season X to the texture of season X+1 according to a determined time. This blend is done by writing directly into the tile texture. For performance reasons, this blend should be spread over at least 4 hours (so no sudden snow).

Color

It is possible to paint the landscape color at the top of the tiles. This color is applied with a precision of 2 meters. It will be stored in a global texture in the patch.

Display

  • Tile textures are stored and compressed with S3TC (DXTC1 or DXTC3).
  • Tiles are displayed with a lightmap integrating color and shading, with a precision of 50 cm.
  • To avoid displaying too many faces, tiles are replaced by a Far Texture at a certain distance, varying between 50 and 100 meters (user choice). This Far texture integrates all the previous factors (color, season, night texture, etc.). The precision of this Far texture decreases with distance (50 cm, 1 m, 2 m). Transitions between Far texture detail levels and with Near tiles are done with alpha blending.
  • The Far Texture is stored in 16 bits. Depending on the needs and time, it could be displayed in 24-32 bits, fake 24 bits on GeForce, 16 bits 444x4, etc. This Far texture is not mip-mapped.
  • Bilinear junctions and Far Texture: Each patch has its own Far texture. This is mapped to the middle of the edge pixels. Additionally, this edge is blended with the corresponding edge of the neighboring patch's texture. Thus, there will be no bilinear junction problem between 2 patches. This process reduces the texture appearance and can therefore induce distortions. It will therefore be done for the 1st mipmap level and possibly for subsequent levels (depends on quality...).

Tile Sets

1500 tiles can be used at the same time. When changing location (territory, city, other), transition zones (with few tiles used in common) are needed between the two sets. This transition must follow the scheme below:

Tile set transition zones: green territory A and A' blending into red territory B' and B

  • Zone A is at 100% of the tile set for territory A.
  • The column of A' zones (2 zones wide) is at 50% of the tile set for territory A.
  • The column of B' zones (2 zones wide) is at 50% of the tile set for territory B.
  • Zone B is at 100% of the tile set for territory B.

1.2.3. Remaining to Define

  • The processing applied to textures at load time (and in real time?) for seasons. Problem of autumn and leaves (not for the prototype).
  • Can an optional bump texture be added to some tiles? (not for the prototype)
  • Can we put clouds whose shadow scrolls on the ground? (to be tested and only during the day) => maybe near in Gouraud, and far in texture.
  • Day/night transition: if Gouraud for clouds during the day, and Gouraud to progressively make specular textures appear, we can do one with RGB, the other with alpha.
  • OK for seasons? (to be seen after the prototype)
  • If we group tiles in batches in large textures (to limit render state changes), how do we handle bilinear junctions between 2 tiles (with LOD 2, 3... N of the large texture)? (We don't group tiles, and if it's too slow, we'll group them, and use glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR) to avoid bilinear problems in higher LODs)
  • How to handle the slight color change between the Far texture in 16 bits and the Tiles in DXT3 (32-bit quality)?
  • Number of tiles revised downward due to DXTC1 bug!?

1.3. Static Lighting

1.3.1. Constraints

  • The terrain is lit by a gaseous cloud.
  • The direction of the light is static.
  • The tint, intensity, and diffusion of the light can vary with time (day/night), seasons, and locations.

1.3.2. Solutions

Each patch has, in addition to its lighting texture, a shading texture of the same size in 8 bits. This is only to give the intensity of the lighting at each point of the global texture.

  • This texture will be pre-calculated with radiosity (with special shadow case, see below).
  • This calculation will take into account the landscape and static objects (houses, trees, etc.).
  • The day/night tint change takes 30 minutes, by only de-dramatizing the shading difference (to avoid having to store 2 shading textures).

1.4. Dynamic Lighting

1.4.1. Constraints

  • There can be other landscape lighting sources than the gaseous cloud.
  • Lamps can be static, moving, flickering, changing tint and intensity.
  • They must be taken into account in the luminosity calculation with the global texture and the shadow texture.

1.4.2. Solutions

Lamps are taken into account in the calculation of the shading texture. This is calculated as often as possible, and as needed (light that turns off, moves, etc.).

The shading calculation of these lamps does not take into account cast shadows.

1.5. Shadows

1.5.1. Constraints

  • We want the most precise shadows possible.
  • Shadows are influenced by light diffusion. At night, there are no more shadows. At noon, maximum shadows.
  • Shadows are erased by dynamic lamps.

1.5.2. Solutions

Each patch has a 32x32 shadow texture in compressed 1-bit that indicates whether there is shadow or not. This gives us shadows precise to 50 cm.

Shadows of dynamic objects on the landscape are calculated via a dynamic shadow texture, then projected on the landscape "as best as possible". Only shadows cast from the "sun" are projected.

2. Objects

Objects are modeled in triangles.

The polygon count can be automatically reduced by the MRM (Multi Resolution Mesh) method.

Objects can be deformed by the blendshape method.

Objects can be skinned on a skeleton.

They can be modeled in several independent parts such as the arms, legs and head for a character. These different parts are connected using interfaces.

Objects can use multiple materials.

Objects can be mapped with multiple texture sets (or "skin" in the Quake sense).

Objects can use shadowmaps as lighting textures.

It is possible to provide N simplified versions (LOD) where the transition between each version is displayed in alpha for each object (for trees for example). Each of these simplified versions has all the properties of an object (skinnable, MRM-able, etc.).

2.1. Vertices

2.1.1. Weights for Skinning

Objects can be skinned on a skeleton. A vertex can be assigned up to 4 matrices.

Skinning requires a weight per skinned matrix for each vertex.

Plugin notes: There are two skinning tools in 3ds Max: Physique and Skin. The first has an SDK, so it is fairly simple to export skinning. The second does not have one for now, although there are plans to provide one in the ComSkin version. It will therefore be necessary to go find the modifier manually in the stack, and using the sources provided in the SDK, read the structures. It is likely that Skin will be preferred.

It is possible to create a plugin to control the validity of skinning in 3ds Max. The latter would display in red the polygons skinned on more than four matrices.

2.1.2. Weights for MRM

The weight for MRM will be set through vertex colors (plugin).

To indicate a fast degradation of a vertex, black will be used; to indicate a slow degradation, white will be used.

Certain vertices can also be flagged "don't move", so that this vertex does not move during degradation (i.e. it is the other vertices that will degrade onto it). This is interesting for hands, for example — if you lock the vertices at the fingertips, you replace "the stump effect" with "the mitten effect".

2.2. Triangles

Triangles use N sets of texture coordinates per face, 3 indices on vertices and 3 indices on normals.

2.2.1. Texture Coordinates

Plugin notes: Texture coordinates should be welded before being exported to limit the risk of UV discontinuity.

2.2.2. Normals

Normals are edited in 3ds Max by smoothing groups (plugin).

Plugin notes: Have a look at "Computing Face and Vertex Normals" in the 3ds Max SDK to correctly recalculate normals from a Mesh class during export. Normals should be grouped to also avoid discontinuities and limit the number of different normals.

2.3. Mesh

2.3.1. Primitives

Triangles are grouped into lists of primitives of the same type. Lists are created and sorted according to several criteria:

  • Lists are sorted by matrices, then by materials, then by textures, matrix changes being more costly than bindTexture.
  • Triangles that use fewer than 4 matrices can be added to lists of triangles that use at least their matrices.
  • To avoid too many matrix changes, the skeleton is traversed in DepthFirst order. By doing this, and by correctly organizing the skin weights, one could change only one matrix out of 4, for each limb traversed.
  • Strips and fans must be found in the primitive lists to optimize the size of the primitives (for bus bandwidth but also for the memory size of an MRM).

2.3.2. Multi Resolution Mesh

An object undergoes offline processing that calculates a series of 10 LOD in which the polygon count decreases linearly (squared?).

  • It is possible to have only certain LODs of an object in memory.
  • Vertices have a weight that influences the degradation of the object (plugin).
  • The MRM object has a link to its descendant (coarser) object as well as a list of indices of vertices, mapping coordinates and normals in this descendant object to blend to perform the geomorph to the lower level.
  • In a LOD, vertices that blend and those that don't blend cannot share the same normals and mapping coordinates, because these values will blend as well.

2.3.3. Simplified Versions

Using a plugin, a "meta-object" can be defined which is a list of triplets {object, display distance, transition distance}. "Object" defines the name of the object to use, "display distance" the distance at which it appears, and "transition distance" the size of the transition zone. This transition is done by an alpha fade.

This technique is usable for example for trees.

2.3.4. Interfaces

An interface allows connecting two objects so that they are always welded. The interface gives the position of the common points between the two objects and controls their MRM degradation.

  • An interface is represented by a special face that will not be displayed. It has an identifier to indicate the type of its connection (plugin).
  • The MRM calculation uses an environment describing the degradation of each interface type. The collapse of vertices along the interface occurs at the same MRM level in each object.
  • This environment fixes both the vertices and the skinning weights on the interface. Indeed, the weights of interface vertices must be the same in all objects to avoid holes during deformations.
  • The normals used on interfaces are forced with the values of the base model (human).

2.3.5. Blendshapes

A blendshape describes the morphing of an object in geometry (vertex + normals) and in UV (plugin). It stores the new position of each displaced vertex.

For MRM, it is necessary to have one blendshape per LOD level. More precisely, each blendshape key only stores all the points it modifies, at all blendshape levels.

Plugin: The Max plugin will simply scan the modifiers in the stack, find "Morpher", the standard morphing plugin.

2.3.6. Shadowmaps

Unfold the mapping?

2.4. Materials

2.4.1. Definition

An object can use multiple materials. A material belongs to one object and one alone.

There are 3 different types of shaders, not combinable:

  • Normal: The optional alpha of the texture is used for transparency (if transparency ON).
  • Alpha specular: A specular texture is used in environment mapping where there is alpha.
  • Alpha user color: The alpha of the texture indicates that a modulate must be done with a color. This allows modifying the base color of a texture. This mode requires special texture processing (plugin).

Each of these shaders can be combined with a shadowmap (which gives 6 different shader types).

Various animatable options:

  • Show / hide.
  • Transparency mode ON/OFF.
  • BlendSrc and BlendDest modes (useful only with transparency ON).
  • ZWrite On/Off. ZTest Function (ALWAYS, NEVER, LESS, LESSEQUAL...).
  • ZBias.
  • ZList or not ZList (mainly useful for transparency).
  • Global Envmap (for the Alpha Specular shader).
  • User color (for the User Color shader).
  • Lighting ON/OFF.
  • Use Specular (secondary color) ON/OFF.
  • If Lighting ON, DefaultMaterial ON/OFF. ON means that Emissive, Ambient, Diffuse and Specular have default values. Useful for optimization.
  • If Lighting ON, RGB emissive, RGB ambient, RGB diffuse, RGB specular.
  • Alpha (value useful for transparency). With a Normal shader, this alpha is multiplied with the texture's alpha to give the final transparency.

Materials are also used to add special information to certain faces. Here are a few:

  • Face belonging to an interface and identifier of that interface.

2.4.2. Remaining to Define

  • Here, we only have 6 types of materials. If we extend the notion of material, we can add other attributes, such as: The texture projection mode (generalization of Specular mapping, and can be used for clouds...). We can generalize the notion of material to a series of passes, each being able to give its blending mode, the set of texture coordinates it uses (stored in the mesh) or the Texture Coordinate Generation mode it uses. The previous 8 shaders are therefore special cases.
  • Do we completely close the possibility of using Vertex Color? (primary / secondary / fogcoord?)
  • Possibility of DeltaMaterials, materials that modify a material, which is interesting for changing the global color of an object for example (blinking), without having to change the mesh's material. A DeltaMaterial would be stored per instance and would apply to a list of the mesh's materials (or all?). Only some properties are modifiable this way. We could perhaps even support the texture set system with this (more general system).

2.5. Texture Sets

A material is assigned not a single texture but a texture set. This allows creating different textures for the same object (plugin).

The different LODs of object textures are loaded "as needed", i.e. depending on the Camera-Object distance. This saves VRAM (and/or RAM) memory, so as to have better-defined textures when close, and less well-defined when the object is far away.

⚠️ **GitHub.com Fallback** ⚠️