This is a part of my Audiosurf 2 scripting documentation.
This page documents the version released May 29, 2014. Some changes have been integrated since then but it is currently inconsistent.
type name = default or choice2 or choice3 -- extra information
If I write ?=
instead of =
that means omitting the value will cause the existing value or default to be preserved. Only matters if you're calling the function more than once.
The skin script is executed during the loading screen when starting a song. A function in the script named Update()
, if present, will be executed every frame during actual gameplay.
This function is executed inside of Unity's LateUpdate function.
Arguments:
float dt -- the current value of Unity's deltaTime value
float tracklocation -- The fractional index of the track node that the player is currently "on". (When the player is halfway between nodes 3 and 4, CurrentNode is 3.5)
float playerstrafe -- the player's current offset from the center of the track
float currentWakeboarderJumpHeight
float intensity -- the same as GetIntensity()
Outputs the specified string to "Audiosurf2_Data\output_log.txt".
print("Track width: " .. trackWidth)
The current mod allows jumping. (wakeboard mod etc)
Prints the amount of time elapsed since the last time this function was called. The argument should be the name of your skin.
table pos {
float x
float y
float z
}
float seconds
table color {
float r
float g
float b
float a
}
-- the following rotation values are in degrees. they are the node's absolute rotation not delta
float pan -- rotation around the y axis
float tilt -- x
float roll -- z
vector3 rot -- same as {tilt, pan, roll}
float intensity -- normalized intensity
bool funkyrot -- if this is in a corkscrew or loop
float antiairtime -- "anti jump seconds"
float trafficstrength
float antitrafficstrength
The current normalized intensity.
An alias of UpdateSpectrum(nil)
Gets the music frequency spectrum of the current point in song playback. If you pass a table
as the argument, it will set the spectrum values into that table instead of creating a new table. (Reusing the same table every frame improves performance.)
The magnitude seems to be in the range 0 to 2. From what I've read, this way of producing a smaller spectrum is technically different from what you would get if you directly calculated a 16 bin spectrum. A smaller FFT would use information from a smaller time span and so change more rapidly.
spectrum = UpdateSpectrum(spectrum)
for i=1,#spectrum do
local bin = spectrum[i]
-- To get the magnitude of a bin:
local magnitude = math.sqrt(bin)
-- To convert the above magnitude to decibels:
local db = 20 * math.log10(magnitude / 2)
-- If you aren't going to use magnitude, you can optimize the decibels equation:
local db = 10 * math.log10(bin / 4)
-- Getting the above values in a useful 0 to 1 range:
local magnitude_normalized = magnitude / 2
local db_normalized = math.min(0, (db + 60) / 60) -- Cut off values less than -60db.
end
Currently, the beginning and end sections of gameplay when audio isn't playing are glitched. In the beginning the spectrum returns unpredictable random values as if it is reinterpreting arbitrary memory. In the end, the values either freeze at their last position or produce more noise. Here is how you can deal with that if it causes you problems:
track = GetTrack() -- Your skin probably already does this. Avoid doing it more than once because it's expensive.
-- Some extra nodes with negative time are added to the start of the track.
local first_real_node
for i=1,#track do
if track[i].seconds >= 0 then
first_real_node = i
break
end
end
if first_real_node == nil then error("negative length song") end
-- Currently the number of extra nodes at the end is always 44. They are clones of the last node with modified position/seconds and zero maxair/trafficstrength.
local last_real_node = #track - 44
local spectrum, UpdateSpectrum = GetSpectrum(), UpdateSpectrum
function Update()
if location >= first and location <= last then
UpdateSpectrum(spectrum)
else
for i=1,#spectrum do spectrum[i] = 0 end
end
-- Do things with the spectrum here.
end
I have only skimmed the code but it looks like this is a variant of GetSpectrum
that splits up the 512 bin spectrum logarithmically rather than linearly before averaging them down to 16. ("horizontal" log scale) The numeric scale of the individual bins ("vertical" scale) is the same as the regular spectrum. It seems to have been forgotten about when UpdateSpectrum
was added.
This gets the full 512 bin audio spectrum that UpdateSpectrum
and GetLogSpectrum
read from internally to produce their results.
Unity's Time.realtimeSinceStartup * 1000.
Note that this is the time since Audiosurf 2 started (potentially more than an hour ago) not the time since this particular track started. Can be useful as a seed to math.randomseed
if non-deterministic behavior is desired. (By default it is seeded with the song length.)
Gets the highway color at the current point in song playback. The returned table contains both styles of color. (color.r
and color[1]
are equivalent)
The current point in song playback. The returned number ranges from 0.0 to 1.0.
Output:
bool *
double *
string *
{*=*} * -- Keys and values can be a mixture of bool, double, and string.
int colorcount -- Set by GameplaySettings{colorcount}, defaults to 1.
Mods can add whatever values they want to the table as long they are one of the basic Lua types. The values can also be Lua tables with keys and values of any of the basic types. Functions and deeper nested tables are not supported, but mods could include them as strings and the skin could convert the strings into Lua code via loadstring()
. Mods can add and overwrite skin properties at any time; skins can call the function again during Update
to see the changes. (The automatic system used internally to transfer the values from mods to skins also supports light userdata, but I don't think Audiosurf 2 ever produces that type and it can't be created by scripts.)
These are the default entries that usually get overwritten by mods:
SetSkinProperties{
lanedividers = {-1.5, 1.5},
shoulderlines = {4.5, -4.5}, -- [sic]
trackwidth = 11.6,
prefersteep = false,
}
These are the properties set by built-in mods and the ones based on them:
double trackwidth
bool prefersteep
double[] lanedividers
double[] shoulderlines
Here are extra properties I have been voluntarily supporting in my skins:
double disableWater -- set a nonzero number to disable water
double forceLaneDividers set a nonzero number to keep the skin from ignoring them if there aren't many of them
double trackheight -- ask for extra vertical empty space above the track floor
double skinnyGreyBlocks -- set to 0 if your grey blocks have the same hitbox as normal blocks, any other number if they have a skinny hitbox like the ones in GameplaySettings{automatic_traffic_collisions = true}
(bool
properties weren't supported in the past and I haven't yet updated my skins, but I will add support eventually.)
As always, contact me if you have something to add.
Gets the folder name of the current mod, converted to lowercase.
Gets the value set by GameplaySettings{trafficcompression}
. The default is 0.65
.
Returns math.min(3, GetQualityLevel4())
Returns the Unity quality level plus 1.
int mincount = 3
int maxcount = 5
Color format: {r=0-1, g=0-1, b=0-1, a=1}
Reads the <ALBUMART>
texture with a tool named Color Thief and produces colors that presumably came from that image. If there is no album art it generates mincount
random colors. (Each color is just 3 random floats between 0.0 and 1.0 inclusive. There is no attempt to avoid greys or produce a tasteful palette.)
According to Dylan: It picks out prominent colors from the album art image. Less colorful images return less colors and if you force it to return more with a high mincount
the colors will have less variation.
mincount
and maxcount
used to be bugged but it is fixed now.
True if the current song is a video.
In case you aren't familiar with Lua syntax, a function name followed by braces is shorthand for calling the function with a single argument which is a table. So, Foo{bar=1}
and Foo({bar=1})
are equivalent.
-- if this is the first run
float maxAllowedTrackHeight = 10000000000
float camStaticZone = 0
-- if this is a dedicated skin (included with the mod)
-- Forced to be "straight" if mod sets GameplaySettings{sideview=true}
.
string/table twistmode ?= nil or "cork" or "straight" or "straightish" or "straightisher" or "straightishest" or "straightishest_flatishest" or "straightishest_flatish" or "straightisher_flatish" or "straight_flat50" or "straight_flat25" or "straight_flatish" or "straight_flatisher" or "straight_flatishest" or "straight_flat" or "cork_flatish" or "circle" or "default" or table {
-- Cork twist mode.
float curvescaler = 1
float steepscaler = 1
}
-- end
bool water = true -- When setting this to false, water is permanently deactivated. Setting it to true again will set a flag that water is in use without actually re-activating the water surface object.
int numvisiblewaterchunks = -1 -- Any value 1 or less is replaced with 4 or 8, depending on how much graphics memory is available.
bool towropes ?= false -- Wakeboard mode effect that connects pullermodel to SetPlayer{surfer={arms}}.
bool usebackgroundcamera = true -- Once set to false it can't be re-enabled.
-- end
vector3[] waterclones = nil
color skywirecolor ?= nil
string minimap_colormode = "track" or "white" or "black" or "greyscale"
bool use_intro_swoop_cam = true -- Only alters the camera behavior; doesn't change the interval of silence before the song.
int glowpasses ?= 4 -- Glow changes take effect next frame. If a pass count less than 1 is applied, the glow effect will be permanently disabled. Passes greater than 30 become 30. The glow "intensity" is always 1.5.
float glowspread ?= 0.5 -- Values are clamped to the range 0.5 to 1.0.
float radialblur_strength ?= 1.0 -- Changes will be applied on the next frame. 0.0 disables the effect. The actual radial blur strength per-frame is math.min(1.5, math.max(0, current_camera_bias - 0.6) * 5) * fif(is_jumping, 0, 1) * radialblur_strength
bool hide_default_background_verticals ?= false -- Objects that draw on top of other objects in the background camera. This was used to add a special effect to the skywires but tends to interfere with other uses of the background camera. Once hidden they cannot be un-hidden.
float crease_strength ?= 0 -- Cannot be set back to 0 once changed.
bool dynamicFOV ?= false -- While true, the setting changed by SetPlayer{fov} is ignored.
float closecam_near ?= ? -- Changes the near clip plane of the close camera (layers 14 and 15).
float closecam_far ?= 50
-- if airdebris_count ~= nil or airdebris_density ~= nil or airdebris_particlesize ~= nil or airdebris_fieldsize ~= nil or airdebris_layer ~= nil
-- Air debris uses the StarFieldBlack shader with default settings and a render queue of 3900.
int airdebris_count = 500 -- "Sprites per chunk".
int airdebris_density = 10 -- "Sprites each ring".
float airdebris_particlesize = 1 -- "Particle scaler".
float airdebris_fieldsize = 300 -- "Cell size".
int airdebris_layer = 11
-- end
float airdebris_flashsizescaler = 1
string airdebris_texture ?= UnityEngine.Resources.Load("particle_ellipse.png") -- AsyncLoadTextureThenBroadcastTo(mipmaps: yes, wrapMode: Clamp (BUG))
color watertint ?= ?
bool widewater ?= false -- Water width is 11.25 normally or 16.25 wide. When turned off, width is not changed back to 11.25 but water simulation behavior does change back.
float minwaterrandomdarkness ?= 0.5 -- Individual water cubes will be tinted to a random greyscale color between this and 1.
int watertype = 0 -- Changes the water shader. Type 1 (default): GpuOffsetCubes, type 2: GpuOffsetCubesNoLines
bool watertint_highway = false -- Water color changes to the current highway color automatically. If enabled, only the alpha of watertint will be used.
address watertexture ?= ? -- AsyncLoadTextureThenBroadcastTo(mipmaps: no, wrapMode: Clamp (BUG))
bool usecubewater ?= true -- When false, water will be disabled after the skin loads.
bool usedefaultrails ?= false
bool fogenabled = false -- Enables or disables fog. Also sets UnityEngine.FogMode.Linear when true.
color fogcolor ?= ?
float fogdensity ?= ? -- unused in this fog mode
float fogstart ?= ?
float fogend ?= ?
bool fog_allowcolorshiftwhenjupming = true -- Temporarily overrides fog settings (on: true, color: highwaycolor * 0.6, mode: ExponentialSquared) at the start of jumps greater than 1 second and restores "normal" settings after the jump. "Normal" settings are determined by checking the fog settings once, on gameplay start, so you may need to turn this off if doing your own dynamic fog effects.
color/string ambientlight = {51,51,51,255} or "highway" or "highwayinverted" -- Changes RenderSettings.ambientLight. Accessible in shaders via UNITY_LIGHTMODEL_AMBIENT. The dynamic color setter enabled by the string settings cannot be switched off once enabled, but setting the constant color every frame may be enough to override it.
bool useblackgrid ?= true
string pullermodel ?= ? -- The wakeboard mode "boats" that connect to towropes and SetWake.
Skins have only limited control over the water effect:
watertype = 1
), GpuOffsetCubesNoLines (watertype = 2
)
Blend SrcAlpha OneMinusSrcAlpha
half4 color = tex2d(_MainTex, vertex.texcoord.xy) * _Color * vertex.color; half4 body = color * vertex.texcoord.z * 10; return register0.x == 0 ? body : half4(color.xyz, 0.01);
watertexture
is loaded with "repeat" wrapping (due to a bug) and no mipmaps. I have not found any official documentation on the significance of different areas of the texture and haven't studied it.
GameplaySettings{usejumpmarkers=true}
, Audiosurf 2 will try to draw a 3 pixel thick opaque white stripe horizontally through the texture. (BUG: This will cause a crash unless the texture is writable. One might be able to work around this by manipulating the texture cache to contain a writable texture.) The center of the line is calculated to be offset (height * 0.37)
from the bottom of the image. Therefore, by varying the resolution of the image, you could change how thick the line is from the shader's perspective.watertint
and watertint_highway
directly control the _Color
of the material.minwaterrandomdarkness
produces random shades of grey in the vertex color. All 8 vertices of each cube are the same color.numvisiblewaterchunks
setting, the range to expect water in is 2990-2998.numvisiblewaterchunks
is fif(gpu_megabytes > 3 * (#GetTrack() / 84), 4, 8)
. The debug console will have "Prebuilding 84-ring-size wave chunks" if the default is 4 and "Live building 21-ring-size wave chunks" if it is 8. (There is no way for Lua to change the rendering mode mentioned in those console lines.) Since this setting appears to have significant performance implications, it is probably best to leave it alone in most graphics quality modes unless it is causing your skin problems.waterclones
lists relative world-space coordinates to render the water surface extra times in different locations. There is no provision for giving them a different rotation, shape, or material. This can't be used to reliably do much unless used with mods that have some limitation on track shape.widewater
widens water from 11.25 to 16.25 and alters water behavior.water
and usecubewater
is aside from that one "deactivates" water and the other "disables" it. If you aren't using water, setting both to false might be best for performance. (Untested.)SetWake
SetPlayer{ vehicle = { use_water_rooster, roostercolor, water_rooster_z_offset }, airvehicle, watervehicle, surfer = { use_water_rooster, roostercolor, water_rooster_z_offset }, }
CreateLight{floatonwaterwaves}
CreateObject{floatonwaterwaves}
SetBlocks{colorblocks = {float_on_water}}
BatchRenderEveryFrame{waterfloat}
Set the sequence of colors that get turned into the "highway colors" gradient. The first color is the low intensity color.
Block colors used by puzzle gamemodes.
One of the Audioshield things present in Audiosurf 2. I haven't checked if these colors get used by anything.
Only the first 3 colors in the array will be used. If you supply less than 3 values, the missing values will be 50% grey. Pass a nil
array to set default colors:
SetShieldColors(nil)
-- same as
SetShieldColors{
{53, 141, 255},
{255, 52, 0},
{103, 53, 176},
}
Exactly the same as SetShieldColors
, including the default values, but sets the "spark colors".
Exactly the same as SetShieldColors
, including the default values, but sets the "orb colors".
Adds or replaces a named sound effect, which can be invoked by Audiosurf 2 or mods. Names are case-insensitive.
Change the position of the video screen, if one exists.
float fov = 90
bool cameraortho = false -- orthographic cameras
bool cameraignoreslope = false
float cameraHeightTrackingRatio = 1
string cameramode = "first" or third" or "first_jumpthird" or "first_trickthird" or "third_trickjumpthird" -- case insensitive. throws an exception if it is a string that doesn't match
string cameradynamics = null or "high" -- "use extra dynamic camera", adjust the camera "bias"
table camfirst ?= nil or {
vector3 pos = {0,0,0} -- default if camfirst is nil: {1, 2.7, 3.50475}
vector3 rot = {0,0,0} -- default if camfirst is nil: {20.49113, 0, 0}
float strafefactor ?= 1
float puzzleoffset ?= 0 -- "ring offset"
}
table camthird ?= nil or { -- pos/rot is called "near" and pos2/rot2 "far"
vector3 pos = {0,0,0} -- default if camthird is nil: {1, 3.9, -0.23}
vector3 rot = {0,0,0} -- default if camthird is nil: {20.49113, 0, 0}
float strafefactor ?= 0.5
-- if pos2 is nil, pos2/rot2/strafefactorFar are set to the current values of pos/rot/strafefactor and your settings for rot2/strafefactorFar are ignored
vector3 pos2 = {0,0,0} -- default if camthird is nil: {1, 1.8, -3.17}
vector3 rot2 = {0,0,0} -- default if camthird is nil: {25.836, 0, 0}
float strafefactorFar ?= 1
float transitionspeed ?= 1 -- "smooth bias speed"
float puzzleoffset ?= 0 -- "ring offset close"
float puzzleoffset2 ?= 0 -- "ring offset far"
}
-- First run only:
table vehicle = ? or { -- strange things may happen if this is omitted during the first run
gameobject * -- all of the variables from gameobject are included directly inside this table
bool reflect ?= false -- cannot be disabled once set to true
float min_hover_height = 0
float max_hover_height = 0
bool use_water_rooster = true -- cannot be re-enabled once set to false
float rollscaler = -1
float panscaler = 0
bool smooth_tilting = false
float smooth_tilting_speed = 10
float smooth_tilting_max_offset = -20
float water_rooster_z_offset = -1.04
color roostercolor = {0.133, 0.22, 0.486, 1}
}
gameobject airvehicle ?= nil
gameobject watervehicle ?= nil
table surfer ?= nil or {
bool use_water_rooster = true
color roostercolor = {0.133, 0.22, 0.486, 1}
float water_rooster_z_offset ?= -1.04
gameobject arms ?= ? or {
-- The object will be completely created in the usual way, and then some things will be shallow copied to the real object.
UnityEngine.MeshFilter.mesh
UnityEngine.Renderer.sharedMaterial
UnityEngine.Renderer.castShadows
UnityEngine.Renderer.receiveShadows
}
gameobject leg ?= arm or {
-- The object will be completely created in the usual way, and then some things will be shallow copied to the real object.
UnityEngine.MeshFilter.mesh
UnityEngine.Renderer.sharedMaterial
UnityEngine.Renderer.castShadows
UnityEngine.Renderer.receiveShadows
}
gameobject body ?= ? or {
-- The object will be completely created in the usual way, and then some things will be shallow copied to the real object.
UnityEngine.MeshFilter.mesh
UnityEngine.Renderer.sharedMaterial
UnityEngine.Renderer.castShadows
UnityEngine.Renderer.receiveShadows
UnityEngine.GameObject.layer -- Default: 14
}
gameobject board ?= ? or {
-- The object will be completely created in the usual way, and then some things will be shallow copied to the real object.
UnityEngine.MeshFilter.mesh
UnityEngine.Renderer.sharedMaterial
UnityEngine.Renderer.castShadows
UnityEngine.Renderer.receiveShadows
}
gameobject towrope_node ?= ? or {
-- The object will be completely created in the usual way, and then some things will be shallow copied to the real object.
UnityEngine.Renderer.sharedMaterial
}
gameobject towboat ?= ? or {
-- The object will be completely created in the usual way, and then some things will be shallow copied to the real object.
UnityEngine.Renderer.sharedMaterial -- materialcolor dynamic colors will be disabled. Maybe because it is going to apply its own dynamic coloring. UpdateMaterial should still work.
}
}
-- End of first run only
SetBackgroundColor{0, 127, 255} -- #007FFF
Sets the background color of the "main camera", which will permanently change the camera mode to clear whatever was drawn by previous cameras. I don't know which camera is the main camera.
-- Some things in this list have the same name because that name can contain any one of the listed types.
materialcolor color ?= ? -- Can be used with skysphere, string sky, and custom.
string sky = nil -- Loads an embedded skybox material. Internally loads a resource named like "Skyboxes/sky/sky". (TODO: find a way to list them.)
table sky = nil or {
-- This table controls Silver Lining.
int month = 2.0
int hour = 12.0
int minute = 0.0
double cloudmaxheight = 1.1 -- Cumulus clouds. 1.0 is the top of the level (track boundaries), -1.0 is the bottom, and 0 is the center.
double cloudminheight = -1.1 -- These two settings are ignored if cloudminheight and cloudmaxheight are specified.
double clouddensity = 0.6 -- 0 or less disables cumulus clouds. setting this too high causes severe graphical glitches and lag.
double cirrusposition = 0.0 -- 0 disables cirrus clouds. Positive and negative numbers are offset from the top and bottom of the track, respectively.
bool showsun = true
vector3 cloudboundsmin = -- By default Y uses cloudminheight, XZ is max(80000, track_bounds.min.XZ * 2).
vector3 cloudboundsmax = -- By default Y uses cloudmaxheight, XZ is max(80000, track_bounds.max.XZ * 2).
bool flare = true -- Once turned off it cannot be turned back on. Unlike the other settings, this one is guaranteed to take effect.
double latitude ?= 42
double longitude ?= 185.6
bool useProceduralAmbientLight ?= true
bool useProceduralSunLight ?= true
vector3 windspeed ?= {10, 0, 10}
}
{string=address} custom = nil -- AsyncLoadTextureInto(wrapMode: Clamp). Names to use: _BackTex _DownTex _FrontTex _LeftTex _RightTex _UpTex
-- IF custom is a table these values will be read as nil:
address skysphere ?= ? or "default" or (...) -- AsyncLoadTextureInto(wrapMode: Repeat, mipmaps: no). "default" will leave the texture at its current setting but allow you to change the other settings. This setting is only applied on the first run but you must supply a string whenever you want to change the other skysphere settings.
UnityEngine.Material skysphere ?= ?
string skyscreen -- Shader name.
UnityEngine.Material skyscreen
int skyscreenlayer = 18 -- If the background camera is disabled, it uses layer 13 instead of your setting.
vector3 skyScreen_TrackOffset = nil -- A position in node space.
vector3 skyScreen_FixedTrackOffset = nil
-- END IF
-- IF skysphere is a string:
rotation sphererot ?= ? -- If you want to change this setting on the UnityEngine.Material version of skyscreen, call SetSkybox a second time with skyscreen = "default".
string emissionmap ?= ? -- SyncLoadTexture(wrapMode: Clamp, mipmaps: no)
vector2 texturescale ?= ?
vector2 textureoffset ?= ?
-- END IF
If your table does not satisfy at least one of these conditions, SetSkybox
will exit early without applying most changes.
skyscreen
is a string
or Material (and custom
is not a table
).skysphere
is a string
or Material (and custom
is not a table
).(sky as string)
is different from the last time.color
is a color
and it wasn't last time, or vice versa.color
is a color
and that color is different from last time.(custom as table)
, converted to a string
, is different from last time. (Bug: Values used to be included and now they aren't. Adding and removing unused keys should be enough to force it to recognize a difference.)sky
is a table
and it wasn't last time, or vice versa.sky
is a table
and any of these values (or their defaults, if unspecified) are different from the last time:
The "last time" memory is only updated by successful runs, and all of its variables start at zero/nil. Unspecified values will be remembered as if their defaults were specified.
If sky
is a table
its settings will be applied and will not block any other settings. If it is not a table, Silver Lining will be disabled.
The following settings are checked in order and if one contains the required type then it will be applied and the settings after it will not be applied.
string/UnityEngine.Material skyscreen
string/UnityEngine.Material skysphere
string sky
table custom
color
will be applied. If you mix skyscreen
with one of the other 3, that one will also be applied with a null material because of a spaghetti bug.
Silver Lining is highly customizable but AS2 doesn't expose most of the interesting options or even most of the basic options. Here's some of the important locked settings:
It's not possible to alter these by setting one of the other values by a really big number; it rejects the entire time setting if one of the values is out of range. The daylight savings time setting is active no matter which time of year you specify, so the effective time zone is UTC -7 (pacific daylight time).
skysphere
SkyboxSetSkybox{
color = {1,1,1},
skysphere = "Sky.jpg",
texturescale = {1,1},
textureoffset = {0,0},
sphererot = {0,0,0},
--emissionmap = "SkyGlow.jpg", -- ???
}
I assume this takes a 360 degree "equirectangular" panorama texture.
custom
SkyboxSetSkybox{
color = {1,1,1},
custom = {
_FrontTex = "MySkybox/Front.jpg",
_BackTex = "MySkybox/Back.jpg",
_LeftTex = "MySkybox/Left.jpg",
_RightTex = "MySkybox/Right.jpg",
_UpTex = "MySkybox/Up.jpg",
_DownTex = "MySkybox/Down.jpg",
},
}
A classic 6-sided skybox, also known as a cubemap skybox. They have more consistent texture stretching than a spherical texture. (Converting an existing spheremap to a cubemap is probably pointless unless you're also going to decrease the resolution.)
skyscreen
SkyboxThis is for using procedural skybox shaders. Like a post-processing effect it simply draws your material as a full-screen quad but does so before the rest of the scene is drawn instead of after it. Shaders made for this purpose change what they draw based on the camera angle.
float latitude ?= 42
float longitude ?= 185.6
Updates parts of the Silver Lining skybox without having to deal with SetSkybox.
bool shadowcaster = false
bool shadowreceiver = false
int layer = 11
vector3 offset = {0,0,0}
float size = 0
float percentringed = 0
bool useairrings = true
-- if material is UnityEngine.Material
UnityEngine.Material material
-- else
string texture = nil -- AsyncLoadTextureInto()
string shader = nil -- Built-in shaders only.
-- end
float airsize = 0
-- if airmaterial is UnityEngine.Material
UnityEngine.Material airmaterial
-- else
string airtexture = nil -- AsyncLoadTextureInto()
string airshader = nil -- Built-in shaders only.
-- end
float height = 0.0
float fallrate = 0.0
int layer = 11
-- if material ~= nil
UnityEngine.Material material
-- else
material * -- All of the variables from material are included directly inside SetWake{}.
-- end
vector3[] offsets ?= {{7.5, 0, 0}, {-7.5, 0, 0}}
color/string bottomcolor = "highway" or "highwayinverted" or {1,1,1,1} etc
color/string topcolor = "highway" or "highwayinverted" or {1,1,1,1} etc
bool extraspray = false
The render queue is changed to be 3998 (can be changed after calling SetWake
to bypass) and _Color is forced to be white (cannot be bypassed).
The settings are not applied until a check is run to see if they are different from the current settings, and there are some bugs in this process:
offsets
is omitted it will not be compared.extraspray
is not compared.UnityEngine.Material/material puzzlematerial = nil
UnityEngine.Material/material puzzlematchmaterial = nil
UnityEngine.Material/material puzzleflyupmaterial = nil
bool usesublayerclone ?= true
address texture ?= ? -- AsyncLoadTextureThenBroadcastTo(mipmaps: no, wrapMode: Clamp (BUG))
float sizescaler ?= 1
float sizescaler_missed ?= 1 -- Until you set this explicitly, changes to sizescaler will be mirrored to sizescaler_missed.
UnityEngine.Material material ?= ?
int maxvisiblecount ?= 30
bool allow_mod_block_scaling = true
table chainspans ?= ? or {
bool hide ?= false
-- if material is UnityEngine.Material
UnityEngine.Material material
-- else if shader ~= nil
material * -- Create a new material.
-- else
-- Modify the default or previously set material.
shadercolors shadercolors ?= ?
address texture ?= ? -- AsyncLoadTextureInto()
-- end
}
table colorblocks ?= ? or {
vector3 scale ?= ?
float height ?= 0 -- Height offset. This might affect all blocks, not just colorblocks.
bool float_on_water = true -- This might affect all blocks, not just colorblocks.
bool reflect = false
-- if gameobject ~= nil
gameobject gameobject -- See below about prefabs.
-- else if material is UnityEngine.Material
UnityEngine.Material material
-- else if shader ~= nil
material * -- Create a new material.
-- else
-- Modify the default or previously set material.
shadercolors shadercolors ?= ?
address texture ?= ? -- AsyncLoadTextureInto()
-- end
UnityEngine.Mesh/mesh/address mesh ?= ?
-- if type(mesh) == "string" and type(meshmorph) == "string"
-- In this mode, OBJ file normals will be read from mesh and meshmorph.
address meshmorph
float meshmorphsmoothspeed ?= 5
string meshmorphtype = "intensity" or "intensitysmooth" or "intensitysmoothfall" or "intensitysmoothrise"
-- end
}
table greyblocks ?= ? or {
bool reflect ?= false
-- if gameobject ~= nil
gameobject gameobject -- See below about prefabs.
-- else if material is UnityEngine.Material
UnityEngine.Material material
-- else if shader ~= nil
material * -- Create a new material.
-- else
-- Modify the default or previously set material.
shadercolors shadercolors ?= ?
address texture ?= ? -- AsyncLoadTextureInto()
-- end
UnityEngine.Mesh/mesh/address mesh ?= ?
-- if type(mesh) == "string" and type(meshmorph) == "string"
-- In this mode, OBJ file normals will be read from mesh and meshmorph.
address meshmorph
float meshmorphsmoothspeed ?= 5
string meshmorphtype = "intensity" or "intensitysmooth" or "intensitysmoothfall" or "intensitysmoothrise"
-- end
}
{string=table} powerups ?= ? or {example = { -- Specifying a powerup will completely discard all of the powerup's previous settings.
-- if gameobject ~= nil
gameobject gameobject -- See below about prefabs.
-- else if material is UnityEngine.Material
UnityEngine.Material material
-- else if shader ~= nil
material *
-- else
address texture ?= nil -- AsyncLoadTextureInto(material: none) BUG: I don't think this setting branch does anything other than load the texture into the cache and log a "mat is null" error.
-- end
UnityEngine.Mesh/mesh/address mesh -- Unspecified mesh will cause errors later.
bool reflect = false
vector3 scale = {1,1,1}
int blockcolorid = nil
}, ...}
gameobject
Prefabscolorblocks
, greyblocks
, and powerups
accept a gameobject
setting but only specific aspects of the object and the object's children are referenced when rendering the blocks:
Overrides the color of "highway color" and "inverse highway color" blocks defined by GameplaySettings{ blocktype_highway, blocktype_highwayinverted }
If called in Update()
, changes will take effect on the next frame.
globalname globalName = nil -- typeName: "rail"
vector2 positionOffset = {0,0} -- added to every coordinate in crossSectionShape
vector2[] crossSectionShape ?= {
{-0.5, 0.5},
{ 0.5, 0.5},
{ 0.5, -0.5},
{-0.5, -0.5},
}
string textureMode = "repeataround" or "wraparound" or "wraparoundcontinuous" or "none" or "repeataroundreverse" or "wraparoundreverse"
string colorMode = "highway" or "highwayinverted" or "static" or "aurora" or "highwayflat" or "trackposition" or "highwayscaledfollowmaxjumpheights" -- The jumpheights option only works inside OnSkinLoaded
/OnRequestLoadObjects
.
int stretch = 1 -- referred to internally as "ring spacing"
color color ?= {r=0, g=0, b=0, a=0} -- (#1) (colorMode specific) There are multiple color settings with the same name. This one sets the vertex colors.
bool flatten = false -- (colorMode specific) "use guard rail heights"
float[] perShapeNodeColorScalers = nil -- (colorMode specific)
int layer = 11
bool allowfullmaterialoptions = false
-- if material ~= nil or allowfullmaterialoptions
-- if material is UnityEngine.Material
UnityEngine.Material material
-- else if type(material) == 'table'
material material
-- else
material * -- All of the variables from material are included directly inside this table.
-- end
-- else
string shader = "DiffuseVertexColored2" -- If it uses the default, other material settings are also applied. (See below. Specifying that shader explicitly will not apply the default settings.)
color color = white -- (#2) There are multiple color settings with the same name. This one applies to the material.
int renderqueue = 2000 -- Render queue. If you specify a number less than 1 it will use the shader's default.
{string=float} shadersettings ?= nil
shadercolors shadercolors ?= nil -- setting _Color here will work
address texture ?= nil -- AsyncLoadTextureInto()
-- end
vector3 skyScreen_TrackOffset ?= nil -- see here
vector3 skyScreen_FixedTrackOffset ?= nil
bool ignoretrackscale = true -- (colorMode specific)
int nodeskip ?= 1 -- referred to internally as "ring skip"
bool alphafromintensity ?= false -- (colorMode specific) Overwrites the vertex color alpha channel with the normalized intensity.
bool texturemirroreddowntrack ?= true
float textureTrackLength ?= 1.0
fload texturetracklength_offset ?= 0.0
bool fullfuture = false -- "render full track"
bool futureonly ?= false -- "stretch to finish"
bool calculatenormals = false
bool calculateNormals = false -- If either of these two is true, normals will be calculated.
vector3[] perShapeNodeNormals ?= nil -- (colorMode specific) These values are rotated by the node rotation but no other corrections are applied, so you may need to use ignoretrackscale to avoid incorrect normals.
bool perShapeNodeColorScalersScaleAlpha = true -- (colorMode specific) Forces the vertex color alpha to always be 100%.
color[] perShapeNodeColors ?= nil -- static mode only
-- Unused: int[] perShapeNodeFFTInfluenceIndices ?= nil
bool collider ?= false
vector3[] perTrackNodeScales ?= nil -- (colorMode specific) Scales rail segments individually. If specified and valid, positionOffset will be applied after scaling instead of immediately being added to crossSectionShape. Array length must match #GetTrack()
. Can also use the name scales. There is some inconsistency in the effects of this setting when an invalid value is specified, but I didn't notice anything useful.
vector3[][] crossSectionShapeList ?= nil -- (colorMode specific) Overrides crossSectionShape with multiple shapes, one for each track node. If shorter than the track it will repeat. The outer array must be a table but the inner arrays can be CLI UnityEngine.Vector3[] objects, which will be stored internally without further copying. (This can be used to make large shape lists of mostly reused shape objects with low memory usage.)
bool wrapnodeshape = true -- Connect the first and last points in crossSectionShape. Might be turned off if using a two-sided shader or the player will never see that side of the rail.
bool shadowcaster ?= true
bool shadowreceiver ?= true
colorMode
SettingThe colorMode
setting ostensibly controls the vertex colors of the rail, but in practice each mode has its own copy-pasted code for builing the rail and not all of them use all of the settings. Below are the used settings per mode. (The names in parentheses after the settings names are the internal names of those settings, put there for me to reference when updating this document.)
GetTrack()[...].color
(TrackServer.Node.color)stretch
(ringSpacing)flatten
(useGuardrailHeights)alphafromintensity
(intensityInVertexColorAlpha)crossSectionShape
(extrusionPoints)crossSectionShapeList
(shapeList)ignoretrackscale
(ignoreTrackScaler)OnRequestTrackReshaping()[...].widthscaler
/.heightscaler
(TrackServer.Node.trackScale)perTrackNodeScales
/scales
(ringScales)perShapeNodeColorScalers
(extrusionColorScalers)perShapeNodeColorScalersScaleAlpha
(extrusionColorScalersScaleAlpha)perShapeNodeColors
or color
(#1).stretch
(ringSpacing)flatten
(useGuardrailHeights)crossSectionShape
(extrusionPoints)crossSectionShapeList
(shapeList)ignoretrackscale
(ignoreTrackScaler)OnRequestTrackReshaping()[...].widthscaler
/.heightscaler
(TrackServer.Node.trackScale)perTrackNodeScales
/scales
(ringScales)perShapeNodeColors
(extrusionColors)color
(staticModeColor)perShapeNodeNormals
(extrusionNormals)GetTrack()[i].intensity
is. The alpha is multiplied as well. If all the highway colors have an alpha of 1 (the default) then this allows a shader to determine the exact intensity.stretch
(ringSpacing)flatten
(useGuardrailHeights)crossSectionShape
(extrusionPoints)crossSectionShapeList
(shapeList)ignoretrackscale
(ignoreTrackScaler)OnRequestTrackReshaping()[...].widthscaler
/.heightscaler
(TrackServer.Node.trackScale)perTrackNodeScales
/scales
(ringScales)perShapeNodeColorScalers
(extrusionColorScalers){0, 0, (node_index - 1) * 3}
.stretch
(ringSpacing)crossSectionShape
(extrusionPoints)perTrackNodeScales
/scales
(ringScales)perShapeNodeColorScalers
(extrusionColorScalers)EncodeFloatRGBA
. This is useful in rail skyscreen shaders. (I don't understand why he won't just pass this information through UV or UV2.)stretch
(ringSpacing)flatten
(useGuardrailHeights)crossSectionShape
(extrusionPoints)crossSectionShapeList
(shapeList)
ignoretrackscale
(ignoreTrackScaler)OnRequestTrackReshaping()[...].widthscaler
/.heightscaler
(TrackServer.Node.trackScale)perTrackNodeScales
/scales
(ringScales)origin.y = track[i].pos.y + fif(track[i].maxAir < minimumjump_height + 2, -9, track[i].maxAir)
GameplaySettings{minimumjump_height}
(CharacterManager.minimumJump_MaxHeight)stretch
(ringSpacing)flatten
(useGuardrailHeights)crossSectionShape
(extrusionPoints)perTrackNodeScales
/scales
(ringScales)GetTrack()[...].maxAir
(TrackServer.Node.maxAir)perShapeNodeColorScalers
(extrusionColorScalers)perShapeNodeColorScalersScaleAlpha
(extrusionColorScalersScaleAlpha)If no material or shader is specified, the following material is used:
material = {
shader = "DiffuseVertexColored2",
texture = UnityEngine.Resources.Load("textures/White.png"),
shadersettings = {
_BumpAmt = 10,
_Cutoff = 0.5,
_EmissionLM = 0,
_InvFade = 1,
_Parallax = 0.02,
_Rate = 300,
_Shininess = 0.7,
_farDistance = 20,
_nearDistance = 10,
},
shadercolors = {
_Color = {r=0.1701978, g=0.6251901, b=0.8842655, a=1}, -- Currently, this will always get overwritten by the color setting.
_Emission = {r=0, g=0, b=0, a=0},
_SpecColor = {r=0.090909, g=0, b=1, a=1},
_TintColor = {r=1, g=1, b=1, a=0.5019608},
_farColor = {r=0.00980173, g=0.6567164, b=0.6024298, a=1},
_nearColor = {r=0.9850746, g=0, b=0, a=1},
},
}
-- calls to this function after the first run are ignored
globalname globalName = nil -- typeName: "RepeatedMeshRail"
string prefabName = nil -- If this is a valid name, gameobject will be ignored.
gameobject gameobject = nil
float ahead_renderdist = 500
float behind_renderdist = 25
int maxverticesperbatch = 50000
float spacing = 0
vector3[] offsets ?= nil -- Must be the same length as #GetTrack()
.
vector3[] scales ?= nil -- Parts of the rail where the interpolated X+Y scale is 0 will be skipped. If your array only contains scales of one and zero, no actual scaling will be performed but zeroes will still be skipped. Must be the same length as #GetTrack()
.
float track_tilt_factor ?= 1
string colorMode = "none" or "highway" or "highwayinverted"
bool buildlive = false
int maxmeshesperbatch = 999999
bool calculatenormals = false
globalname globalName = nil -- typeName: "ro"
string name = nil -- the prototype name
gameobject gameobject = nil
float railoffset = nil -- causes it to be "attached to the highway" if set to a number
-- if railoffset is a number
bool floatonwaterwaves = false
float tiltsmoother = 0 -- "smooth tilt speed". if nonzero, turns on "smooth tilting"
-- else
int/string tracknode = -1 or ("end" / "End" / "END") or ("start" / "Start" / "START") -- if it is an int 0 or greater or "start" or "end", it attaches to that "node" on the highway
-- end
int shapetotrack_at ?= nil -- Track node index, starting at 1.
bool active = ?
bool visible = true
An alias for CreateObject{}.
An alias for CreateObject{}.
string prefabName = nil -- Required. This refers to CreateObject{name} or a built-in object asset.
int[] nodes = (throw NullReferenceException) -- Zero-based track node indexes. (0 is the first node.)
vector3[] offsets = {{0,0,0}, ...} -- World-space offset from the corresponding node's position.
vector3[] scales = {{1,1,1}, ...}
vector3[] rotations = {{0,0,0}, ...}
int count = 5 -- The number of objects that will be visible simultaneously.
int renderBehindDistance = 10 -- Wait until an object's node is this many nodes behind math.floor(tracklocation) before reassigning it to a future node.
This seems to be similar in purpose to BatchRenderEveryFrame
except it uses a pool of real objects (attached components such as thrusters will work) and we are working in world space (offset by node position only) rather than node space. Once the player passes by an object's node, it will be teleported to the next node in nodes
that an object hasn't been placed on already.
At startup it creates the specified number of instances of the specified object, leaves their transform at the original object's position, and assigns them to imaginary node -1
. Whenever the current node minus renderBehindDistance
is greater than an object's assigned node, it will get reassigned to the next unused node index in nodes
and transformed accordingly. When it reaches the end of nodes
it will stop making changes and the objects will continue to exist in their current locations.
prefabName
is first checked against the list of prototypes, which can be named objects created by CreateObject, or built-in prototypes. If no prototype is found, it will do Resources.Load(prefabName)
and then immediately unsafe-cast the result to UnityEngine.GameObject
. I am not sure if this can be exploited to instantiate other kinds of resources.
When working with the GetTrack()
array to choose nodes, you will need to subtract the Lua array indexes by one to convert it to the zero-based indexes expected by this function. An entry in nodes
that is too large (node[i] >= #GetTrack()
) will cause the rest of the array to be ignored. Negative indexes will throw IndexOutOfRangeException at the point where it attempts to assign an object to that node. If any of the other arrays are smaller than nodes
, that array will be replaced with the default.
string prefabName -- mandatory
int[] locations -- mandatory. ints lower than 1 will be treated as 1
vector3[]/vector3 offsets = nil -- vector3[] version must be as long as locations
vector3[] scales = nil -- only works if override_impactpositions, waterfloat, or songspeedratio are used. overrides the scale of the prefab rather than combining with it
vector3[] rotations = nil
vector3[] override_impactpositions = nil -- "override node position"
vector3[] override_velocities = nil -- "override direction"
int afternodereached_numbernodesrendered = 50
bool override_velocities_scaledbytrackspeed = true
bool rotateWithTrack = true
int maxShown = 100 -- earlier numbers in the locations array have priority over later ones when this limit is reached
int maxDistanceShown = 600 -- locations more than this many nodes away from the player will not be visible
bool testAndHideIfCollideWithTrack = false
int collisionLayer = -1
bool waterfloat = false
float songspeedratio = nil -- internal name "compression", is disabled unless you set this. cannot be switched off once enabled
vector3[] worldspaceoffsets = nil
color[]/string colors = nil or {...} or "highway" or "highwayinverted" or "nodecolor" -- nodecolor sets the individual objects' colors to the node they are attached to. highway and highwayinverted act like materialcolor. highwayinverted is bugged and is identical to highway
The below documentation hasn't been updated for newly added settings rotations
and worldspaceoffsets
.
Each number in locations
is the index of a track node to place an instance at. (GetTrack
gets a list of all nodes) The other optional array settings are used to modify specific instances specified in locations
. If set, they should be the same array length as locations
and the order of the entries determines which location they will influence.
By default, an instance is placed at the center of a node. offsets
can be used to move them away from the center. Offset is relative to the node's position and rotation, so a positive X offset will always move it to the right of the track. Positive Y moves up and positive Z moves forward.
Here are some terms I will use in the following explanations:
GetTrack()
.If you use songspeedratio
, the numbers in locations
are relative to CurrentNode rather than the beginning of the track. (the objects will move along with you) The number specified by songspeedratio
scales the locations, allowing you to indirectly specify non-integers.
maxDistanceShown
is based on the difference between CurrentNode and the number in locations
. The actual per-frame condition for hiding is locations[i] - CurrentNode > maxDistanceShown
so it won't re-hide objects later. Strangely, this behavior is not affected by songspeedratio
in any way. Locations are still relative to the beginning of the track when considering distance. This means you probably want to set maxDistanceShown
larger than the highest number in locations
when using songspeedratio
in order to disable it. Combining the two might be useful for some strange special effects.
afternodereached_numbernodesrendered
is subtracted from CurrentNode and any location less than that value will be hidden. Like maxDistanceShown
, this comparison is not affected by songspeedratio
. For that frame, an instance hidden in this manner still counts toward the maxShown
limit. Future frames will ignore that location and all earlier entries in the array. This can cause strange behavior if the values in locations
aren't sorted from lowest to highest.
If override_impactpositions
and override_velocities
are set, the actual per-frame position of the instances in world space will be impactpositions + (x * velocities)
where x is the time until reaching the node specified in locations
. (CurrentTime - Track[locations[i]].seconds
) If override_velocities_scaledbytrackspeed
is true, x will instead be the current playback node index minus the node index specified in locations
, multiplied by 3. (3 * (CurrentNode - locations[i])
) Overrides nullify the effects of offsets
, rotateWithTrack
, waterfloat
, and songspeedratio
. Ensure that those options are switched off for best performance. Overrides were added so the Audiosphere mod could render its falling meteors.
override_velocities
also overrides the angle of each instance by specifying a direction for the object to "look" toward. (Quaternion.LookRotation(override_velocities[i], Vector3(0, 1, 0))
) This can probably be abused to get rotated objects which don't appear to move by using a very small velocity. (since there isn't a "rotations" setting) Just be careful not to go smaller than float
can support. Don't use completely zero velocities; it will probably spam errors to output_log.txt every frame.
Overrides, combined with maxDistanceShown
and afternodereached_numbernodesrendered
, allow us to place an object at an arbitrary position in the world which appears at a certain time, moves from point A to point B, then disappears.
Instances hidden by testAndHideIfCollideWithTrack
will still count toward the maxShown
limit. I was unable to find how collisionLayer
is honored but it may behave the same way.
string prefabName -- mandatory
int[] locations -- mandatory. ints lower than 1 will be treated as 1
vector3[]/vector3 offsets = nil -- vector3[] version must be as long as locations
vector3[]/vector3 scales = nil -- vector3[] version must be as long as locations
color[] colors = nil
float[] repeaterSpacings = nil
globalname globalName = nil -- typeName: "forest"
gameobject[] trees = nil
string objectorder = "random" or "sequential"
int minspacing = 1000
int maxspacing = 3000
vector3[]/table[] offsets = nil or {{0,0,0}, ...} or {{
vector3 min = {0,0,0}
vector3 max = min
}, ...}
string offsetorder = "random" or "sequential"
bool collisiontest = true
string trackpositioncolorproperty = nil -- this is the name of a shader color (same as the key names in material.shadercolors) which will be set to the track color of whatever location each object is at
int numrendered = 50
Creates a Unity Light.
globalname globalName = nil -- typeName: "light"
float railoffset = nil -- causes it to be "attached to the highway" if set to a number
-- if railoffset != nil then
bool floatonwaterwaves = false
float tiltsmoother = 0 -- "smooth tilt speed". if nonzero, turns on "smooth tilting"
-- end
transform transform = nil
string type = "point" or "directional"
materialcolor color = ?
string mode = "auto" or "pixel" or "vertex"
float intensity = 0.5
float range = ?
table shadows ?= {
string type = ("none" / "None") or ("soft" / "Soft") or ("hard" / "Hard")
float strength ?= 1
float bias ?= 0.05
float softness ?= ? -- Obsolete: Shadow softness is removed in Unity 5.0+
float softnessfade ?= ? -- Obsolete: Shadow softness is removed in Unity 5.0+
}
int light
transform transform ?= ?
materialcolor color ?= ?
float intensity = 0.5
float range ?= ?
table shadows ?= nil -- this is the same as CreateLight{shadows}. omitting it disables shadows.
AssetBundles is a special table that contains all asset bundles in your skin or mod, by name. The asset bundle objects are UnityEngine.AssetBundle, but the only thing most people need to know about that object is it contains an instance method named LoadAsset that you can use like this:
-- 2022-03-02: Warning: This code is untested and was written based on theory. I am publishing this early and will do testing later.
SetRings{
material = BuildMaterial{
-- Read a shader named "Example" that was stored in the top folder of the Unity project and built into to the bundle named "examples" (filename "examples.as2assets").
shader = AssetBundles.examples:LoadAsset('assets/Example.shader'),
texture = "ring.png",
shadersettings = {
_SpinSpeed = math.pi/64,
},
},
}
SetBlocks{
colorblocks = {
height = 0.65,
float_on_water = false,
gameobject = {
-- Normally you would need to instantiate a prefab (see below) but the traffic system already does something like that.
go = AssetBundles.examples:LoadAsset('assets/colorblock.prefab'),
},
scale = {1,1,1},
},
greyblocks = {
height = 0.65,
float_on_water = false,
gameobject = {
-- If you prefer, Lua lets us omit the parentheses for function calls that only take one string or table argument.
go = AssetBundles.examples:LoadAsset 'assets/greyblock.prefab',
},
scale = {1,1,1},
},
powerups = {
powerpellet = {
gameobject = {
go = AssetBundles.examples:LoadAsset('assets/powerpellet.prefab'),
},
}
},
chainspans = {
hide = false,
material = AssetBundles.examples:LoadAsset('assets/chainspans.mat'),
},
}
Object = import_type 'UnityEngine.Object'
CreateObject{
name="EndCookie",
tracknode="end",
gameobject={
go = Object.Instantiate(AssetBundles.examples:LoadAsset('assets/EndCookie.prefab')),
}
}
When you try to get an asset bundle from the table the first time it will be automatically loaded and added to the table for future reuse. (This is implemented with a metatable that calls LoadAssetBundle with the file extension appended.)
(A more thorough tutorial is in progress. Contact me if you need help.)
C:\Program Files\UnityAS2
. (Installing outside of the standard Program Files
folders is not recommended.)
Assets
folder is next to your main Lua file.Editor
and copy these files into that folder.
AS2AssetBundles.cs
from Audiosurf 2\Audiosurf2_Data\SkinningAssetBundles
Ionic.Zip.dll
from Audiosurf 2\Audiosurf2_Data\Managed
Assets
menu at the top, then choose Build AS2 AssetBundles
from the menu.
Build AS2 AssetBundles
option is missing, you failed to add the editor script correctly or you have errors in the Console
tab that need to be addressed before it will load new scripts.
When uploading to the workshop, Audiosurf 2 has been set up to automatically exclude the cache files from Unity project folders so you shouldn't need to clean those up yourself. See the .as2ignore
file for details.
From the official documentation: Loads the asset bundle and adds it to the global AssetBundles table. The table has a metamethod that calls this function if a key doesn't exist; it is the preferred way to load asset bundles.
You should ignore this function and use AssetBundles unless you are building your own cache system.
Creates a material object and returns a reference to it. This allows a single material to be used on multiple objects with less waste, and allows the material to be modified during Update()
via UpdateMaterial{}
or the object's members. The object's members also give access to advanced settings.
An alias for BuildMaterial{}
UnityEngine.Material material
{string=float/vector4} shadersettings ?= ? -- Omitted settings are left at their previous values. Types can be mixed.
table texturesettings ?= ? or {
-- These settings only apply to the main texture.
vector2 offset ?= ?
vector2 scale ?= ?
vector2 tiling ?= ? -- Same as scale.
}
shadercolors shadercolors ?= ?
vector2 textureoffset ?= ? -- Same as texturesettings.offset.
vector2 texturescale ?= ? -- Same as texturesettings.scale.
Modifies an existing material. Useful for implementing animations inside the Update()
function. Somewhat redundant now that the material object is exposed for direct changes.
An alias for UpdateMaterial{}
Can be one of the following tables:
address mesh -- Create a new mesh out of the specified model. This value is required.
bool calculateNormals = true -- note the capital N in this version
bool calculateTangents = false
bool submeshesWhenCombining = false
int shapetotrack_at = nil -- A track node id. (1 is the first node.)
bool barycentricTangents = false
bool splitVertices = false
address[] meshes -- mesh morphing
-- if meshes is a table
color[] meshcolors = nil
bool barycentricTangents = false
bool splitVertices = false
bool usesequentialmode = false
float sequentialspeed = 0
string sequentialmode = nil or "loop" or "intensityloop" or "baycrowdloop" or "intensitymatch"
bool recalculateNormalsEveryFrame = false
-- else
UnityEngine.Mesh/mesh mesh = nil -- If specified, modifies an existing mesh. (Procedural animations.)
vector3[] vertextable ?= nil -- Sets UnityEngine.Mesh.vertices.
vector2[] uvtable ?= nil -- Sets UnityEngine.Mesh.uv.
color[] colortable ?= nil -- Sets UnityEngine.Mesh.colors.
int[] indextable ?= nil -- Sets UnityEngine.Mesh.triangles. If it doesn't contain a zero, all of the numbers will be reduced by one (its indexing starts with 0).
bool calculatenormals ?= false
-- end if
int shapetotrack_at = nil -- A track node id. (1 is the first node.)
The mesh
object returned by BuildMesh can be used instead of a filename in most functions that take an .obj file:
exampleMesh = BuildMesh{ mesh = "example.obj", } CreateObject{ railoffset = 0, floatonwaterwaves = false, gameobject = { mesh = exampleMesh, shader = "VertexColorUnlitTinted", shadercolors = { _Color = {1,1,1} }, } }
See the documentation of the other functions for confirmation. One important exception is that mesh objects cannot be used for mesh morphing. It is possible to imitate mesh morphing via procedural animations.
BuildMesh has multiple uses:
In general, you define vertices and their attributes with vertextable
, uvtable
, and colortable
. Those 3 tables should be the same length or nil
to leave them unchanged. To build faces from the vertices you define triangles by adding sets of 3 vertex indices, in clockwise order, to indextable
.
(I haven't yet published any here but I have made animated spectrum visualizers with this. Contact me if you want examples/help.)
mesh mesh
float[] weights
string depth = "background" or "foreground" or "topmost_exclusive" or ("middle" / "foreground_exceptclose") -- Selects camera.
UnityEngine.Material material = nil -- Only accepts pre-built materials. Specifying this does not prevent "builtin" from being read, and both will be added to the specified camera.
table builtin = nil or {
string name = nil or (see below) -- A valid name is required or builtin will be ignored.
-- Other values, depending on the name. See below for all the variations.
}
Attaches a post-processing effect to the selected camera:
background
: The background camera. Covers objects on layers 18 and 19.middle
/ foreground_exceptclose
: The foreground camera. Covers objects on layers 11, 12, 13, 18, and 19.foreground
: The close camera. Covers objects on layers 11, 12, 13, 14, 15, 18, and 19.topmost_exclusive
: The close blitter camera. Adding a material
effect to this camera switches the close camera to blitter mode. Covers objects on layers 14 and 15.material
Post EffectsThis adds a material to a multi-material effect named PostEffects
. The material's shader receives the camera view through the main texture (_MainTex
) and it is drawn as a quad covering the camera.
If the effect has 1 material, it does Graphics.Blit(src, dest, material)
. If someone wants this code path but wants to do multiple material
effects, they might be able to use a single material with a custom multi-pass shader, using UsePass and GrabPass as needed.
If there are multiple materials, they are chained together in the order they were added by blitting to pooled RenderTexture
objects. The first material receives directly from src
and the last one outputs directly to dest
. RenderTexture settings:
If the effect has 0 materials but is somehow enabled, it does Graphics.Blit(src, dest)
, making it effectively an identity function. We can get this state by specifying no material
along with an invalid builtin
that causes an exception to be thrown, then catching the exception after it leaves AddPostEffect
. Setting an address
to something other than a string
or nil
should cause an InvalidCastException
.
There is special behavior when adding a material
post effect to the close blitter camera: The close camera will be assigned a background color and a RenderTexture
, which will be used as the source for the close blitter camera rather than reading from the screen buffer. The blit output will also be null
(the screen) rather than dest
. Settings:
{0,0,0,0}
builtin
Post EffectsThis allows scripts to utilize some Unity post effects that have been integrated into Audiosurf 2. If material
and builtin
effects are mixed on the same camera, PostEffects
is always the first component to be added. Post effects should render in the order they are added to the camera.
An older version of Amplify Color. Adds AmplifyColorEffect with the old version's default settings.
string name = "amplifycolor" / "AmplifyColor"
float blendamount = 0 -- BlendAmount
address lut = nil -- LutTexture, SyncLoadTexture(wrapMode: Clamp, mipmaps: no, readable: yes, format: RGBA32)
address blendlut = nil -- LutBlendTexture, SyncLoadTexture(wrapMode: Clamp, mipmaps: no, readable: yes, format: RGBA32)
address mask = nil -- MaskTexture, SyncLoadTexture(wrapMode: Clamp, mipmaps: no, readable: yes, format: RGBA32)
Enables the Candela SSRR effect. (Screen Space Ray-traced Reflections) All it does is check if the object exists and, if found, activates it. I can't find the class in the version of Audiosurf 2 I am looking at, and it was made for an older version of Unity, so this might be a removed feature. Because this component is added in the editor, like PostEffects
, I am not sure which one renders first.
string name = "CandelaSSR" / "CandelaSSRR" / "SSR" / "ssr"
-- no options
The Heathen's Selective Glow effect. Adds SelectiveGlow
with the following settings:
"Hidden/Composite Selective Glow "
, if it exists, or "Hidden/Composite Selective Glow"
"Hidden/Render Selective Glow"
"Hidden/HeathenBlurConeTap"
"Hidden/_HeathenFastBlur"
GetQualityLevel4() <= 1
string name = "SelectiveGlow" / "selectiveglow" / "HeathenSelectiveGlow"
-- no options
Sonic Ether's Natural Bloom Dirty Lens effect. Adds SENaturalBloomAndDirtyLens with default settings.
string name = "SENaturalBloomAndDirtyLens" / "NaturalBloom" / "SENaturalBloom" / "senaturalbloom" / "naturalbloom"
float dirtintensity = 0.05 -- lensDirtIntensity, suggested range is 0.0 to 0.95
float bloomintensity = 0.05 -- bloomIntensity, suggested range is 0.0 to 0.4
address dirt = nil -- lensDirtTexture, SyncLoadTexture(wrapMode: Clamp, mipmaps: no, readable: yes, format: RGBA32)
The SSAO Pro effect. Adds SSAOPro
with default settings.
string name = "SSAOPro" / "ssaopro" / "ssao" / "SSAO"
-- no options
This is implied to be the Global Fog effect from the Unity 5 "Pro only" standard effects package. Adds a GlobalFogU5
effect:
It also takes some fog settings from RenderSettings
(fogMode
, fogDensity
, fogStartDistance
, fogEndDistance
), so SetScene{fogenabled,fogcolor,fogdensity,fogstart,fogend}
will change this effect.
string name = "GlobalFog"
float height = -400 -- "Fog top Y coordinate"
With custom shaders it has always been possible to use special vertex shaders to position geometry directly in screen space without using AddPostEffect
and sample the screen using GrabPass. An example is available here.