Model-Based Rendering

While Ren'Py is primarily used with two dimensional rectangular images thatare common in visual novels, underneath the hood it has a model-based rendererintended to to take advantage of features found in modern GPUs. This allowsfor a number of visual effects that would not otherwise be possible.

As a warning, this is one of the most advanced features available in Ren'Py.In many cases, it's not necessary to understand how model-based renderingworks behind the scenes - features likematrixcolor and Live2D supportcan be used without understanding how Model-Based rendering works, and moresuch features will be added to the understanding. This documentation isintended for very advanced creators, and for developers looking to addto Ren'Py itself.

Model-Based Rendering is one of the most advanced features in Ren'Py, andthis documentation may be hard to understand without first looking at theOpenGL, OpenGL ES, GLSL, and GLSL ES manual. What's more, since there areportions of the models that are passed directly to your GPU drivers, whichmay accept erroneous inputs, it's important to check on multiple kinds ofhardware.

Models, Renders, and Drawing Operations

The fundamental thing that Ren'Py draws to the screen is a Model. A modelconsists of the following things:

  • A Mesh of one or more triangles. A triangle consists ofthree vertices (corners), each of which contains a position in two orthree-dimensional space, and may contain additional information, mostcommonly texture coordinates.

  • Zero or more textures, with the precise number allowed being limited by theGPUs your game can run on. All GPUs should support at least three texturesper model. A texture is a rectangle containing image data that's been loadedon the GPU, either directly or using a render-to-texture operation.

  • A list of shader part names. Ren'Py uses these shader parts to create shaders,which are programs that are run on the GPU to render the model. Shader partnames can be prefixed with a "-" to prevent that shader part from being used.

  • Uniform values. A uniform is additional data that is the same throughout themodel. For example, when a model represents a solid color, the color is auniform.

  • GL properties. GL properties are flags that further control how thingsare rendered, such as the minification/magnification modes and thecolor mask.

As Ren'Py usually draws more than one thing to the screen, it creates atree ofRender objects. These Render objects may have Models orother Renders as children. (A Render object can also be turned into a Model.as described below.) A Render contains:

  • A list of children, including a 2-dimensional offset that is applied toeach child.

  • AMatrix that describes how the children are transformed inthree-dimensional space.

  • Lists of shader part names, uniforms, and GL properties that are appliedto the Models when being drawn.

  • Flags that determine if the drawable-space clipping polygon should beupdated.

Ren'Py draws the screen by performing a depth-first walk through the tree ofRenders, until a Model is encountered. During this walk, Ren'Py updates amatrix transforming the location of the Model, a clipping polygon, andlists of shader parts, uniforms, and GL properties. When a Model is encounteredas part of this walk, the appropriate shader program is activated on the GPU,all information is transferred, and a drawing operation occurs.

Where Models are Created

Ren'Py creates Models automatically as part of its normal operation.The main reason to understand where models are created is that modelscorrespond to drawing operations, and hence are the units that shadersare applied to.

Images and Image Manipulators

These create a model with a mesh containing two triangles that coverthe rectangle of the image. The mesh contains texture coordinates.The model uses the "renpy.texture" shader.

Solid()

The Solid displayable creates a mesh containing two triangles, and notexture coordinates. The model uses the "renpy.solid" shader,with the color placed in theu_renpy_solid_color uniform.

Dissolve(),ImageDissolve(),AlphaDissolve(),Pixellate(),AlphaMask(),Flatten()

Each of these transforms and displayables creates a Model with a mesh,shaders, and uniforms as is needed for its purposes.

Live2D

Live2D displayables may created multiple Models when rendered, generallyone Model for each layer.

Transform() and ATL

A Transform creates a model ifmesh is True, or ifbluris being used. In this case, the children of the Transform are renderedto textures, with the mesh of the first texture being used for the meshassociated with the model.

Not every transform creates a Model. Some transforms will simply addshaders and uniforms to a Render (such as transforms that useblur oralpha). Other transforms simply affectgeometry.

Render

A Transform creates a model if itsmesh attribute is True.In this case, the children of the Render are rendered totextures, with the mesh of the first texture being used forthe mesh associated with the model.

