GUI Scripting: RenderDef
This page is part of a series. See GUI Scripting Language for overview.
Introduction
A renderDef allows dynamic projection of a 3D model, in its own separate world, onto a 2D surface. The orientation of the model can be dynamically and programmatically controlled. The only use of a renderDef in the core is for the compass that can be shown in the HUD, and whose orientation changes automatically as the player faces in different directions.
Of the Properties in Common, only a few are needed, such as the rect and making the background transparent. User variables will probably not be needed, but GUI:: Parameters will be vital to control the orientation of the model from a script.
Additional Properties Specific to RenderDefs
® = A property known as a "register", that can be altered at runtime by binding it to a GUI:: parameter, or in a "set" or "transition" script command. Other properties cannot be so altered, nor appear within event handlers.
Vector3of4 = A list of 4 floats (comma-separated in a Property declaration), but only the first 3 elements matter. This is a workaround for lack of vector3 parsing support by GUI script. By convention, use "0" or "1" as fourth element.
RenderDef Properties – Used in TDM Core
Lightcolor vector3of4 ®
Color of the light. Elements in range 0 to 1. This is RGB, not RGBA. Default is 1,1,1,1 (white).
lightColor 1, 1, 1, 1
Lightorigin vector3of4 ®
Position of the light. Default is -128,0,0,1.
lightOrigin -50, 0, 50, 0
Model "path_to_model_file"
Model (.ase or .lwo file, not model def) to render. For simple models, this is as a func_static entity.
model "models/darkmod/player_equipment/compass.ase" // Standard TDM model "models/erh/submarine/er_sub_compass.ase" // Variant compass in "Seed of Lodestar" beta FM by ERH+
Modelorigin vector3of4 ®
Position of the model. Default 0,0,0,0.
modelOrigin 0, 0, 0, 1
Modelrotate vector3of4 ®
Rotation by Euler angles (-180 to 180 or equivalently 0 to 360 degrees). Vector elements are respectively pitch, yaw, and roll. See "Additional Notes" below for more. Default 0,0,0,0.
modelRotate ("gui::modelPitch"), ("gui::modelYaw"), ("gui::modelRoll"), 1 // controlled by playertools script; see example below.
Needsrender bool
Dirty flag. If 1 (true), something changed so the scene must be rendered again. Default is 0 (false).
needsRender 1
Noshadows bool
If 1 (true), prevents the model from casting a shadow, just like the familiar spawnarg on any entity. Default is 1 (true).
noshadows 1
Viewoffset vector3of4 ®
Position of the camera. Default -128,0,0,1
viewOffset -10, 0, 6, 1
RenderDef Properties – Not Used in TDM Core
These appear to be intended for Articulated Figure models. Specifically, given the Animclass name, find the entityDef. Then look for its "model" specification. From that, find the modelDef, and within that, the md5animation matching the "anim_name". For more, see the "Anim Example" below.
Anim "anim_name"
Animation to play.
Animclass "class_name"
entityDef to grab the animation from.
Compass HUD Example
The tdm_gui01.pk4\guis\playertools\compass.gui by Drumple and greebo:
windowDef Desktop { rect 500, 290, 140, 180 backcolor 0 ,0 ,0 ,0 visible "gui::CompassVisible" nocursor 1 renderDef compassModel { rect 0, 0, 140, 180 visible 1 backcolor 0, 0, 0, 0 model "models/darkmod/player_equipment/compass.ase" needsRender 1 modelRotate ("gui::modelPitch"), ("gui::modelYaw"), ("gui::modelRoll"), 1 modelOrigin 0, 0, 0, 1 viewOffset -10, 0, 6, 1 lightOrigin -50, 0, 50, 0 lightColor 1, 1, 1, 1 noshadows 1 } } // Desktop
Then, in tdm_playertools.script, there is code that creates an overlay for the compass in the HUD and, when the compass is visible, updates its image every frame. The latter, which takes the player’s orientation and calculates the GUI Parameters "modelPitch", "modelYaw", and "modelRoll", is:
... #define COMPASS_MIN_PITCH -75 #define COMPASS_MAX_PITCH 40 void playertools_compass::updateCompass(entity userEntity) // userEntity is the player { _playerAngles = userEntity.getViewAngles(); float yaw = _playerAngles_y - 90; // Clamp the pitch to [COMPASS_MIN_PITCH .. COMPASS_MAX_PITCH] float playerPitchClamped = _playerAngles_x; if (playerPitchClamped > 0) { playerPitchClamped = COMPASS_MAX_PITCH * playerPitchClamped/90; } else { playerPitchClamped = COMPASS_MIN_PITCH * -playerPitchClamped/90; } float modelPitch = playerPitchClamped * sys.sin(yaw); float modelRoll = playerPitchClamped * sys.cos(yaw); userEntity.setGuiFloat(_overlayHandle, "modelYaw", -_playerAngles_y); userEntity.setGuiFloat(_overlayHandle, "modelPitch", modelPitch); userEntity.setGuiFloat(_overlayHandle, "modelRoll", modelRoll); } ...
This "playertools_compass" script object contains additional required functions to manage the display of an item in inventory. For more about this, see Inventory#Custom_HUDs.
Anim Example
Back in 2006, when the early form of TDM’s main menu system was being designed, various ideas where considered for a side area next to the menu parchment. This area should have images of characters (guard, priest, haunt, noble) fade in and out, blended into a swirling brown background. One idea that drumple tested was using a renderDef of a representative animated 3D AI model:
renderDef ModelRender { rect 0,10, 320, 400 visible 1 backcolor 0, 0, 0, 0 bordercolor 1,1,1,1 bordersize 0 model "models/md5/chars/guards/elite_citywatch/elitecitywatchmesh.md5mesh" anim "idle" animClass "darkmod_citywatch_elite" needsRender 1 modelRotate 10, 180, 0, 0 modelOrigin 0, 0, 0, 0 viewOffset -60, 0, 50, 0 lightOrigin -100, 50, 0, 0 lightColor 1, 1, 1, 1 notime 1 }
Presumably there was a parent windowDef with the brown background. Drumple felt the renderDef needed further property adjustments, to minimize skewing due to touchy fisheye perspective. Nevertheless, Gildoran liked the results, finding that the model - blended into its background - evoked the moving newspaper pictures from Harry Potter movies. But Springheel thought it inferior to the illustration look possible with pre-rendered shots. The latter was adopted.
Additional Notes
ModelRotate and Pitch, Yaw, and Roll
Think in terms of an airplane model, with origin at its center of gravity, and its own relative axes passing through the origin. Namely:
- x axis extends along the length of the plane. So forwards/backwards.
- y axis is perpendicular to that and right/left (wing-aligned).
- z axis is perpendicular to those axes and up/down (ceiling/floor aligned)
When the plane is on ground and facing north (compass angle 0), its axes are aligned with the world coordinates. Then, to describe a different orientation, 3 consecutive rotations about each of the plane's axes is done. The order that these are applied very much matters, and is:
- About the z-axis, called "yaw". (Other terms are pan or azimuth or heading). After this rotation, the plane's x/y axes are usually no longer aligned with the world x/y axes.
- About the y-axis, called "pitch". (Other terms are elevation or tilt). After this rotation, the plane's x/y/z axes are usually no longer aligned with the world x/y/z axes.
- About the x-axis, called "roll". This is "fall over sideways".
This order of rotations is described in TDM’s Angles.h thusly:
idAngles uses the "yaw, pitch, roll" convention, in which the yaw rotation occurs first, then pitch occurs relative to the yawed axes, and finally roll occurs relative to the yawed and pitched axes. Also known as the "zyx" convention.
Unfortunately, the vector elements for idAngles and so ModelRotate must be entered in a different order:
- pitch
- yaw
- roll
For a fuller understanding, a good resource is D. Rose, "Rotations in Three-Dimensions: Euler Angles and Rotation Matrices - Part 1", Feb., 2015.
Complications with RenderDefs
Springheel in 2007 explored using renderDefs to represent purchasable items in the store in 3D. The interest was to support mappers creating custom items with new models. But each model would need to come with its own set of renderDef Properties (e.g., modelOrigin, viewOffset, etc.). Otherwise, if you just tried to use generic settings, models would appear too small, too large (and clipped), badly skewed, and so on. Mappers could have difficulty understanding how to come up with good Property values. And maybe low-poly models would be needed to avoid renderDef lagginess. In the end, it was decided that having mappers provide 2D static image files - which they would probably need anyway for inventory icons - was easier.
A 2015 discussion considered whether, as an improvement to realism, a shouldered corpse could be a ragdoll. One approach would be use a renderDef to create an overlay (e.g., of the legs) within the main field of view. Vanished One recalled that one reason TDM has an icon-based HUD is that you can't specify a skin for display in a renderDef. (Drumple’s concern about renderDef fisheye distortion, mentioned above, was also noted. Other posts expressed concerns about point-of-view conflicts when turning with intrusive legs.)
It is unfortunate that renderDef is limited to a single light source, and offers no fov/zoom Properties. The camera has a fixed horizontal field of view of 90 degrees, with vertical appropriately adjusted based on the rect dimensions. (The situation is more flexible with the player's view, which can be set with CVar "g_fov viewAngle". In addition, from within DoomScript there are further relevant functions that can be applied to $player1: getFov, startZoom, endZoom, and resetZoom.)
Light Bug, Now Fixed
Note bug 4569, discovered by Durandall. Lightcolor and lightorigin were ignored starting in TDM 1.08. Functionality was restored in 2.07.