-
Notifications
You must be signed in to change notification settings - Fork 26
VRSL DMX: Creating Custom DMX Shaders
VRSL DMX is intended to be used more like a data protocol rather than a discrete set of shaders and tools. As such, any shader property can be controlled by DMX, whether it's lighting, vertex transforms, screen space, etc. If it's a shader property, it can be controlled by VRSL. This page discusses what you need to add to your custom shaders to enable VRSL DMX functionality.
Here is the video tutorial version of this page.
VRSL DMX works similarly to audiolink in that there is a single CGINC file that you need to include to start creating DMX-compatible world shaders.
For avatar shaders, the same file can be found in theVRSL-AvatarCarePackage.unitypackage
file.
The file is called VRSLDMX.cginc
. For world shaders, you can get to it with this line of code:
#include "Packages/com.acchosen.vr-stage-lighting/Runtime/Shaders/VRSLDMX.cginc"
For avatar shaders, it would be this line:
#include "Assets/VRSL Addons/VRSL-AvatarCarePackage/VRSLDMX.cginc"
This file contains a few instanced defined properties, standard defined properties, and some functions needed to read DMX from the grid node. Once you have this file in, there are some properties you may want to define first before you get started writing.
It is recommended, if possible, to get the DMX data in the vertex shader rather than the fragment shader. This is because since there is no UV mapping involved when sampling, it is generally faster to sample the data in the vertex shader and send it to the fragment shader through the v2f struct. (If it's not possible, all of the functions will still work in the fragment shader as normal).
Shader "Unlit/VRSL-TutorialV2"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
[Toggle] _EnableDMX ("Enable Stream DMX/DMX Control", Int) = 0
[Toggle] _NineUniverseMode ("Extended Universe Mode", Int) = 0
[Toggle] _EnableVerticalMode ("Enable Vertical Mode", Int) = 0
[Toggle] _EnableCompatibilityMode ("Enable Compatibility Mode", Int) = 0
[Toggle] _EnableStrobe ("Enable Strobe", Int) = 0
[Header(Base Properties)]
[HDR] _Emission ("Base DMX Emission Color", Color) = (1,1,1,1)
_GlobalIntensity ("Global Intensity", Range(0,1)) = 1
_FinalIntensity ("Final Intensity", Range(0,1)) = 1
// Use this for World Shaders
_DMXChannel ("Starting DMX Channel", Int) = 1
//Use these for Avatar Shaders
// _Channel ("DMX Channel", Int) = 1
// _Universe ("DMX Universe", Int) = 1
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// make fog work
#pragma multi_compile_fog
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
UNITY_FOG_COORDS(1)
float4 vertex : SV_POSITION;
nointerpolation float4 finalColor : TEXCOORD1; //final output color from DMX
};
//Main CGINC File For World Shaders
#include "Packages/com.acchosen.vr-stage-lighting/Runtime/Shaders/VRSLDMX.cginc"
//Main CGINC File For Avatar Shaders
//#include "Assets/VRSL Addons/VRSL-AvatarCarePackage/VRSLDMX.cginc"
sampler2D _MainTex;
float4 _MainTex_ST;
int _Channel, _Universe;
//Channel Mappings
//intensity = ch1
//rgb = ch2, ch3, ch4
//strobe = ch5
//always read DMX data from the vertex shader
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
UNITY_TRANSFER_FOG(o,o.vertex);
//Use this for Avatar Shaders
//int dmx = ConvertToRawDMXChannel(_Channel, _Universe);
//Use this for World Shaders
int dmx = GetDMXChannel();
float intensity = ReadDMX(dmx, _Udon_DMXGridRenderTexture); // 0-1 output
//this is the same as 3 ReadDMX() calls mapped to a float3 with 1 in the alpha channel
float4 color = GetDMXColor(dmx+1);
// a special function for getting strobe output, which is a square wave from 0-1
float strobe = GetStrobeOutput(dmx + 4);
//combine them together
o.finalColor = (intensity * color) * strobe;
//check to see if dmx capabilities are enabled, if not, output this base emission color.
o.finalColor = isDMX() ? o.finalColor : getBaseEmission();
//Use the global and final intensity values to control the final strength of the color with udon
//good for world shaders that want to be controlled by udon-based sliders.
o.finalColor *= getGlobalIntensity() * getFinalIntensity();
return o;
}
fixed4 frag (v2f i) : SV_Target
{
// sample the texture, multiply by dmx final output.
fixed4 col = tex2D(_MainTex, i.uv) * i.finalColor;
UNITY_APPLY_FOG(i.fogCoord, col);
return col;
}
ENDCG
}
}
}
In this example, we created a custom parameter in the v2f struct with float4 finalColor : TEXCOORD1;
, which simply stores the final emission color of our DMX shader. We then use isDMX()
to determine if we are using DMX at runtime, and adjust the final output of finalColor
with dmx data accordingly.
This way, our fragment shader only needs to grab i.finalColor
to get the final output of our DMX color.
You do not need to only send color data, you can also send the dmx data values themselves if needed through the same method.
These are the 3 most important properties
-
_DMXChannel ("Starting DMX Channel", Int) = 1
- The
_DMXChannel
instanced property is where you'll set the starting DMX Channel for your DMX shader. DMX Channels start reading from 1, so 1 is the default. This is more of a "raw" channel number and should be used only for world shaders when its controlled by theVRStageLighting_DMX_Static
script.
- The
-
_Channel ("Starting DMX Channel", Int) = 1
- An alternative to "_DMXCHannel" for avatar shaders. Use this to manually set the proper dmx512 channel.
-
_Universe("Starting DMX Universe", Int) = 1
- An alternative to "_DMXCHannel" for avatar shaders. Use this in conjunction with
_Channel
to manually set the universe for the dmx512 channel
- An alternative to "_DMXCHannel" for avatar shaders. Use this in conjunction with
The first property is required for world shaders. The last 2 are required for avatar shaders.
Here are some extra properties that are not required but are still highly recommended to have in your shader to enable standard features:
-
[Toggle] _EnableDMX ("Enable Stream DMX/DMX Control", Int) = 0
- A simple instanced int toggle property that can be used to enable/disable DMX functionality at runtime. This toggle can be controlled by the VRSL DMX Udon Script.
-
[Toggle] _NineUniverseMode ("Extended Universe Mode", Int) = 0
- An instanced toggle for nine/extended universe mode. This toggle is required for your shader to be used in extended universe mode. This toggle can be controlled by the VRSL Control Panel.
-
[Toggle] _EnableVerticalMode ("Enable Vertical Mode", Int) = 0
- An instanced toggle for vertical mode. This toggle is required for your shader to be used in vertical mode. This toggle can be controlled by the VRSL Control Panel.
-
[Toggle] _EnableCompatibilityMode ("Enable Compatibility Mode", Int) = 0
- An instanced toggle for legacy mode. This toggle is required for your shader to be used in legacy mode. This toggle can be controlled by the VRSL Control Panel.
-
[Toggle] _EnableStrobe ("Enable Strobe", Int) = 0
- An instanced toggle for strobe functionality. Use this property if you want to have an instanced toggle for the strobing feature. This toggle can be controlled by the VRSL DMX Udon Script.
-
[HDR] _Emission ("Base DMX Emission Color", Color) = (1,1,1,1)
- An instanced base emission color. Multiple your DMX color output by this to change the shader's base starting color. This color can be controlled by the VRSL DMX Udon Script.
-
_GlobalIntensity ("Global Intensity", Range(0,1)) = 1
- An instanced 0-1 float value intended to control the base intensity of your DMX color output. This value can be controlled by the VRSL DMX Udon Script.
-
_FinalIntensity ("Final Intensity", Range(0,1)) = 1
- An instanced 0-1 float value intended to control the base intensity of your DMX color output. Functionally, this is no different than Global Intensity, however, it is included in case you needed the base intensity to be controlled by more than one external script or animation. This value can be controlled by the VRSL DMX Udon Script.
There are a few functions inside of the VRSLDMX.cginc
script that you will need to use to enable DMX compatibility.
The general use case, however, will be to use the ReadDMX()
function with GetDMXChannel()
and _DMXGridRenderTexture
as your input. This will read DMX data from the _DMXGridRenderTexture
at the specified DMX channel. The general workflow is to increment the DMX channel value to traverse the grid and sample from nearby channels to create a "fixture profile" for your shader that you can then mimic inside of the DMX software of your choosing.
-
ReadDMX(uint DMXChannel, sampler2D _Tex)
- Returns a 0-1 value from a specified DMX channel from the provided texture. Use this with
GetDMXChannel()
as input. You can incrementGetDMXChannel()
to get nearby channels to sample from for different properties. It is recommended to use the standard global texture_Udon_DMXGridRenderTexture
as the texture input. Other global texture inputs include_Udon_DMXGridStrobeTimer
and_Udon_DMXGridSpinTimer
. You may also use_Udon_DMXGridRenderTextureMovement
to get the movement smoothing texture for column 13 channels to control "movement speed", but you will need to manually define this as a sampler2D since it is not necessary for most shaders, especially avatar shaders.
- Returns a 0-1 value from a specified DMX channel from the provided texture. Use this with
-
GetDMXChannel()
- Returns the instanced DMX channel property of your shader as a uint. Use this for world shaders.
-
ConvertToRawDMXChannel(int chan, int universe)
- Returns a conversion of the standard dmx channel and universe properties that you use for avatar shaders. Input the _Channel and _Universe properties to convert it to its "raw" dmx channel format. This is the avatar shader equivalent for
GetDMXChannel()
- Returns a conversion of the standard dmx channel and universe properties that you use for avatar shaders. Input the _Channel and _Universe properties to convert it to its "raw" dmx channel format. This is the avatar shader equivalent for
-
GetStrobeOutput(uint DMXChannel)
- Returns an alternating 0-1 value with the rate controlled by the specified DMX Channel value. Multiply the output of this function by any other value to make it strobe from its current value to 0 and back.
-
GetDMXColor(uint DMXChannel)
- This function calls
ReadDMX()
3 times, at 3 consecutive DMX increments (DMXChannel, DMXChannel + 1, DMXChannel + 2) to get 3 DMX channels for red, green, and blue. It then combines those values into a color (float4) that it returns.
- This function calls
-
isDMX()
- Returns the instanced toggle property,
_EnableDMX
.
- Returns the instanced toggle property,
-
getBaseEmission()
- Returns the instanced color property,
_Emission
.
- Returns the instanced color property,
-
getGlobalIntensity()
- Returns the instanced float property,
_GlobalIntensity
.
- Returns the instanced float property,
-
getFinalIntensity()
- Returns the instanced float property,
_FinalIntensity
.
- Returns the instanced float property,
-
isStrobe()
- Returns the instanced toggle property,
_EnableStrobe
.
- Returns the instanced toggle property,
-
getNineUniverseMode()
- Returns the instanced toggle property,
_NineUniverseMode
.
- Returns the instanced toggle property,
To add your custom DMX shader/material to the VRSL DMX Script, VRStageLighting_DMX_Static
, you will need to add the script to a game object, add your material to your target mesh object, and then add that object's mesh renderer to the obj renderers
array at the bottom of the script. This will enable basic instancing functionality as well as allow your custom shader to appear as a fixture in the VRSL Control Panel.
Testing DMX shaders would normally require you to have dmx software and the dmx grid node set up to take data in and set up the mappings and such. However, this is extremely tedious and not very practical, especially for avatar creators who simply want to make sure their avatar is working properly and not have to set up an entire dmx scene and software just to test these features.
In the VRSL-AvatarCarePackage.unitypackage
file, there is a special prefab called the VRSL-AvatarDMXTesting-Prefab
. This prefab is a script with cameras that plays back pre-recorded dmx videos and automatically outputs the data to the standard global texture names, as if VRSL was properly built in the scene, getting data. The data that is sent is simple patterns across many channels and many universes for you to test your inputs on your avatars. The script also contains settings to determine which mode it is (currently only Horizontal and Vertical are supported) and whether or not extended mode (9-universe mode) is enabled. Depending on the settings, similar but different videos will be played.
You can set your avatar's universe and channel settings to match the ones shown in the video to test different channels. Most of the cubes are the same 5-channel fixtures as shown in the example. There are also 15-channel fixtures getting random data on channel 400 in universes 1-3 you can test as well. When you are done testing, be sure to disable this prefab before uploading your avatar
Importing this care package and dropping this prefab into your avatar scene should be all you need to test your shader and your material settings for your DMX compatible avatar.
In the standard VR Stage Lighting package, there are special example scenes that have recorded videos of DMX data that avatar authors can use to test their avatars without needing to have an entire software suite setup.
The two scenes are called VRSL-ExampleScene-AvatarTest-Editor
and VRSL-ExampleScene-AvatarTest-InGame
respectively. As the names imply, one is for testing the avatar shader in the editor and the other is for testing the avatar in the world. These scenes are located in Packages\com.acchosen.vr-stage-lighting\Runtime\Example Scenes\DMX-AvatarTesting
The first scene contains a simple unity video player with a video loaded (that is included with the VR Stage Lighting Package) that plays around with the first 4 channels of dmx on universe 1, using the example 5-channel shader setup to demonstrate their values. Since VRSL DMX runs through a pixel grid, the pixel grid is included in the video, so that your avatar will also react to those same outputted dmx channels if they are outputted correctly. Just load the scene with your avatar and hit play.
The second scene is similar but has a Usharp Video player inside with a VRCWorld object so that you may build and test the world in game. It contains the same video, but it is extended to test channel 5, which is usually reserved for strobing. The video will automatically play upon loading in the world.
There will be public worlds to properly test dmx compatible avatars in the near future so do look out for that as well!