It's expected that Ren'Py will add more ways of creating models in thefuture.

Shader Program Generation

Ren'Py generates a shader program by first assembling a list of shader partnames. This list consists of "renpy.geometry", the list of shader partstaken from Renders, and the list of shader parts found in the Model beingdrawn.

The shader parts are then deduplicated. If a shader part begins with "-",it is removed from the list, as is the rest of that part without theleading "-". (So "-renpy.geometry" will cause itself and "renpy.geometry"to be removed.)

Ren'Py then takes the list of shader parts, and retrieves lists of variables,functions, vertex shader parts, and fragment shader parts. These are, in turn,used to generate the source code for shaders, with the parts of the vertex andfragment shaders being included in low-number to high-number priority order.

This means that any variable created by one of the shaders will be accessibleby every other fragment from any other shader in the list of shader parts.There is no scope like in Python functions to protect interference betweenshaders.

Ren'Py keeps a cache of all combinations of shader parts that have ever beenused in game/cache/shaders.txt, and loads them at startup. If major changesin shader use occur, this file should be edited or deleted so it can bere-created with valid data.

Creating a Custom Shader

New shader parts can be created by calling the renpy.register_shaderfunction and supplying portions of GLSL shaders.

Generally, shader parts should be of the form "namespace.part", such as"mygame.recolor" or "mylibrary.warp". Names beginning with "renpy." or"live2d." are reserved for Ren'Py, as are names beginning with _.

renpy.register_shader(name,**kwargs)

This registers a shader part. This takesname, and thenkeyword arguments.

name

A string giving the name of the shader part. Names starting with anunderscore or "renpy." are reserved for Ren'Py.

variables

The variables used by the shader part. These should be listed one perline, a storage (uniform, attribute, or varying) followed by a type,name, and semicolon. For example:

variables='''uniform sampler2D tex0;attribute vec2 a_tex_coord;varying vec2 v_tex_coord;'''
vertex_functions

If given, a string containing functions that will be included in thevertex shader.

fragment_functions

If given, a string containing functions that will be included in thefragment shader.

Other keyword arguments should start withvertex_ orfragment_,and end with an integer priority. So "fragment_200" or "vertex_300". Thesegive text that's placed in the appropriate shader at the given priority,with lower priority numbers inserted before higher priority numbers.

Ren'Py supports only the following variable types:

  • float (a Python float)

  • vec2 (a tuple of 2 floats)

  • vec3 (a tuple of 3 floats)

  • vec4 (a tuple of 4 floats)

  • int (a Python integer)

  • ivec2 (a tuple of 2 integers)

  • ivec3 (a tuple of 3 integers)

  • ivec4 (a tuple of 4 integers)

  • bool (a Python boolean)

  • bvec2 (a tuple of 2 booleans)

  • bvec3 (a tuple of 3 booleans)

  • bvec4 (a tuple of 4 booleans)

  • type[n] (an array of [n] elements of [type] (any of the types above) (for instance, int[5] would be an array of 5 integers))

  • mat2 (aMatrix)

  • mat3 (aMatrix)

  • mat4 (aMatrix)

  • sampler2D (a Displayabe, including strings that give Displayables, or a Render)

Uniform variables should begin with u_, attributes with a_, and varyingvariables with v_. Names starting with u_renpy_, a_renpy, and v_renpyare reserved, as are the standard variables given below.

As a general sketch for priority levels, priority 100 sets up geometry,priority 200 determines the initial fragment color (gl_FragColor), andhigher-numbered priorities can apply effects to alter that color.

Here's an example of a custom shader part that applies a gradient acrosseach model it is used to render:

initpython:renpy.register_shader("example.gradient",variables="""        uniform vec4 u_gradient_left;        uniform vec4 u_gradient_right;        uniform vec2 u_model_size;        varying float v_gradient_done;        attribute vec4 a_position;    """,vertex_300="""        v_gradient_done = a_position.x / u_model_size.x;    """,fragment_300="""        float gradient_done = v_gradient_done;        gl_FragColor *= mix(u_gradient_left, u_gradient_right, gradient_done);    """)

The custom shader can then be applied using a transform:

