Skip to content

Commit

Permalink
add AudioLinkBlend
Browse files Browse the repository at this point in the history
  • Loading branch information
PiMaker committed Jul 11, 2021
1 parent 7ad04ae commit 5a12b06
Show file tree
Hide file tree
Showing 16 changed files with 547 additions and 0 deletions.
8 changes: 8 additions & 0 deletions Assets/_AudioLinkBlend.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

162 changes: 162 additions & 0 deletions Assets/_AudioLinkBlend/ALBlendGenerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;
using VRC.Udon;
using UdonSharp;

#if UNITY_EDITOR

public class ALBlendGenerator : MonoBehaviour
{
[Header("Internal Stuff")]
public Material AudioLinkBlendMaterial;
public UdonSharpProgramAsset ALConfigure;

[Header("User Configuration")]
[Tooltip("Which AudioLink Band to react to (0=bass, 1=mid_low, 2=mid_high, 3=treble) - this is encoded into the name of the created GameObject")]
[Range(0, 3)]
public int AudioLinkBand = 0;

[HideInInspector]
public float min = 0.0f, max = 1.0f;
[HideInInspector]
public int shape = 0;

public void DoWork()
{
var mesh = this.GetComponent<SkinnedMeshRenderer>();

var initialVal = mesh.GetBlendShapeWeight(shape);

var newMesh = new Mesh();

var scale = this.transform.localScale;
this.transform.localScale = Vector3.one;

mesh.SetBlendShapeWeight(shape, max);
mesh.BakeMesh(newMesh);

var bounds1 = CalculateBounds(newMesh);

var vertexPositions = new List<Vector3>(newMesh.vertices);
var normalPositions = new List<Vector3>(newMesh.normals);
var uvPositions = new List<Vector2>(newMesh.uv);

mesh.SetBlendShapeWeight(shape, min);
mesh.BakeMesh(newMesh);

var bounds2 = CalculateBounds(newMesh);

this.transform.localScale = scale;

newMesh.SetUVs(1, vertexPositions);
newMesh.SetUVs(2, normalPositions);
newMesh.SetUVs(3, uvPositions);

var meshName = this.gameObject.transform.GetHierarchyPath().Replace("\\", "_").Replace("/", "_");
SaveMesh(newMesh, meshName);

mesh.SetBlendShapeWeight(shape, initialVal);

// disable parent renderer, children will render instead
mesh.enabled = false;

foreach (var existingChild in this.transform)
{
var subFilter = (existingChild as Transform)?.GetComponent<MeshFilter>();
if (subFilter != null)
{
subFilter.sharedMesh = newMesh;
}
}

var newObj = new GameObject(this.gameObject.name + "_AL;" + this.AudioLinkBand,
typeof(MeshRenderer), typeof(MeshFilter), typeof(UdonBehaviour));

newObj.transform.SetParent(this.gameObject.transform);
newObj.transform.localPosition = Vector3.zero;
newObj.transform.localRotation = Quaternion.identity;
newObj.transform.localScale = Vector3.one;

var filter = newObj.GetComponent<MeshFilter>();
filter.sharedMesh = newMesh;
filter.sharedMesh.bounds = new Bounds(Vector3.zero, new Vector3(
Mathf.Max(Mathf.Abs(bounds1.extents.x), Mathf.Abs(bounds2.extents.x)) * 0.5f,
Mathf.Max(Mathf.Abs(bounds1.extents.y), Mathf.Abs(bounds2.extents.y)) * 0.5f,
Mathf.Max(Mathf.Abs(bounds1.extents.z), Mathf.Abs(bounds2.extents.z)) * 0.5f
));

var rend = newObj.GetComponent<MeshRenderer>();
this.AudioLinkBlendMaterial.enableInstancing = true;
rend.sharedMaterials = Enumerable.Repeat(this.AudioLinkBlendMaterial, mesh.sharedMaterials.Length).ToArray();

var udon = newObj.GetComponent<UdonBehaviour>();
udon.programSource = ALConfigure;
}

void SaveMesh(Mesh mesh, string name)
{
var path = "Assets\\_pi_\\_AudioLinkBlend\\generated\\";
System.IO.Directory.CreateDirectory(path);
path += name + ".asset";
MeshUtility.Optimize(mesh);
AssetDatabase.CreateAsset(mesh, path);
AssetDatabase.SaveAssets();
}

Bounds CalculateBounds(Mesh mesh)
{
var min = Vector3.one * float.MaxValue;
var max = Vector3.one * float.MinValue;
foreach (var v in mesh.vertices)
{
// please don't ask me why we need to multiply by 500 here...
min = Vector3.Min(v * 500.0f, min);
max = Vector3.Max(v * 500.0f, max);
}
var ret = new Bounds(Vector3.zero, new Vector3(
Mathf.Max(Mathf.Abs(min.x), Mathf.Abs(max.x)) * 0.5f,
Mathf.Max(Mathf.Abs(min.y), Mathf.Abs(max.y)) * 0.5f,
Mathf.Max(Mathf.Abs(min.z), Mathf.Abs(max.z)) * 0.5f
));
return ret;
}

public List<string> GetBlendShapes()
{
var mesh = this.GetComponent<SkinnedMeshRenderer>().sharedMesh;
var ret = new List<string>();
for (int i = 0; i < mesh.blendShapeCount; i++)
{
ret.Add(mesh.GetBlendShapeName(i));
}
return ret;
}
}

