Meshes
It is possible to directly use 3D models (meshes) as object graphics. To do so they need to be in OGRE format. For most modeling tools there exist exporter tools, a list can be found on the OGRE Wiki. Both the OGRE binary format (*.mesh) and the OGRE XML format(*.mesh.xml) are supported, however it is recommended to always use the binary format whenever possible since it is smaller in size and can be loaded more quickly by the engine. The tool OgreXMLConverter can convert between the two formats.
Der Exporter erzeugt in der Regel eine Mesh-Datei (*.mesh oder *.mesh.xml), falls das Mesh Bones enthält eine Skelett-Datei (*.skeleton oder *.skeleton.xml), ein Materialskript (*.material) und eventuell verwendete Texturen. Um das Mesh für ein Clonk-Objekt zu verwenden müssen alle erzeugten Dateien in die Objektdefinition (*.ocd) kopiert werden und die Mesh-Datei muss in Graphics.mesh bzw. Graphics.mesh.xml umbenannt werden. Texturen werden im PNG-, JPG- und BMP-Format unterstützt.
Das Mesh wird nicht automatisch auf die Größe des Shapes (d.h. die Width- und Height-Werte aus der DefCore.txt) skaliert. Stattdessen entspricht eine Einheit im Modellierungstool ein Pixel in Clonk. Dies erleichtert die Größenverhältnisse zwischen verschiedenen Meshes einzuhalten, was insbesondere beim Aneinanderhängen von Meshes (siehe unten) hilfreich ist. Auch auf das Koordinatensystem ist acht zu geben: Die X-Achse im Mesh-Koordinatensystem zeigt in Clonk nach vorne, die Y-Achse nach rechts und die Z-Achse nach oben.
Materialskripte
Alle Materialskripte (*.material-Dateien) werden von der Engine geladen bevor das eigentliche Mesh geladen wird. Dabei handelt es sich um einfache Textdateien die Materialeigenschaften (Farben für verschiedene Lichter, Texturen, etc.) bestimmen die dann von Meshes verwenden werden können. Jedem Material ist ein Name zugeordnet der in der Regel im Modellierungstool bestimmt werden kann. Dabei sollte darauf geachtet werden, dass dieser möglichst eindeutig ist (also zum Beispiel den Objektnamen enthält), da alle geladenen Materialien direkt von jedem Mesh verwendet werden können und es ansonsten leicht zu Namenskonflikten kommen kann.
Material scripts can also be crafted or edited by hand. The format is described in the OGRE manual. However not all of the features described there are supported (yet): Especially usage of LOD (Level of Detail) is not yet possible. The usage of pixel, vertex and geometry shaders has some restrictions, as discussed in the section below. For the source1 and source2 fields in the colour_op_ex field in texture units the additional value src_player_colour can be specified to refer to the player color of the object's owner. This can be used to colorize objects (partly) by the player color.
Zur Laufzeit kann das Materialskript auch mit der C4Script-Funktion SetMeshMaterial geändert werden.
Shaders
Pixel, vertex and geometry Shaders can be used to customize the appearance of an object beyond what is possible by the declarations in OGRE passes and texture units. The OGRE manual should be consulted to learn how shaders can be used, however, there are some restrictions in OpenClonk.
First and foremost, only shaders written in the GLSL are supported at the moment. None of the automatic parameters are available for shaders, however, some of these are implicitly available as GLSL variables.
When a custom fragment shader is used, then that shader is responsible for applying the player color and color modulation to the object, since in that case the engine cannot take care of that. The additional parameters mentioned above can be used for that purpose. Also, when a custom fragment shader is used, the colour_op, colour_op_ex, alpha_op and alpha_op_ex directives in all texture units are ignored.
When a fragment shader or a vertex shader (or both) are not specified, then standard shaders are generated. The standard shaders expect certain GLSL varying variables to be propagated from the vertex shader to the fragment shader, so if you implement a vertex shader but not a fragment shader, make sure to create the following varying variables:
Variable name | Typ | Beschreibung |
---|---|---|
normalDir | vec3 | The interpolated normal vector for lighting calculations. |
texcoord | vec2 | The interpolated texture coordinate, based on the texture coordinates specified in the mesh. |
The standard fragment shader uses these values and possibly processes them with what is specified in the texture unit declarations. The standard vertex shader creates these values from the GL state, and is independent of the texture units or other declarations. If no custom vertex shader is provided, the following shader is used:
varying vec3 normalDir; varying vec2 texcoord; void main() { normalDir = normalize(gl_NormalMatrix * gl_Normal); texcoord = gl_MultiTexCoord0.xy; gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; }
Shaders for OpenClonk are composed of various shader slices. This allows to add openclonk-specific code to the shaders, such as applying color modulation for objects, or lighting. A slice is specified by
slice(position) { ... }
in the shader code, and the code within the slice is then used for composing the whole shader code. Uniform variables should be declared outside of any slices. The following position values for slices are defined, and slices are inserted from lower to higher values:Slice position | Wert | Beschreibung |
---|---|---|
texcoord | 50 | Vertex shader: Should be used to set the texcoord varying variable. |
normal | 60 | Vertex shader: Should be used to set the normalDir varying variable. |
position | 80 | Vertex shader: Should be used to set the gl_Position variable. |
init | 0 | Fragment shader: Should be used for initializing required variables. The standard slices set the initial color value from the mesh material properties here. |
coordinate | 20 | Fragment shader: Should be used for calculating custom texture coordinates. |
texture | 40 | Fragment shader: Should be used for texture lookups. |
material | 60 | Fragment shader: Used by the landscape shader to query the material pixel. |
normal | 80 | Fragment shader: Should be used to compute the normal vector. |
light | 100 | Fragment shader: Should be used for lighting calculations. |
color | 120 | Fragment shader: Should be used for setting the output color value. |
finish | 140 | Fragment shader: Final slice position, can be used for debug code overwriting any previous output, for example. |
A slice position can also have a relative constant offset with a plus or minus sign, such as
texture+1
. The fragment shader slices should modify the implicitly defined value color
of type vec4
.In order to make sure that other OGRE mesh viewers can still display the mesh, it is suggested to wrap the slice definitions into corresponding
#ifdef
blocks. This also allows to, for example, set default light conditions when the mesh is shown in a standalone OGRE mesh viewer. An example is given here:#ifndef OPENCLONK #define slice(x) #define color gl_FragColor varying vec2 texcoord; void main() { color = vec4(1.0, 1.0, 1.0, 1.0); // or gl_FrontMaterial.ambient; #endif // Shader slices go here. slice(XXX) { ... } #ifndef OPENCLONK // Custom lighting code for standalone mesh viewers can go here } #endif
If the uniform variable
oc_PlayerColor
is defined with type vec3
, it is automatically set by OpenClonk to the player color of ColorByOwner objects.Animationen
Wei bei Bitmap-basierten Grafiken kann ein Objekt während einer Aktivität eine Animation abspielen. Dazu muss zuerst ein Rig für das Modell erstellt und anschließend die Animation erzeugt werden. Beim Export wird sie in der *.skeleton (bzw. *.skeleton.xml im OGRE-XML-Format) gespeichert. Um sie während einer Aktivität abzuspielen muss das Animation-Feld in der ActMap gesetzt sein. Die Facet-Felder werden bei Mesh-Grafiken ignoriert.
Per Script ist es auch möglich, mehrere Animationen gleichzeitig abzuspielen bzw. Übergänge zwischen Animationen zu machen. Um mehr darüber zu erfahren siehe Animationen.
Just as scripts, animations can be appended or included to certain definitions. For this purpose the *.skeleton file has to match a certain pattern: appendto.Definition.skeleton adds the animations in that skeleton to the skeleton that was loaded by Definition. Existing animations will not be overloaded. Similarly, include.Definition.skeleton includes animations. Make sure to name your skeleton accordingly when rigging the mesh, if you want to include animations. Obviously, animations from only one definition can be included, but skeletons from multiple animations can be appended.
Attachment of meshes
Meshes können aneinandergehängt werden, sodass sie sich immer miteinander bewegen. Auf diese Weise kann der Clonk zum Beispiel Sachen tragen oder mit dem Bogen Zielen. Um zwei Meshes zu verbinden gibt es die C4Script-Funktion AttachMesh, um sie wieder zu lösen kann DetachMesh verwendet werden. Beim Anhängen wird dabei jeweils ein Bone von den beiden Meshes angegeben. Das angehängte Mesh wird dann so positioniert, dass sein Bone immer die gleiche Position und Orientierung hat wie der Bone mit dem es verbunden wird.
However it needs to be taken care of the fact that only the meshes, that is the graphics of the objects, are attached. The real position of the attached object (so what is returned by the functions GetX and GetY or the area in which the object is found by the functions Find_AtPoint, Find_InRect or Find_AtRect) is not affected.
Repräsentativgrafik
Wird ein Mesh verwendet so bleibt der Picture-Eintrag aus der DefCore.txt ohne Wirkung. Stattdessen wird eine perspektivische Projektion des Meshes verwendet. Die Kamera befindet sich dabei vor dem Mesh in einer geeigneten Entfernung so dass das Mesh vollständig erfasst wird.
Die Position und Ausrichtung des Meshes relativ zur Kamera kann mit der "PictureTransformation"-Eigenschaft geändert werden. So kann es gedreht, versetzt und vergrößert dargestellt werden. Der Eigenschaft sollte ein Array mit 12 Integer-Einträgen zugewiesen werden, die eine 3x4-Matrix bilden. Die ersten vier Werte bilden die erste Zeile, die nächsten vier die zweite und die letzten vier Werte die dritte Zeile. Mit Hilfe der Skriptfunktionen Trans_Identity, Trans_Translate, Trans_Rotate, Trans_Scale und Trans_Mul lassen sich diese Matrizen sehr bequem generieren.
Wie bei SetObjDrawTransform werden die einzelnen Matrixelemente in Promille (1000 = 100%) angegeben, da es in Clonk keine Fließkommazahlen gibt.
Als Beispiel hier die Transformation für die Werkzeughütte:
SetProperty("PictureTransformation", Trans_Mul(Trans_Translate(0,0,7000), Trans_Rotate(-20,1,0,0), Trans_Rotate(30,0,1,0)), def);
Zuerst wird die Werkzeughütte um 30 Grad gegen den Uhrzeigersinn um die Y-Achse gedreht, danach um 20 Grad im Uhrzeigersinn um die X-Achse. Anschließend wird sie noch um 7 Einheiten in positive Z-Richtung verschoben sodass sie näher an der Kamera ist.
MeshTransformation
Genauso wie die Eigenschaft "PictureTransformation" das Erscheinungsbild der Repräsentativgrafik ändert gibt es auch die Eigenschaft "MeshTransformation", die auf die normale Grafik im Spiel wirkt. Dies wirkt sich sehr ähnlich wie SetObjDrawTransform aus, jedoch gibt es einige Unterschiede:
- Mit der "MeshTransformation"-Eigenschaft kann auch die Z-Koordinate beeinflusst werden. Das Mesh kann also zum Beispiel um die X- oder Y-Achse gedreht werden.
- SetObjDrawTransform wird auch nach der Beleuchtung angewandt. Die transformierten Koordinaten haben also keinen Einfluss auf die Beleuchtung mehr. Wird das Mesh zum Beispiel von unten beleuchtet und wird es dann mit SetObjDrawTransform auf den Kopf gestellt, so bleibt die Beleuchtung an der gleichen Stelle auf dem Mesh, wird also mitgedreht. Bei der "MeshTransformation"-Eigenschaft wird die Beleuchtung jedoch hinterher gemacht, sodass das Mesh immer von unten beleuchtet wird, egal wie es ausgerichtet ist.
- Sind sowohl "MeshTransformation" als auch SetObjDrawTransform gesetzt, so wird zuerst die "MeshTransformation" auf das Mesh angewandt und dann SetObjDrawTransform.