transformgradient:shader"example.gradient"u_gradient_left(1.0,0.0,0.0,1.0)u_gradient_right(0.0,0.0,1.0,1.0)showeileenhappyatgradient

As stated before, thegradient_done variable from the example.gradient shaderwill be accessible by any and all other shaders applied from the same list. Thiscan be useful when having optional parts in a given shader system, but it can alsolead to name collisions when using two independent shaders.

GLSL Version.The version of GLSL supported depends on platform, but the most restrictiveare mobile and web platforms, which use GLSL ES 1.00. Ren'Py declares variablesto have highp precision, which supports floating point numbers in the range2-62 to 262. Non-zero floating point numbers should have amagnitude betwee 2-62 and 262, and integers should be in the rangerange -216 to 216. Actual hardware often supports a larger range,but this isn't guaranteed.

There is a variable that can help in debugging custom shaders:

defineconfig.log_gl_shaders=False

If true, source code for the GLSL shader programs will be written tolog.txt on start.

Shader Part Local Variables

Variables can be declared shader-local by using one ofu__,a__,v__, orl__ as a prefix. When this is done, the double underscoresare filled in with the shader name with all dots replaced with underscores.For example, if the shader name isexample.gradient, the prefixu__ will be replaced withu_example_gradient_.

The main use of this is withtext shaders, where mostuniforms are shader-local. Also, local variables inside the shader shouldbe declared withl__.

Transforms and Model-Based Rendering

Model-Based rendering adds the following properties to ATL andTransform():

mesh
Type:

None or True or tuple

Default:

None

If not None, this Transform will be rendered as a model. This means:

  • A mesh will be created. If this is a 2-component tuple, it's takenas the number of points in the mesh, in the x and y directions. (Eachdimension must be at least 2.) If True, the mesh is taken from thechild.

  • The child of this transform will be rendered to a texture.

  • The renpy.texture shader will be added.

By default, the texture used by the mesh will not be mipmapped. Ifmipmaps are desired,gl_mipmap should be set to True.

mesh_pad
Type:

None or tuple

Default:

None

If not None, this can either be a 2 or 4-component tuple. If mesh isTrue and this is given, this applies padding to the size of the texturesapplied to the textures used by the mesh. A 2-component tuple appliespadding to the right and bottom, while a 4-component tuple appliespadding to the left, top, right, and bottom.

This can be used, in conjunction with thegl_pixel_perfect property,to render text into a mesh. In Ren'Py, text is rendered at the screenresolution, which might overflow the boundaries of the texture thatwill be applied to the mesh. Adding a few pixels of padding makes thetexture bigger, which will display all pixels. For example:

transformadjust_text:meshTruemesh_pad(10,0)gl_pixel_perfectTrueshader"shaders.adjust_text"

will ensure that the texture passed to the shader contains all of the pixelsof the text.

shader
Type:

None or str or list of str

Default:

None

If not None, a shader part name or list of shader part names that will beapplied to this Render (if a Model is created) or the Models reachedthrough this Render.

blend
Type:

None or str

Default:

None

if not None, this should be a string. This string is looked up inconfig.gl_blend_func to get the value for the gl_blend_funcproperty. It's used to use alternate blend modes.

The default blend modes this supports are "normal", "add", "multiply","min", and "max".

In addition, uniforms that start with u_ but not with u_renpy are made availableas Transform properties. GL properties are made available as transformproperties starting with gl_. For example, the color_mask property is madeavailable as gl_color_mask.

Blend Functions

defineconfig.gl_blend_func={...}

A dictionary used to map a blend mode name to a blend function. Theblend modes are supplied to thegl_blend_func property, given below.

The default blend modes are:

gl_blend_func["normal"]=(GL_FUNC_ADD,GL_ONE,GL_ONE_MINUS_SRC_ALPHA,GL_FUNC_ADD,GL_ONE,GL_ONE_MINUS_SRC_ALPHA)gl_blend_func["add"]=(GL_FUNC_ADD,GL_ONE,GL_ONE,GL_FUNC_ADD,GL_ZERO,GL_ONE)gl_blend_func["multiply"]=(GL_FUNC_ADD,GL_DST_COLOR,GL_ONE_MINUS_SRC_ALPHA,GL_FUNC_ADD,GL_ZERO,GL_ONE)gl_blend_func["min"]=(GL_MIN,GL_ONE,GL_ONE,GL_MIN,GL_ONE,GL_ONE)gl_blend_func["max"]=(GL_MAX,GL_ONE,GL_ONE,GL_MAX,GL_ONE,GL_ONE)