[CustomEditor(typeof(ALBlendGenerator))]
public class ALBlendGeneratorEditor : Editor
{
public override void OnInspectorGUI()
{
DrawDefaultInspector();

ALBlendGenerator gen = (ALBlendGenerator)target;

EditorGUILayout.LabelField("Blend Shape:");
var shapes = gen.GetBlendShapes();
gen.shape = EditorGUILayout.Popup(gen.shape, shapes.ToArray());

EditorGUILayout.LabelField("Blend Range:");
EditorGUILayout.MinMaxSlider(ref gen.min, ref gen.max, 0.0f, 1.0f);

if (GUILayout.Button("Generate"))
{
gen.DoWork();
}
}

}

#endif
14 changes: 14 additions & 0 deletions Assets/_AudioLinkBlend/ALBlendGenerator.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

52 changes: 52 additions & 0 deletions Assets/_AudioLinkBlend/ALConfigure.asset
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: c333ccfdd0cbdbc4ca30cef2dd6e6b9b, type: 3}
m_Name: ALConfigure
m_EditorClassIdentifier:
serializedUdonProgramAsset: {fileID: 11400000, guid: 6381663f2156a724790b248df4b9b562,
type: 2}
udonAssembly:
assemblyError:
sourceCsScript: {fileID: 11500000, guid: b05a9d5f502351a458ad740db5938ddd, type: 3}
behaviourSyncMode: 0
behaviourIDHeapVarName: __refl_const_intnl_udonTypeID
compileErrors: []
hasInteractEvent: 0
serializationData:
SerializedFormat: 2
SerializedBytes:
ReferencedUnityObjects: []
SerializedBytesString:
Prefab: {fileID: 0}
PrefabModificationsReferencedUnityObjects: []
PrefabModifications: []
SerializationNodes:
- Name: fieldDefinitions
Entry: 7
Data: 0|System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[UdonSharp.Compiler.FieldDefinition,
UdonSharp.Editor]], mscorlib
- Name: comparer
Entry: 7
Data: 1|System.Collections.Generic.GenericEqualityComparer`1[[System.String,
mscorlib]], mscorlib
- Name:
Entry: 8
Data:
- Name:
Entry: 12
Data: 0
- Name:
Entry: 13
Data:
- Name:
Entry: 8
Data:
8 changes: 8 additions & 0 deletions Assets/_AudioLinkBlend/ALConfigure.asset.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 22 additions & 0 deletions Assets/_AudioLinkBlend/ALConfigure.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using UdonSharp;
using UnityEngine;
using VRC.SDKBase;

public class ALConfigure : UdonSharpBehaviour
{
void Start()
{
var rend = this.GetComponent<MeshRenderer>();

var bandSplit = this.gameObject.name.Split(';');
var band = int.Parse(bandSplit[bandSplit.Length - 1]);

var mpb = new MaterialPropertyBlock();
rend.GetPropertyBlock(mpb);
mpb.SetInt("_ALBand", band);
rend.SetPropertyBlock(mpb);

// disable ourselves so we don't use any performance (hopefully)
this.enabled = false;
}
}
11 changes: 11 additions & 0 deletions Assets/_AudioLinkBlend/ALConfigure.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

61 changes: 61 additions & 0 deletions Assets/_AudioLinkBlend/AudioLinkBlend.shader
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
Shader "_pi_/AudioLinkBlend"
{
Properties
{
_Color ("Color", Color) = (1,1,1,1)
_MainTex ("Albedo (RGB)", 2D) = "white" {}
_Glossiness ("Smoothness", Range(0,1)) = 0.5
_Metallic ("Metallic", Range(0,1)) = 0.0

_ALBand ("AudioLink Band", Int) = 0

[HideInInspector] _AudioLink ("AudioLink Texture", 2D) = "black" {}
}
SubShader
{
Tags { "RenderType"="Opaque" "DisableBatching"="true" }
LOD 100

CGPROGRAM
#pragma surface surf Standard addshadow fullforwardshadows vertex:vert
#pragma target 3.0

#include "../../AudioLink/Shaders/AudioLink.cginc"

sampler2D _MainTex;

struct Input {
float2 uv_MainTex;
};

half _Glossiness;
half _Metallic;
fixed4 _Color;

UNITY_INSTANCING_BUFFER_START(Props)
UNITY_DEFINE_INSTANCED_PROP(uint, _ALBand)
UNITY_INSTANCING_BUFFER_END(Props)

void vert(inout appdata_full v, out Input o) {
UNITY_INITIALIZE_OUTPUT(Input, o);

if (AudioLinkData(ALPASS_GENERALVU + uint2(0, 0)).x >= 0) {
uint band = UNITY_ACCESS_INSTANCED_PROP(Props, _ALBand);
float intens = AudioLinkData(ALPASS_AUDIOLINK + int2(0, band)).r * 100.0;

v.vertex = lerp(v.vertex, v.texcoord1, intens);
v.normal = lerp(v.normal, v.texcoord2, intens);
o.uv_MainTex = v.texcoord = lerp(v.texcoord, v.texcoord3, intens);
}
}

void surf (Input IN, inout SurfaceOutputStandard o) {
fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
o.Albedo = c.rgb;
o.Metallic = _Metallic;
o.Smoothness = _Glossiness;
o.Alpha = c.a;
}
ENDCG
}
}
9 changes: 9 additions & 0 deletions Assets/_AudioLinkBlend/AudioLinkBlend.shader.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 5a12b06

Please sign in to comment.