As Ren'Py uses premultiplied alpha, the results of some of these may be counterintuitive when a pixelis not opaque. In the GPU, the color (r, g, b, a) is represented as (r * a, g * a, b * a, a), and the blend functionuses these premultiplied colors. This may be a different result that you get for these blend modes in a paint program,when what is drawn is not fully opaque.

Float, Sample, and Vector Uniforms

The following uniforms are made available to all models.

vec2u_model_size

The width and height of the model, as supplied to Ren'Py. Thisis only available for 2D models that supply a size, and is (0, 0)for 3d models.

floatu_lod_bias

The level of detail bias to apply to texture lookups. This may beset in a Transform. The default value, taken fromconfig.gl_lod_biasand defaulting to -0.5, biases Ren'Py to always pick the next biggerlevel and scale it down.

floatu_time

The time of the frame. The epoch is undefined, so it's best to treatthis as a number that increases by one second a second. The time ismodulo 86400, so it will reset to 0.0 once a day.

vec4u_random

Four random numbers between 0.0 and 1.0 that are (with incredibly highlikelyhood) different from frame to frame.

vec4u_viewport

This gives the current viewport being drawn into. u_viewport.xy isare the coordinates of the bottom-left corner of the viewport, relativeto the bottom-left corner of the window. u_viewport.pq is the widthand height of the viewport.

vec2u_virtual_size

This is the virtual size of the game (config.screen_width,config.screen_height).This can be used to convert from gl_Position to virtual coordinates using:

v_position=u_virtual_size*vec2(gl_Position.x*.5+.5,-gl_Position.y*.5+.5)
vec2u_drawable_size

The size of the drawable are of the windows, in pixels, at the resolutionthe game is running at. For example, if a 1280x720 game is scaled up to1980x1080, this will be (1920, 1080).

sampler2Dtex0,sampler2Dtex1,sampler2Dtex2

If textures are available, the corresponding samplers are placed inthis variable.

vec2res0,vec2res1,vec2res2

If textures are available, the size of the textures are placed in thesevariables. When the texture is loaded from disk, this is the size of theimage file. After a render to texture, it's the number of drawable pixelsthe rendered texture covered.

If a sampler uniform is available, then suffixing it with__res will give a vec2containing the underlying texture size. For example,u_markup__res will give the size of theu_markup texture.

If a vec4 uniform is available, then suffixing it with__premul will give a vec4containing the premultiplied color. For example,u_color__premul will give a vec4where the red, green, and blue channels are multiplied by the alpha channel.

Matrix Uniforms

The following uniforms are made available to all models. This assumes that only one transform with theperspective property is used to render a model. When multiple transforms with theperspectiveare used, the innermost transformation with perspective set defines the world and view spaces.

mat4u_projection

This is a matrix that transforms coordinates from view space to the OpenGL viewport.This is sent by Ren'Py, and is updated by transforms with theperspective propertyto encapsulate the effects of that property.

mat4u_view

This is a matrix that transforms vertex coordinates from the world space to the view space. Thisdefaults to the identity matrix, but can be set by transforms with theperspective property,in which case the effects of positioning, rotation, and scaling are encapsulated in this matrix.

mat4u_model

This is a matrix that transforms vertex coordinates from the model space to the world space.

mat4u_projectionview

This matrix containsu_projection*u_view. It exists to minimize the number of uniforms that needto be sent to the GPU, and the amount of work that needs to be done in the shader.

mat4u_transform

This is the same asu_projectionview*u_model. It's the matrix that transforms vertex coordinatesdirectly to the OpenGL viewport. It exists to minimize the number of uniforms that need to be sent to the GPU,the amount of work that needs to be done in the shader, and for compatibility with older versions of Ren'Py.

In addition to these methods, Ren'Py can synthesize matrices with certain functions applied when suffixes areappended to the matrix

__inverse

When appended to a matrix, this returns the inverse of the matrix. For example,u_projection__inverseis the inverse of the projection matrix.

__transpose

When appended to a matrix, this returns the transpose of the matrix. For example,u_view__transposeis the transpose of the view matrix.

__inverse_transpose

When appended to a matrix, this returns the inverse of the transpose of the matrix. For example,u_model__inverse_transpose is the inverse of the transpose of the model matrix. This is useful fortransforming normals.

Attributes

The following attribute is available to all models:

vec4a_position

The position of the vertex being rendered. This is in virtual pixels, relative to the upperleft corner of the texture.

If textures are available, so is the following attribute:

vec2a_tex_coord

The coordinate that this vertex projects to inside the textures.

If normals are available, so is the following attribute:

vec3a_normal

The normal of the vertex being rendered.

If tangents are available, so are the following attributes:

vec3a_tangent

The tangent of the vertex being rendered.

vec3a_bitangent

The bitangent of the vertex being rendered.

GL Properties

GL properties change the global state of OpenGL, or the Model-Based renderer.These properties can be used with a Transform, or with theRender.add_property()function.

gl_blend_func

If present, this is expected to be a six-component tuple, which isused to set the equation used to blend the pixel being drawn with thepixel it is being drawn to, and the parameters to that equation.

Specifically, this should be (rgb_equation,src_rgb,dst_rgb,alpha_equation,src_alpha,dst_alpha). These will be used tocall:

glBlendEquationSeparate(rgb_equation,alpha_equation)glBlendFuncSeparate(src_rgb,dst_rgb,src_alpha,dst_alpha)

Please see the OpenGL documentation for what these functions do.OpenGL constants can be imported from renpy.uguu:

initpython:fromrenpy.uguuimportGL_ONE,GL_ONE_MINUS_SRC_ALPHA

Theblend transform property is generally an easy way touse this.

gl_color_mask

This is expecting to be a 4-tuple of booleans, corresponding to the fourchannels of a pixel (red, green, blue, and alpha). If a given channel isTrue, the draw operation will write to that pixel. Otherwise, it willnot.

gl_cull_face

If not None, this enables face culling, which is the process of removingtriangles that are facing away from the camera. To do this, we need toknow which face is the front face, and which is the back face. The front faceis determined using the winding order of the vertices, which is one of "cw" (clockwise) or "ccw" (counter-clockwise).The values are done in the Ren'Py coordinate system (with +Y down), which is the opposite of the OpenGL coordinate system.

gl_depth

If True, this will clear the depth buffer, and then enable depthrendering for this displayable and the children of this displayable.

Note that drawing any pixel, even transparent pixels, will updatethe depth buffer. As a result, using this with images that havetransparency may lead to unexpected problems. (As an alternative,consider thezorder andbehind clauses of theshow statement.)

gl_pixel_perfect

When True, Ren'Py will move the mesh such that the first vertex is aligned witha pixel on the screen. This is mostly used in conjunction with text,to ensure that the text remains sharp.

The following properties only take effect when a texture is being created,by a Transform withmesh set, or byModel(), where thesecan be supplied the property method.

gl_drawable_resolution

If True or not set, the texture is rendered at the same resolutionas the window displaying the game. If False, it's rendered at thevirtual resolution of the displayable.

gl_anisotropic

If supplied, this determines if the textures applied to a mesh arecreated with anisotropy. Anisotropy is a feature that causes multipletexels (texture pixels) to be sampled when a texture is zoomed by adifferent amount in X and Y.

This defaults to True. Ren'Py sets this to False for certain effects,like the Pixellate transition.

gl_mipmap

If supplied, this determines if the textures supplied to a mesh arecreated with mipmaps. This defaults to True.

gl_texture_wrap

When supplied, this determines how the textures applied to a meshare wrapped. This expects a 2-component tuple, where the firstcomponent is used to set GL_TEXTURE_WRAP_S and the second componentis used to set GL_TEXTURE_WRAP_T, which conventionally are the X and Yaxes of the created texture.

The values should be OpenGL constants imported from renpy.uguu:

initpython:fromrenpy.uguuimportGL_CLAMP_TO_EDGE,GL_MIRRORED_REPEAT,GL_REPEAT

This can also be customized for specific textures.gl_texture_wrap_tex0 controlsthe first texture,gl_texture_wrap_tex1 the second,gl_texture_wrap_tex2, the third,andgl_texture_wrap_tex3 the fourth. While only these four are avalable through Transforms,it's possibe to supply "texture_wrap_tex4" or "texture_wrap_myuniform" to Render.add_property.

GLTFModel Displayable

The GLTFModel displayble allow you to load 3D models in the GLTF file format. This is what you should useif you have a 3D model you created in another program and want to display in Ren'Py.

classGLTFModel(filename:'str',shader:'str|tuple[str]'=(),tangents:'bool'=False,zoom:'float'=1.0,report:'bool'=False,**kwargs)

A displayable that loads a 3D Model in the GLTF format. This format is supported by many 3D tools. Ren'Pyuses theOpen Asset Importer (assimp) library to load GLTF models.

For the purposes of Ren'Py's 2D layout system, a GLTFModel has zero width and height. By default, the modelis loaded at the size found in the file that contains it. If required, thezoom may be used to scale it.

When multiple models are in use, thegl_depthTrue property should be supplied to the camera, so thatdepth testing is enabled. Ren'Py does not currently perform any culling of the model, so it'simportant to use models simple enough to be completely rendered.

filename

The filename of the model to display.

shader

Either a string or tuple of strings, giving the name of the shader to use.

tangents

If True, tangents will be included in the mesh.

zoom

A zoom factor that will be applied to the model. Many models naturally use the range -1 to 1, and so thismay need to be quite large to make the model visible.

report

If true, a report of the model will be printed to the log. This includes the uniforms that are used bythe model.

A displayable that loads a 3D Model in the GLTF format. This format is supported by many 3D tools. Ren'Pyuses theOpen Asset Importer (assimp) library to load GLTF models.

For the purposes of Ren'Py's 2D layout system, a GLTFModel has zero width and height. By default, the modelis loaded at the size found in the file that contains it. If required, thezoom may be used to scale it.

When multiple models are in use, thegl_depthTrue property should be supplied to the camera, so thatdepth testing is enabled. Ren'Py does not currently perform any culling of the model, so it'simportant to use models simple enough to be completely rendered.

filename

The filename of the model to display.

shader

Either a string or tuple of strings, giving the name of the shader to use.

tangents

If True, tangents will be included in the mesh.

zoom

A zoom factor that will be applied to the model. Many models naturally use the range -1 to 1, and so thismay need to be quite large to make the model visible.

report

If true, a report of the model will be printed to the log. This includes the uniforms that are used bythe model.

Some things we noticed:

  • Some models are very small, and need to be zoomed by 100x or 1000x to be useful.

  • The uniforms generating by each model can vary.

We recommend creating GLTF models with report=True, and then looking at log.txt to seethe size and what's available. It's then possible to scale the model and tocreate a suitable shader.

Limitations

GLTFModel currently does not include a default shader, so you must define and include a shader.Here is one possible shader that can be used with GLTFModel:

initpython:renpy.register_shader("example.lighting",variables="""        uniform mat4 u_model__inverse_transpose;        uniform vec4 u_color_diffuse;        uniform vec4 u_color_specular;        uniform sampler2D u_tex_diffuse;        varying vec3 v_normal;        varying vec2 v_tex_coord;        attribute vec3 a_normal;        attribute vec2 a_tex_coord;""",vertex_201="""        v_normal = (u_model__inverse_transpose * vec4(a_normal, 1.0)).xyz;        v_tex_coord = a_tex_coord;""",fragment_201="""        // The direction of the light.        vec3 lightDir = normalize(vec3(0.0, -1000.0, 1000.0));        vec3 normal = normalize(v_normal);        float lambertian = max(dot(normal, lightDir), 0.0);        vec4 diffuse_color = texture2D(u_tex_diffuse, v_tex_coord.xy);        diffuse_color *= vec4(lambertian * u_color_diffuse.rgb * u_color_diffuse.a, u_color_diffuse.a);        vec3 viewDir = normalize(vec3(0.0, 0.0, -1.0));        vec3 halfDir = normalize(lightDir + viewDir);        float specular = pow(max(dot(normal, halfDir), 0.0), 4.0);        vec4 specular_color = vec4(u_color_specular.rgb * u_color_specular.a * specular, u_color_specular.a * specular);        gl_FragColor = diffuse_color + specular_color;        if (gl_FragColor.a < 0.9) {            discard;        }""")

This is a very simple shader that applies diffuse and specular lighting to the model basedon a single light source, meant for experimentation until better shaders are created.

GLTFModel does not support transparent surfaces well. While the discard command above emulatestransparency, the ordering is a bit wrong and can lead to artifacts.

Model Displayable

The Model displayable acts as a factory to created models for use with themodel-based renderer. This is an older API you may wish to use when you want to createmodels in Python.

classModel(size=None,**properties)

This is a displayable that causes Ren'Py to create a 2D or 3D modelfor use with the model-based renderer, that will be drawn in a singleoperation with the shaders given here, or selected by an enclosingTransform or Displayable.

size

If not None, this should be a width, height tuple, that's used togive the size of the Model. If not given, the model is the sizeof the area provided to it. The fit parameter to a texture takesprecedence.

If no mesh method is called, a mesh that sets a_position and a_tex_coordto match the way Ren'Py loads textures is created if at least one textureis supplied. Otherwise, a mesh that only sets a_position is used.

All methods on this calls return the displayable the method is calledon, making it possible to chain calls.

child(displayable,fit=False)

This is the same as the texture method, except that thefocusandmain parameters are set to true.

grid_mesh(width,height)

Creates a mesh that consists of a width x height grid of evenlyspaced points, connecting each point to the closest pointsvertically and horizontally, and dividing each rectangle inthe grid so created into triangles.

width,height

The number of points in the horizontal vertical directions,a integer that is at least 2.

property(name,value)

Sets the value of a gl property.

name

A string giving the name of the GL property, including the "gl_"prefix.

value

The value of the gl property.

shader(shader)

Adds a shader to this model.

shader

A string given the name of a shader to use with this model.

texture(displayable,focus=False,main=False,fit=False,texture_wrap=None)

Add a texture to this model, by rendering the given displayable.The first texture added will betex0, the secondtex1, aand so on.

focus

If true, focus events are passed to the displayable. It'sassumed that coordinate relative to the model map 1:1 withcoordinates relative to the displayable.

main

If true, this is marked as a main child of this displayable,which allows it to be inspected using the displayableinspector.

fit

If true, the Model is given the size of the displayable.This may only be true for one texture.

texture_wrap

If not None, this is thegl_texture wrap GL property that will be appliedto this texture.

uniform(name,value)

Sets the value of a uniform that is passed to the shaders.

name

A string giving the name of the uniform to set, including the"u_" prefix.

value

The value of the uniform. Either a float, a 2, 3, or 4 elementtuple of floats, or a Matrix.

Model Displayable Examples

The Model displayable can be used in conjunction with an ATL transform anda built-in shader to create the Dissolve transform:

transformdt(delay=1.0,new_widget=None,old_widget=None):delaydelayModel().texture(old_widget).child(new_widget)shader['renpy.dissolve']u_renpy_dissolve0.0lineardelayu_renpy_dissolve1.0

Using the Model displayable as the child of a displayable is incompatiblewithmesh, as the two both create models inside Ren'Py.

Animated Shaders

When using shaders that depend onu_time to animate, one must be aware,that even though every shader on screen will run on every frame displayed,Ren'Py does not run on constant FPS, and will fall back to the minimum framerate of 5 FPS if no displayables require to be redrawn.

When using an animating shader in an ATL transform, this can cause that shaderto "stutter" and only animate properly while some other object on screenanimates as well, in case the transform you're using it in does not causeredraws otherwise. In this case, an empty ATL loop can be introduced to forceredraws to happen:

transformfancy_shader:shader'my_fancy_shader'pause0repeat

pause0 will cycle the frames as fast as possible. You can also setdifferent values forpause to specify a minimum frame rate, likepause1.0/30.

Shader Parts

For a list of shader parts that Ren'Py uses, see theDefault Shader Parts.