1
This commit is contained in:
@@ -0,0 +1,144 @@
|
||||
// Fantasy Adventure Environment
|
||||
// Copyright Staggart Creations
|
||||
// staggart.xyz
|
||||
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
namespace FAE
|
||||
{
|
||||
|
||||
[ExecuteInEditMode]
|
||||
public class CliffAppearance : MonoBehaviour
|
||||
{
|
||||
public Shader cliffShader;
|
||||
public Shader cliffCoverageShader;
|
||||
|
||||
public Material[] targetMaterials = new Material[0];
|
||||
|
||||
//Objects
|
||||
public Color objectColor = Color.white;
|
||||
[Range(0f, 1f)]
|
||||
public float roughness = 0.15f;
|
||||
|
||||
//Detail norma
|
||||
public Texture detailNormalMap;
|
||||
[Range(0f, 1f)]
|
||||
public float detailNormalStrength = 0.5f;
|
||||
|
||||
//Global
|
||||
public Texture globalColorMap;
|
||||
public Color globalColor = Color.white;
|
||||
[Range(0f, 5f)]
|
||||
public float globalTiling = 0.01f;
|
||||
|
||||
//Coverage
|
||||
public bool useCoverageShader;
|
||||
public Texture coverageColorMap;
|
||||
public Texture coverageNormalMap;
|
||||
[Range(0f, 1f)]
|
||||
public float coverageAmount = 0.01f;
|
||||
[Range(0f, 20f)]
|
||||
public float coverageTiling = 1f;
|
||||
public Texture coverageMap;
|
||||
|
||||
public void OnEnable()
|
||||
{
|
||||
if (targetMaterials.Length == 0)
|
||||
{
|
||||
this.enabled = false;
|
||||
}
|
||||
|
||||
if (UnityEngine.Rendering.GraphicsSettings.renderPipelineAsset == null)
|
||||
{
|
||||
cliffShader = Shader.Find("FAE/Cliff");
|
||||
cliffCoverageShader = Shader.Find("FAE/Cliff coverage");
|
||||
}
|
||||
else
|
||||
{
|
||||
cliffShader = Shader.Find("Universal Render Pipeline/FAE/FAE_Cliff");
|
||||
cliffCoverageShader = Shader.Find("Universal Render Pipeline/FAE/FAE_Cliff_Coverage");
|
||||
}
|
||||
|
||||
Apply();
|
||||
}
|
||||
|
||||
|
||||
private void GetSettings()
|
||||
{
|
||||
if (!targetMaterials[0])
|
||||
{
|
||||
return;
|
||||
}
|
||||
Material mat = targetMaterials[0];
|
||||
|
||||
globalColorMap = mat.GetTexture("_Globalalbedo");
|
||||
detailNormalMap = mat.GetTexture("_Detailnormal");
|
||||
|
||||
objectColor = mat.GetColor("_ObjectColor");
|
||||
globalColor = mat.GetColor("_GlobalColor");
|
||||
|
||||
detailNormalStrength = mat.GetFloat("_Detailstrength");
|
||||
globalTiling = mat.GetFloat("_Globaltiling");
|
||||
roughness = mat.GetFloat("_Roughness");
|
||||
|
||||
if (mat.shader == cliffCoverageShader)
|
||||
{
|
||||
useCoverageShader = true;
|
||||
|
||||
coverageNormalMap = mat.GetTexture("_CoverageNormals");
|
||||
coverageColorMap = mat.GetTexture("_CoverageAlbedo");
|
||||
coverageMap = mat.GetTexture("_CoverageMap");
|
||||
|
||||
coverageAmount = mat.GetFloat("_CoverageAmount");
|
||||
coverageTiling = mat.GetFloat("_CoverageTiling");
|
||||
}
|
||||
else
|
||||
{
|
||||
useCoverageShader = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void Apply()
|
||||
{
|
||||
if (targetMaterials.Length != 0)
|
||||
|
||||
foreach (Material mat in targetMaterials)
|
||||
{
|
||||
if (!mat) continue;
|
||||
|
||||
if (useCoverageShader)
|
||||
{
|
||||
mat.shader = cliffCoverageShader;
|
||||
|
||||
mat.SetTexture("_CoverageNormals", coverageNormalMap);
|
||||
mat.SetTexture("_CoverageAlbedo", coverageColorMap);
|
||||
mat.SetTexture("_CoverageMap", coverageMap);
|
||||
|
||||
mat.SetFloat("_CoverageAmount", coverageAmount);
|
||||
mat.SetFloat("_CoverageTiling", coverageTiling);
|
||||
}
|
||||
else
|
||||
{
|
||||
mat.shader = cliffShader;
|
||||
}
|
||||
|
||||
//Textures
|
||||
mat.SetTexture("_Globalalbedo", globalColorMap);
|
||||
mat.SetTexture("_Detailnormal", detailNormalMap);
|
||||
|
||||
//Colors
|
||||
mat.SetColor("_ObjectColor", objectColor);
|
||||
mat.SetColor("_GlobalColor", globalColor);
|
||||
|
||||
//Floats
|
||||
mat.SetFloat("_Detailstrength", detailNormalStrength);
|
||||
mat.SetFloat("_Globaltiling", globalTiling);
|
||||
mat.SetFloat("_Roughness", roughness);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,33 @@
|
||||
// Fantasy Adventure Environment
|
||||
// Copyright Staggart Creations
|
||||
// staggart.xyz
|
||||
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
namespace FAE
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
[ExecuteInEditMode]
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Sets world-space obstacle position and bending strength on the FAE foliage shader
|
||||
/// </summary>
|
||||
public class FoliageBender : MonoBehaviour
|
||||
{
|
||||
|
||||
[Range(0f, 100f)]
|
||||
public float strength = 20f;
|
||||
[Range(0f, 5f)]
|
||||
public float radius = 1.5f;
|
||||
|
||||
void Update()
|
||||
{
|
||||
Shader.SetGlobalVector("_ObstaclePosition", this.transform.position);
|
||||
Shader.SetGlobalFloat("_BendingStrength", strength);
|
||||
Shader.SetGlobalFloat("_BendingRadius", radius);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,659 @@
|
||||
// Fantasy Adventure Environment
|
||||
// Copyright Staggart Creations
|
||||
// staggart.xyz
|
||||
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using System;
|
||||
using Workflow = FAE.TerrainUVUtil.Workflow;
|
||||
|
||||
namespace FAE
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
using UnityEditor.SceneManagement;
|
||||
[ExecuteInEditMode]
|
||||
#endif
|
||||
|
||||
public class PigmentMapGenerator : MonoBehaviour
|
||||
{
|
||||
//Dev
|
||||
public bool debug = false;
|
||||
public bool performCleanup = true;
|
||||
public bool manualInput = false;
|
||||
|
||||
//Terrain objects
|
||||
public GameObject[] terrainObjects;
|
||||
|
||||
//Terrain utils
|
||||
public TerrainUVUtil util;
|
||||
public Workflow workflow;
|
||||
|
||||
public int resIdx = 4;
|
||||
private int resolution = 1024;
|
||||
public Vector3 targetSize;
|
||||
public Vector3 targetOriginPosition;
|
||||
public Vector3 targetCenterPosition;
|
||||
|
||||
//Runtime
|
||||
[SerializeField]
|
||||
public Vector4 terrainScaleOffset;
|
||||
|
||||
//Terrain terrain
|
||||
public Terrain[] terrains;
|
||||
|
||||
//Mesh terrain
|
||||
private MeshRenderer[] meshes;
|
||||
private Material material;
|
||||
|
||||
#region Rendering
|
||||
//Constants
|
||||
const int HEIGHTOFFSET = 1000;
|
||||
const int CLIP_PADDING = 100;
|
||||
|
||||
//Render options
|
||||
public LayerMask layerMask = 1;
|
||||
public float renderLightBrightness = 0.25f;
|
||||
public bool useAlternativeRenderer = false;
|
||||
|
||||
//Rendering
|
||||
private Camera renderCam;
|
||||
private Light renderLight;
|
||||
private Light[] lights;
|
||||
#endregion
|
||||
|
||||
#region Inputs
|
||||
//Inputs
|
||||
public Texture2D inputHeightmap;
|
||||
public Texture2D customPigmentMap;
|
||||
public bool useCustomPigmentMap;
|
||||
|
||||
//Texture options
|
||||
public bool flipVertically;
|
||||
public bool flipHortizontally;
|
||||
|
||||
public enum TextureRotation
|
||||
{
|
||||
None,
|
||||
Quarter,
|
||||
Half,
|
||||
ThreeQuarters
|
||||
}
|
||||
public TextureRotation textureRotation;
|
||||
#endregion
|
||||
|
||||
//Textures
|
||||
public Texture2D pigmentMap;
|
||||
|
||||
//Meta
|
||||
public bool isMultiTerrain;
|
||||
public string savePath;
|
||||
private float originalTargetYPos;
|
||||
[NonSerialized]
|
||||
public bool showArea;
|
||||
|
||||
//MegaSplat
|
||||
public bool hasTerrainData = true;
|
||||
public bool isMegaSplat = false;
|
||||
|
||||
//Reset lighting settings
|
||||
UnityEngine.Rendering.AmbientMode ambientMode;
|
||||
Color ambientColor;
|
||||
bool enableFog;
|
||||
Material skyboxMat;
|
||||
|
||||
public enum HeightmapChannel
|
||||
{
|
||||
None,
|
||||
Texture1,
|
||||
Texture2,
|
||||
Texture3,
|
||||
Texture4,
|
||||
Texture5,
|
||||
Texture6,
|
||||
Texture7,
|
||||
Texture8
|
||||
}
|
||||
public HeightmapChannel heightmapChannel = HeightmapChannel.None;
|
||||
public string HeightmapChannelName;
|
||||
public string[] terrainTextureNames;
|
||||
|
||||
//Used at runtime
|
||||
private void OnEnable()
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
//This is to avoid the pigment map remaining in the shader
|
||||
Shader.SetGlobalTexture("_PigmentMap", null);
|
||||
}
|
||||
|
||||
private void OnDrawGizmosSelected()
|
||||
{
|
||||
if (showArea)
|
||||
{
|
||||
Color32 color = new Color(0f, 0.66f, 1f, 0.1f);
|
||||
Gizmos.color = color;
|
||||
Gizmos.DrawCube(targetCenterPosition, targetSize);
|
||||
color = new Color(0f, 0.66f, 1f, 0.66f);
|
||||
Gizmos.color = color;
|
||||
Gizmos.DrawWireCube(targetCenterPosition, targetSize);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
|
||||
CheckMegaSplat();
|
||||
|
||||
if (GetComponent<Terrain>() || GetComponent<MeshRenderer>())
|
||||
{
|
||||
isMultiTerrain = false;
|
||||
//Single terrain, use first element
|
||||
terrainObjects = new GameObject[1];
|
||||
terrainObjects[0] = this.gameObject;
|
||||
}
|
||||
else
|
||||
{
|
||||
isMultiTerrain = true;
|
||||
//Init array
|
||||
if (terrainObjects == null) terrainObjects = new GameObject[0];
|
||||
}
|
||||
|
||||
//Create initial pigment map
|
||||
if (pigmentMap == null)
|
||||
{
|
||||
Generate();
|
||||
}
|
||||
|
||||
#endif
|
||||
SetPigmentMap();
|
||||
|
||||
}
|
||||
|
||||
private void CheckMegaSplat()
|
||||
{
|
||||
#if __MEGASPLAT__
|
||||
if(workflow == TerrainUVUtil.Workflow.Terrain)
|
||||
{
|
||||
if (terrains[0].materialType == Terrain.MaterialType.Custom)
|
||||
{
|
||||
if (terrains[0].materialTemplate.shader.name.Contains("MegaSplat"))
|
||||
{
|
||||
isMegaSplat = true;
|
||||
useAlternativeRenderer = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
isMegaSplat = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
isMegaSplat = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
public void GetChildTerrainObjects(Transform parent)
|
||||
{
|
||||
//All childs, recursive
|
||||
Transform[] children = parent.GetComponentsInChildren<Transform>();
|
||||
|
||||
int childCount = 0;
|
||||
|
||||
//Count first level transforms
|
||||
for (int i = 0; i < children.Length; i++)
|
||||
{
|
||||
if (children[i].parent == parent) childCount++;
|
||||
}
|
||||
|
||||
//Temp list
|
||||
List<GameObject> terrainList = new List<GameObject>();
|
||||
|
||||
//Init array with childcount length
|
||||
this.terrainObjects = new GameObject[childCount];
|
||||
|
||||
//Fill array with first level transforms
|
||||
for (int i = 0; i < children.Length; i++)
|
||||
{
|
||||
if (children[i].parent == parent)
|
||||
{
|
||||
terrainList.Add(children[i].gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
terrainObjects = terrainList.ToArray();
|
||||
}
|
||||
|
||||
//Grab the terrain position and size and pass it to the shaders
|
||||
public void GetTargetInfo()
|
||||
{
|
||||
if (debug) Debug.Log("Getting target info for " + terrainObjects.Length + " object(s)");
|
||||
|
||||
if (!util) util = ScriptableObject.CreateInstance<TerrainUVUtil>();
|
||||
|
||||
util.GetObjectPlanarUV(terrainObjects);
|
||||
|
||||
//Determine if the object is a terrain or mesh
|
||||
workflow = util.workflow;
|
||||
|
||||
//If using Unity Terrains
|
||||
terrains = util.terrains;
|
||||
|
||||
//Avoid unused variable warning
|
||||
material = null;
|
||||
|
||||
//Summed size
|
||||
targetSize = util.size;
|
||||
|
||||
//First terrain makes up the corner
|
||||
targetOriginPosition = util.originPosition;
|
||||
|
||||
//Center of terrain(s)
|
||||
targetCenterPosition = util.centerPostion;
|
||||
|
||||
//Terrain UV
|
||||
terrainScaleOffset = util.terrainScaleOffset;
|
||||
|
||||
|
||||
SetPigmentMap();
|
||||
}
|
||||
|
||||
//Set the pigmentmap texture on all shaders that utilize it
|
||||
public void SetPigmentMap()
|
||||
{
|
||||
if (pigmentMap)
|
||||
{
|
||||
Shader.SetGlobalVector("_TerrainUV", new Vector4(targetSize.x, targetSize.z, Mathf.Abs(targetOriginPosition.x - 1), Mathf.Abs(targetOriginPosition.z - 1)));
|
||||
|
||||
//Set this at runtime to account for different instances having different pigment maps
|
||||
Shader.SetGlobalTexture("_PigmentMap", pigmentMap);
|
||||
}
|
||||
}
|
||||
|
||||
public static int IndexToResolution(int i)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
switch (i)
|
||||
{
|
||||
case 0:
|
||||
res = 64; break;
|
||||
case 1:
|
||||
res = 128; break;
|
||||
case 2:
|
||||
res = 256; break;
|
||||
case 3:
|
||||
res = 512; break;
|
||||
case 4:
|
||||
res = 1024; break;
|
||||
case 5:
|
||||
res = 2048; break;
|
||||
case 6:
|
||||
res = 4096; break;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
//Editor functions
|
||||
#if UNITY_EDITOR
|
||||
//Primary function
|
||||
public void Generate()
|
||||
{
|
||||
if (terrainObjects.Length == 0) return;
|
||||
|
||||
if (!manualInput)
|
||||
{
|
||||
GetTargetInfo();
|
||||
}
|
||||
else
|
||||
{
|
||||
workflow = (terrainObjects[0].GetComponent<Terrain>()) ? Workflow.Terrain : Workflow.Mesh;
|
||||
}
|
||||
|
||||
//If a custom map is assigned, don't generate one, only assign
|
||||
if (useCustomPigmentMap)
|
||||
{
|
||||
pigmentMap = customPigmentMap;
|
||||
SetPigmentMap();
|
||||
return;
|
||||
}
|
||||
|
||||
LightSetup();
|
||||
|
||||
CameraSetup();
|
||||
|
||||
MoveTerrains();
|
||||
|
||||
RenderToTexture();
|
||||
|
||||
SetPigmentMap();
|
||||
|
||||
if (performCleanup) Cleanup();
|
||||
|
||||
ResetLights();
|
||||
|
||||
}
|
||||
|
||||
//Position a camera above the terrain(s) so that the world positions line up perfectly with the texture UV
|
||||
public void CameraSetup()
|
||||
{
|
||||
//Create camera
|
||||
if (!renderCam)
|
||||
{
|
||||
GameObject cameraObj = new GameObject();
|
||||
cameraObj.name = this.name + " renderCam";
|
||||
renderCam = cameraObj.AddComponent<Camera>();
|
||||
}
|
||||
|
||||
//Set up a square camera rect
|
||||
float rectWidth = resolution;
|
||||
rectWidth /= Screen.width;
|
||||
renderCam.rect = new Rect(0, 0, 1, 1);
|
||||
|
||||
//Camera set up
|
||||
renderCam.orthographic = true;
|
||||
renderCam.orthographicSize = (targetSize.x / 2);
|
||||
renderCam.clearFlags = CameraClearFlags.Skybox;
|
||||
renderCam.allowHDR = true;
|
||||
|
||||
renderCam.farClipPlane = 5000f;
|
||||
renderCam.useOcclusionCulling = false;
|
||||
|
||||
renderCam.cullingMask = layerMask;
|
||||
|
||||
//Rendering in Forward mode is a tad darker, so a Directional Light is used to make up for the difference
|
||||
renderCam.renderingPath = (useAlternativeRenderer || workflow == TerrainUVUtil.Workflow.Mesh) ? RenderingPath.Forward : RenderingPath.VertexLit;
|
||||
|
||||
if (workflow == Workflow.Terrain)
|
||||
{
|
||||
//Hide tree objects
|
||||
foreach (Terrain terrain in terrains)
|
||||
{
|
||||
terrain.drawTreesAndFoliage = false;
|
||||
}
|
||||
}
|
||||
|
||||
//Position cam in given center of terrain(s)
|
||||
renderCam.transform.position = new Vector3(
|
||||
targetCenterPosition.x,
|
||||
targetOriginPosition.y + targetSize.y + HEIGHTOFFSET + CLIP_PADDING,
|
||||
targetCenterPosition.z
|
||||
);
|
||||
|
||||
renderCam.transform.localEulerAngles = new Vector3(90, 0, 0);
|
||||
}
|
||||
|
||||
private void MoveTerrains()
|
||||
{
|
||||
//Store terrain position value, to revert to
|
||||
//Safe to assume all terrains have the same Y-position, should be the case for multi-terrains
|
||||
originalTargetYPos = targetOriginPosition.y;
|
||||
|
||||
//Move terrain objects way up so they are rendered on top of all other objects
|
||||
foreach (GameObject terrain in terrainObjects)
|
||||
{
|
||||
terrain.transform.position = new Vector3(terrain.transform.position.x, HEIGHTOFFSET, terrain.transform.position.z);
|
||||
}
|
||||
}
|
||||
|
||||
private void RenderToTexture()
|
||||
{
|
||||
if (!renderCam) return;
|
||||
|
||||
pigmentMap = null;
|
||||
|
||||
//If this is a terrain with no textures, abort (except in the case of MegaSplat)
|
||||
if (workflow == Workflow.Terrain)
|
||||
{
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
if (terrains[0].terrainData.terrainLayers.Length == 0 && !isMegaSplat) return;
|
||||
#else
|
||||
if (terrains[0].terrainData.splatPrototypes.Length == 0 && !isMegaSplat) return;
|
||||
#endif
|
||||
}
|
||||
|
||||
resolution = IndexToResolution(resIdx);
|
||||
//Set up render texture
|
||||
RenderTexture rt = new RenderTexture(resolution, resolution, 0);
|
||||
renderCam.targetTexture = rt;
|
||||
|
||||
savePath = GetTargetFolder();
|
||||
|
||||
EditorUtility.DisplayProgressBar("PigmentMapGenerator", "Rendering texture", 1);
|
||||
|
||||
//Render camera into a texture
|
||||
Texture2D render = new Texture2D(rt.width, rt.height, TextureFormat.ARGB32, false);
|
||||
RenderTexture.active = rt;
|
||||
renderCam.Render();
|
||||
|
||||
//Compose texture on GPU
|
||||
rt = CompositePigmentMap(rt, inputHeightmap);
|
||||
|
||||
render.ReadPixels(new Rect(0, 0, resolution, resolution), 0, 0);
|
||||
|
||||
//Cleanup
|
||||
renderCam.targetTexture = null;
|
||||
RenderTexture.active = null;
|
||||
DestroyImmediate(rt);
|
||||
|
||||
//Encode
|
||||
byte[] bytes = render.EncodeToPNG();
|
||||
|
||||
//Create file
|
||||
EditorUtility.DisplayProgressBar("PigmentMapGenerator", "Saving texture...", 1);
|
||||
File.WriteAllBytes(savePath, bytes);
|
||||
|
||||
//Import file
|
||||
AssetDatabase.Refresh();
|
||||
|
||||
//Load the file
|
||||
pigmentMap = new Texture2D(resolution, resolution, TextureFormat.ARGB32, true);
|
||||
pigmentMap = AssetDatabase.LoadAssetAtPath(savePath, typeof(Texture2D)) as Texture2D;
|
||||
|
||||
EditorUtility.ClearProgressBar();
|
||||
|
||||
}
|
||||
|
||||
//Add the heightmap and do texture transformations
|
||||
private RenderTexture CompositePigmentMap(RenderTexture inputMap, Texture2D heightmap = null)
|
||||
{
|
||||
Material compositeMat = new Material(Shader.Find("Hidden/PigmentMapComposite"));
|
||||
compositeMat.hideFlags = HideFlags.DontSave;
|
||||
|
||||
compositeMat.SetTexture("_MainTex", inputMap);
|
||||
|
||||
//No given heightmap, get from terrain splatmap
|
||||
//If a channel is chosen, add heightmap to the pigment map's alpha channel
|
||||
if (heightmap == null && workflow == Workflow.Terrain && (int)heightmapChannel > 0)
|
||||
{
|
||||
//Sample one of the two splatmaps (supporting 8 textures as input)
|
||||
int spatmapIndex = ((int)heightmapChannel >= 5) ? 1 : 0;
|
||||
int channelIndex = (spatmapIndex > 0) ? (int)heightmapChannel - 4 : (int)heightmapChannel;
|
||||
|
||||
Texture2D splatmap = terrains[0].terrainData.alphamapTextures[spatmapIndex];
|
||||
|
||||
compositeMat.SetTexture("_SplatMap", splatmap);
|
||||
compositeMat.SetVector("_SplatMask", new Vector4(
|
||||
channelIndex == 1 ? 1 : 0,
|
||||
channelIndex == 2 ? 1 : 0,
|
||||
channelIndex == 3 ? 1 : 0,
|
||||
channelIndex == 4 ? 1 : 0)
|
||||
);
|
||||
}
|
||||
|
||||
if (workflow == Workflow.Mesh)
|
||||
{
|
||||
//Transforms
|
||||
Vector4 transform = new Vector4(0, 0, 0, 0);
|
||||
if (flipHortizontally) transform.x = 1;
|
||||
if (flipVertically) transform.y = 1;
|
||||
transform.z = -(int)textureRotation * (Mathf.PI / 2f);
|
||||
|
||||
compositeMat.SetVector("_Transform", transform);
|
||||
}
|
||||
|
||||
if (heightmap != null && isMultiTerrain) //Custom heightmap only for multi-terrains
|
||||
{
|
||||
compositeMat.SetTexture("_SplatMap", heightmap);
|
||||
|
||||
//Given heightmap is already a grayscale map, unmask all color channels
|
||||
compositeMat.SetVector("_SplatMask", new Vector4(1, 0, 0, 0));
|
||||
}
|
||||
|
||||
//Render shader output
|
||||
RenderTexture rt = new RenderTexture(inputMap.width, inputMap.height, 0);
|
||||
RenderTexture.active = rt;
|
||||
|
||||
Graphics.Blit(inputMap, rt, compositeMat);
|
||||
DestroyImmediate(compositeMat);
|
||||
|
||||
//inputMap.ReadPixels(new Rect(0, 0, inputMap.width, inputMap.height), 0, 0);
|
||||
//inputMap.Apply();
|
||||
|
||||
//RenderTexture.active = null;
|
||||
|
||||
return rt;
|
||||
}
|
||||
|
||||
//Store pigment map next to TerrainData asset, or mesh's material
|
||||
private string GetTargetFolder()
|
||||
{
|
||||
string m_targetPath = null;
|
||||
|
||||
//Compose target file path
|
||||
|
||||
//For single terrain
|
||||
if (terrainObjects.Length == 1)
|
||||
{
|
||||
if (workflow == TerrainUVUtil.Workflow.Terrain)
|
||||
{
|
||||
//If there is a TerraData asset, use its file location
|
||||
if (terrains[0].terrainData.name != string.Empty)
|
||||
{
|
||||
hasTerrainData = true;
|
||||
m_targetPath = AssetDatabase.GetAssetPath(terrains[0].terrainData) + string.Format("{0}_pigmentmap.png", terrains[0].terrainData.name);
|
||||
m_targetPath = m_targetPath.Replace(terrains[0].terrainData.name + ".asset", string.Empty);
|
||||
}
|
||||
//If there is no TerrainData, store it next to the scene. Some terrain systems don't use TerrainData
|
||||
else
|
||||
{
|
||||
hasTerrainData = false;
|
||||
string scenePath = EditorSceneManager.GetActiveScene().path.Replace(".unity", string.Empty);
|
||||
m_targetPath = scenePath + "_pigmentmap.png";
|
||||
}
|
||||
}
|
||||
//If the target is a mesh, use the location of its material
|
||||
else if (workflow == TerrainUVUtil.Workflow.Mesh)
|
||||
{
|
||||
material = terrainObjects[0].GetComponent<MeshRenderer>().sharedMaterial;
|
||||
m_targetPath = AssetDatabase.GetAssetPath(material) + string.Format("{0}_pigmentmap.png", string.Empty);
|
||||
m_targetPath = m_targetPath.Replace(".mat", string.Empty);
|
||||
}
|
||||
}
|
||||
//For multi-terrain, use scene folder or material
|
||||
else
|
||||
{
|
||||
if (workflow == TerrainUVUtil.Workflow.Mesh)
|
||||
{
|
||||
material = terrainObjects[0].GetComponent<MeshRenderer>().sharedMaterial;
|
||||
m_targetPath = AssetDatabase.GetAssetPath(material) + string.Format("{0}_pigmentmap.png", string.Empty);
|
||||
m_targetPath = m_targetPath.Replace(".mat", string.Empty);
|
||||
}
|
||||
else
|
||||
{
|
||||
string scenePath = EditorSceneManager.GetActiveScene().path.Replace(".unity", string.Empty);
|
||||
m_targetPath = scenePath + "_pigmentmap.png";
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return m_targetPath;
|
||||
}
|
||||
|
||||
void Cleanup()
|
||||
{
|
||||
DestroyImmediate(renderCam.gameObject);
|
||||
|
||||
if (renderLight) DestroyImmediate(renderLight.gameObject);
|
||||
|
||||
//Reset terrains
|
||||
foreach (GameObject terrain in terrainObjects)
|
||||
{
|
||||
//Reset terrain position(s)
|
||||
terrain.transform.position = new Vector3(terrain.transform.position.x, originalTargetYPos, terrain.transform.position.z);
|
||||
}
|
||||
|
||||
//Reset draw foliage
|
||||
if (workflow == TerrainUVUtil.Workflow.Terrain)
|
||||
{
|
||||
foreach (Terrain terrain in terrains)
|
||||
{
|
||||
terrain.drawTreesAndFoliage = true;
|
||||
}
|
||||
}
|
||||
|
||||
renderCam = null;
|
||||
renderLight = null;
|
||||
|
||||
}
|
||||
|
||||
//Disable directional light and set ambient color to white for an albedo result
|
||||
void LightSetup()
|
||||
{
|
||||
//Set up lighting for a proper albedo color
|
||||
lights = FindObjectsOfType<Light>();
|
||||
foreach (Light light in lights)
|
||||
{
|
||||
if (light.type == LightType.Directional)
|
||||
light.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
//Store current settings to revert to
|
||||
ambientMode = RenderSettings.ambientMode;
|
||||
ambientColor = RenderSettings.ambientLight;
|
||||
enableFog = RenderSettings.fog;
|
||||
skyboxMat = RenderSettings.skybox;
|
||||
|
||||
//Flat lighting
|
||||
RenderSettings.ambientMode = UnityEngine.Rendering.AmbientMode.Flat;
|
||||
RenderSettings.ambientLight = Color.white;
|
||||
RenderSettings.fog = false;
|
||||
RenderSettings.skybox = null;
|
||||
|
||||
//To account for Forward rendering being slightly darker, add a light
|
||||
if (useAlternativeRenderer)
|
||||
{
|
||||
if (!renderLight) renderLight = new GameObject().AddComponent<Light>();
|
||||
renderLight.name = "renderLight";
|
||||
renderLight.type = LightType.Directional;
|
||||
renderLight.transform.localEulerAngles = new Vector3(90, 0, 0);
|
||||
renderLight.intensity = renderLightBrightness;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//Re-enable directional light and reset ambient mode
|
||||
void ResetLights()
|
||||
{
|
||||
foreach (Light light in lights)
|
||||
{
|
||||
if (light.type == LightType.Directional)
|
||||
light.gameObject.SetActive(true);
|
||||
}
|
||||
|
||||
RenderSettings.ambientMode = ambientMode;
|
||||
RenderSettings.ambientLight = ambientColor;
|
||||
RenderSettings.fog = enableFog;
|
||||
RenderSettings.skybox = skyboxMat;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
@@ -0,0 +1,198 @@
|
||||
// Fantasy Adventure Environment
|
||||
// Copyright Staggart Creations
|
||||
// staggart.xyz
|
||||
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
namespace FAE
|
||||
{
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[ExecuteInEditMode]
|
||||
#endif
|
||||
|
||||
public class TerrainUVUtil : ScriptableObject
|
||||
{
|
||||
|
||||
//Dev
|
||||
public static readonly bool debug = false;
|
||||
|
||||
//Public
|
||||
public enum Workflow
|
||||
{
|
||||
None,
|
||||
Terrain,
|
||||
Mesh
|
||||
}
|
||||
public Workflow workflow = Workflow.None;
|
||||
|
||||
public Bounds meshBounds;
|
||||
public Vector3 pivotPos;
|
||||
|
||||
public float height;
|
||||
public float bottom;
|
||||
public Vector3 size;
|
||||
public Vector3 centerPostion;
|
||||
public Vector3 originPosition;
|
||||
|
||||
public Terrain[] terrains;
|
||||
public MeshRenderer[] meshes;
|
||||
|
||||
public Vector4 terrainScaleOffset;
|
||||
|
||||
public void GetObjectPlanarUV(GameObject[] gameObjects)
|
||||
{
|
||||
//No objects given
|
||||
if (gameObjects.Length == 0)
|
||||
{
|
||||
Debug.LogError("No objects given to render!");
|
||||
return;
|
||||
}
|
||||
|
||||
//Determine workflow
|
||||
if (gameObjects[0].GetComponent<Terrain>())
|
||||
{
|
||||
workflow = Workflow.Terrain;
|
||||
GetTerrainInfo(gameObjects);
|
||||
}
|
||||
else if (gameObjects[0].GetComponent<MeshRenderer>())
|
||||
{
|
||||
workflow = Workflow.Mesh;
|
||||
GetMeshInfo(gameObjects);
|
||||
}
|
||||
//Safeguard
|
||||
else
|
||||
{
|
||||
workflow = Workflow.None;
|
||||
Debug.LogError("Terrain UV Utility: Current object is neither a terrain nor a mesh!");
|
||||
return;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
if (debug)
|
||||
{
|
||||
Debug.Log("Summed size: " + size);
|
||||
Debug.Log("Center position: " + centerPostion);
|
||||
Debug.Log("Origin position:" + originPosition);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
private void GetMeshInfo(GameObject[] meshObjects)
|
||||
{
|
||||
height = 0;
|
||||
size = Vector3.zero;
|
||||
MeshRenderer mesh;
|
||||
|
||||
//Init mesh terrain array
|
||||
meshes = new MeshRenderer[meshObjects.Length];
|
||||
|
||||
Bounds cornerMeshBounds = new Bounds();
|
||||
|
||||
for (int i = 0; i < meshObjects.Length; i++)
|
||||
{
|
||||
mesh = meshObjects[i].GetComponent<MeshRenderer>();
|
||||
meshBounds = mesh.bounds;
|
||||
|
||||
//Store the bounds of the first, corner, mesh
|
||||
if (i == 0) cornerMeshBounds = meshBounds;
|
||||
|
||||
//Mesh size has to be uniform
|
||||
if (!IsApproximatelyEqual(meshBounds.extents.x, meshBounds.extents.z))
|
||||
{
|
||||
Debug.LogWarningFormat("[PigmentMapGenerator] size of \"{0}\" is not uniform at {1}! This is required for correct results.", mesh.name, meshBounds.extents.x + "x" + meshBounds.extents.z);
|
||||
}
|
||||
|
||||
//Set height to highest terrain
|
||||
if (meshBounds.size.y > height)
|
||||
{
|
||||
height = meshBounds.size.y;
|
||||
}
|
||||
|
||||
//With every terrain, size is increased
|
||||
size.x += meshBounds.size.x;
|
||||
size.z += meshBounds.size.z;
|
||||
}
|
||||
|
||||
size.y = height;
|
||||
|
||||
//Multi-terrain
|
||||
if (meshObjects.Length > 1)
|
||||
{
|
||||
size.x /= Mathf.Sqrt(meshObjects.Length);
|
||||
size.z /= Mathf.Sqrt(meshObjects.Length);
|
||||
originPosition = cornerMeshBounds.min;
|
||||
originPosition.y = meshObjects[0].transform.position.y;
|
||||
centerPostion = new Vector3(cornerMeshBounds.min.x + (size.x / 2), height / 2f, cornerMeshBounds.min.z + (size.z / 2));
|
||||
}
|
||||
//Single terrain
|
||||
else
|
||||
{
|
||||
originPosition = cornerMeshBounds.min;
|
||||
originPosition.y = meshObjects[0].transform.position.y;
|
||||
centerPostion = cornerMeshBounds.center;
|
||||
}
|
||||
|
||||
terrainScaleOffset = new Vector4(size.x, size.z, originPosition.x, originPosition.z);
|
||||
|
||||
Shader.SetGlobalVector("_TerrainUV", terrainScaleOffset);
|
||||
}
|
||||
|
||||
private void GetTerrainInfo(GameObject[] terrainObjects)
|
||||
{
|
||||
height = 0;
|
||||
size = Vector3.zero;
|
||||
Terrain terrain;
|
||||
|
||||
//Init terrain array
|
||||
terrains = new Terrain[terrainObjects.Length];
|
||||
|
||||
for (int i = 0; i < terrainObjects.Length; i++)
|
||||
{
|
||||
|
||||
terrain = terrainObjects[i].GetComponent<Terrain>();
|
||||
terrains[i] = terrain;
|
||||
|
||||
//Terrain size has to be uniform
|
||||
if (!IsApproximatelyEqual(terrain.terrainData.size.x, terrain.terrainData.size.z))
|
||||
{
|
||||
Debug.LogErrorFormat(this.name + ": size of \"{0}\" is not uniform at {1}!", terrain.name, terrain.terrainData.size.x + "x" + terrain.terrainData.size.z);
|
||||
return;
|
||||
}
|
||||
|
||||
//Set height to highest terrain
|
||||
if (terrain.terrainData.size.y > height)
|
||||
{
|
||||
height = terrain.terrainData.size.y;
|
||||
}
|
||||
if (terrains[i].transform.position.y < bottom)
|
||||
{
|
||||
bottom = terrain.transform.position.y;
|
||||
}
|
||||
|
||||
//With every terrain, size is increased
|
||||
size += terrain.terrainData.size;
|
||||
}
|
||||
|
||||
//For multi terrains, divide by square root of num tiles to get total size
|
||||
if (terrainObjects.Length > 1)
|
||||
{
|
||||
size /= Mathf.Sqrt(terrainObjects.Length);
|
||||
}
|
||||
|
||||
//First terrain is considered the corner and origin
|
||||
originPosition = terrains[0].transform.position;
|
||||
|
||||
//Offset origin point by half the size to get center
|
||||
centerPostion = new Vector3(originPosition.x + (size.x / 2f), originPosition.y + (height / 2f), originPosition.z + (size.z / 2f));
|
||||
}
|
||||
|
||||
//Check if values are equal, has error margin for floating point precision
|
||||
private bool IsApproximatelyEqual(float a, float b)
|
||||
{
|
||||
return Mathf.Abs(a - b) < 0.02f;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,72 @@
|
||||
#if VEGETATION_STUDIO_PRO
|
||||
using AwesomeTechnologies.VegetationSystem;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AwesomeTechnologies.Shaders
|
||||
{
|
||||
|
||||
public class FAEFoliageShaderController : IShaderController
|
||||
{
|
||||
public bool MatchShader(string shaderName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(shaderName)) return false;
|
||||
|
||||
return (shaderName == "FAE/Foliage" || shaderName == "Universal Render Pipeline/FAE/FAE_Foliage") ? true : false;
|
||||
}
|
||||
|
||||
public bool MatchBillboardShader(Material[] materials)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public ShaderControllerSettings Settings { get; set; }
|
||||
public void CreateDefaultSettings(Material[] materials)
|
||||
{
|
||||
Settings = new ShaderControllerSettings
|
||||
{
|
||||
Heading = "Fantasy Adventure Environment Foliage",
|
||||
Description = "Description text",
|
||||
LODFadePercentage = false,
|
||||
LODFadeCrossfade = false,
|
||||
SampleWind = true,
|
||||
SupportsInstantIndirect = true
|
||||
};
|
||||
|
||||
Settings.AddLabelProperty("Color");
|
||||
Settings.AddFloatProperty("AmbientOcclusion", "Ambient Occlusion", "", ShaderControllerSettings.GetFloatFromMaterials(materials, "_AmbientOcclusion"), 0, 1);
|
||||
|
||||
Settings.AddLabelProperty("Translucency");
|
||||
Settings.AddFloatProperty("TranslucencyAmount", "Amount", "", ShaderControllerSettings.GetFloatFromMaterials(materials, "_TransmissionAmount"), 0, 10);
|
||||
Settings.AddFloatProperty("TranslucencySize", "Size", "", ShaderControllerSettings.GetFloatFromMaterials(materials, "_TransmissionSize"), 1, 20);
|
||||
|
||||
Settings.AddLabelProperty("Wind");
|
||||
Settings.AddFloatProperty("WindInfluence", "Max Strength", "", ShaderControllerSettings.GetFloatFromMaterials(materials, "_MaxWindStrength"), 0, 1);
|
||||
Settings.AddFloatProperty("GlobalWindMotion", "Global motion", "", ShaderControllerSettings.GetFloatFromMaterials(materials, "_GlobalWindMotion"), 0, 1);
|
||||
Settings.AddFloatProperty("LeafFlutter", "Leaf flutter", "", ShaderControllerSettings.GetFloatFromMaterials(materials, "_LeafFlutter"), 0, 1);
|
||||
Settings.AddFloatProperty("WindSwinging", "Swinging", "", ShaderControllerSettings.GetFloatFromMaterials(materials, "_WindSwinging"), 0, 1);
|
||||
Settings.AddFloatProperty("WindAmplitude", "Amplitude Multiplier", "", ShaderControllerSettings.GetFloatFromMaterials(materials, "_WindAmplitudeMultiplier"), 0, 10);
|
||||
}
|
||||
|
||||
public void UpdateMaterial(Material material, EnvironmentSettings environmentSettings)
|
||||
{
|
||||
if (Settings == null) return;
|
||||
|
||||
material.SetFloat("_AmbientOcclusion", Settings.GetFloatPropertyValue("AmbientOcclusion"));
|
||||
|
||||
material.SetFloat("_TransmissionAmount", Settings.GetFloatPropertyValue("TranslucencyAmount"));
|
||||
material.SetFloat("_TransmissionSize", Settings.GetFloatPropertyValue("TranslucencySize"));
|
||||
|
||||
material.SetFloat("_MaxWindStrength", Settings.GetFloatPropertyValue("WindInfluence"));
|
||||
material.SetFloat("_GlobalWindMotion", Settings.GetFloatPropertyValue("GlobalWindMotion"));
|
||||
material.SetFloat("_LeafFlutter", Settings.GetFloatPropertyValue("LeafFlutter"));
|
||||
material.SetFloat("_WindSwinging", Settings.GetFloatPropertyValue("WindSwinging"));
|
||||
material.SetFloat("_WindAmplitudeMultiplier", Settings.GetFloatPropertyValue("WindAmplitude"));
|
||||
}
|
||||
|
||||
public void UpdateWind(Material material, WindSettings windSettings)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,103 @@
|
||||
#if VEGETATION_STUDIO_PRO
|
||||
using AwesomeTechnologies.VegetationSystem;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AwesomeTechnologies.Shaders
|
||||
{
|
||||
|
||||
public class FAEGrassShaderController : IShaderController
|
||||
{
|
||||
public bool MatchShader(string shaderName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(shaderName)) return false;
|
||||
|
||||
return (shaderName == "FAE/Grass") ? true : false;
|
||||
}
|
||||
|
||||
public bool MatchBillboardShader(Material[] materials)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public ShaderControllerSettings Settings { get; set; }
|
||||
public void CreateDefaultSettings(Material[] materials)
|
||||
{
|
||||
Settings = new ShaderControllerSettings
|
||||
{
|
||||
Heading = "Fantasy Adventure Environment Grass",
|
||||
Description = "Description text",
|
||||
LODFadePercentage = false,
|
||||
LODFadeCrossfade = false,
|
||||
SampleWind = true,
|
||||
SupportsInstantIndirect = true
|
||||
};
|
||||
|
||||
bool hasPigmentMap = Shader.GetGlobalTexture("_PigmentMap");
|
||||
|
||||
|
||||
Settings.AddLabelProperty("Color");
|
||||
Settings.AddBooleanProperty("EnablePigmentMap", "Use pigment map", "", hasPigmentMap);
|
||||
Settings.AddColorProperty("TopColor", "Top", "", ShaderControllerSettings.GetColorFromMaterials(materials, "_ColorTop"));
|
||||
Settings.AddColorProperty("BottomColor", "Bottom", "", ShaderControllerSettings.GetColorFromMaterials(materials, "_ColorBottom"));
|
||||
Settings.AddFloatProperty("WindTint", "Wind tint", "", ShaderControllerSettings.GetFloatFromMaterials(materials, "_ColorVariation"), 0, 1);
|
||||
Settings.AddFloatProperty("AmbientOcclusion", "Ambient Occlusion", "", ShaderControllerSettings.GetFloatFromMaterials(materials, "_AmbientOcclusion"), 0, 1);
|
||||
|
||||
Settings.AddLabelProperty("Translucency");
|
||||
Settings.AddFloatProperty("TranslucencyAmount", "Amount", "", ShaderControllerSettings.GetFloatFromMaterials(materials, "_TransmissionAmount"), 0, 10);
|
||||
Settings.AddFloatProperty("TranslucencySize", "Size", "", ShaderControllerSettings.GetFloatFromMaterials(materials, "_TransmissionSize"), 1, 20);
|
||||
|
||||
Settings.AddLabelProperty("Wind");
|
||||
Settings.AddFloatProperty("WindInfluence", "Influence", "", ShaderControllerSettings.GetFloatFromMaterials(materials, "_MaxWindStrength"), 0, 1);
|
||||
Settings.AddFloatProperty("WindSwinging", "Swinging", "", ShaderControllerSettings.GetFloatFromMaterials(materials, "_WindSwinging"), 0, 1);
|
||||
Settings.AddFloatProperty("WindAmplitude", "Amplitude Multiplier", "", ShaderControllerSettings.GetFloatFromMaterials(materials, "_WindAmplitudeMultiplier"), 0, 10);
|
||||
|
||||
#if TOUCH_REACT
|
||||
Settings.AddLabelProperty("Touch React");
|
||||
#else
|
||||
Settings.AddLabelProperty("Player bending");
|
||||
|
||||
#endif
|
||||
Settings.AddFloatProperty("BendingInfluence", "Influence", "", ShaderControllerSettings.GetFloatFromMaterials(materials, "_BendingInfluence"), 0, 1);
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void UpdateMaterial(Material material, EnvironmentSettings environmentSettings)
|
||||
{
|
||||
if (Settings == null) return;
|
||||
|
||||
//Force enable touch react usage
|
||||
#if TOUCH_REACT
|
||||
material.SetFloat("_VS_TOUCHBEND", 0);
|
||||
#endif
|
||||
material.SetFloat("_PigmentMapInfluence", Settings.GetBooleanPropertyValue("EnablePigmentMap") ? 1 : 0);
|
||||
|
||||
//Allow VS heightmaps to control the height
|
||||
material.SetFloat("_MaxHeight", 0.5f);
|
||||
|
||||
material.SetColor("_ColorTop", Settings.GetColorPropertyValue("TopColor"));
|
||||
material.SetColor("_ColorBottom", Settings.GetColorPropertyValue("BottomColor"));
|
||||
material.SetFloat("_ColorVariation", Settings.GetFloatPropertyValue("WindTint"));
|
||||
material.SetFloat("_AmbientOcclusion", Settings.GetFloatPropertyValue("AmbientOcclusion"));
|
||||
|
||||
material.SetFloat("_TransmissionAmount", Settings.GetFloatPropertyValue("TranslucencyAmount"));
|
||||
material.SetFloat("_TransmissionSize", Settings.GetFloatPropertyValue("TranslucencySize"));
|
||||
|
||||
material.SetFloat("_MaxWindStrength", Settings.GetFloatPropertyValue("WindInfluence"));
|
||||
material.SetFloat("_WindSwinging", Settings.GetFloatPropertyValue("WindSwinging"));
|
||||
material.SetFloat("_WindAmplitudeMultiplier", Settings.GetFloatPropertyValue("WindAmplitude"));
|
||||
|
||||
material.SetFloat("_BendingInfluence", Settings.GetFloatPropertyValue("BendingInfluence"));
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void UpdateWind(Material material, WindSettings windSettings)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,126 @@
|
||||
#if VEGETATION_STUDIO_PRO
|
||||
using AwesomeTechnologies.VegetationSystem;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AwesomeTechnologies.Shaders
|
||||
{
|
||||
// ReSharper disable once InconsistentNaming
|
||||
public class FAETreeShaderController : IShaderController
|
||||
{
|
||||
private static readonly string[] BranchShaderNames =
|
||||
{
|
||||
"FAE/Tree Branch",
|
||||
"Universal Render Pipeline/FAE/FAE_TreeBranch"
|
||||
};
|
||||
|
||||
private static readonly string[] TrunkShaderNames =
|
||||
{
|
||||
"FAE/Tree Trunk",
|
||||
"Universal Render Pipeline/FAE/FAE_TreeTrunk"
|
||||
};
|
||||
|
||||
public bool MatchShader(string shaderName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(shaderName)) return false;
|
||||
|
||||
for (int i = 0; i <= BranchShaderNames.Length - 1; i++)
|
||||
{
|
||||
if (BranchShaderNames[i].Contains(shaderName)) return true;
|
||||
}
|
||||
|
||||
for (int i = 0; i <= TrunkShaderNames.Length - 1; i++)
|
||||
{
|
||||
if (TrunkShaderNames[i].Contains(shaderName)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool MatchBillboardShader(Material[] materials)
|
||||
{
|
||||
//VSP will skip any LODs matching this shader, bypass when URP is in use so billboards are still rendered
|
||||
if (UnityEngine.Rendering.GraphicsSettings.renderPipelineAsset != null) return false;
|
||||
|
||||
for (int i = 0; i <= materials.Length - 1; i++)
|
||||
{
|
||||
if (materials[i].shader.name == "FAE/Tree Billboard" || materials[i].shader.name == "Universal Render Pipeline/FAE/FAE_TreeBillboard") return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsTrunkShader(string shaderName)
|
||||
{
|
||||
for (int i = 0; i <= TrunkShaderNames.Length - 1; i++)
|
||||
{
|
||||
if (TrunkShaderNames[i].Contains(shaderName)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public ShaderControllerSettings Settings { get; set; }
|
||||
public void CreateDefaultSettings(Material[] materials)
|
||||
{
|
||||
Settings = new ShaderControllerSettings
|
||||
{
|
||||
Heading = "Fantasy Adventure Environment Tree",
|
||||
Description = "",
|
||||
LODFadePercentage = true,
|
||||
LODFadeCrossfade = true,
|
||||
SampleWind = true,
|
||||
SupportsInstantIndirect = true
|
||||
};
|
||||
|
||||
Settings.AddLabelProperty("Branch");
|
||||
Settings.AddColorProperty("Color", "Main color", "", ShaderControllerSettings.GetColorFromMaterials(materials, "_Color"));
|
||||
Settings.AddColorProperty("HueVariation", "Hue Variation", "",
|
||||
ShaderControllerSettings.GetColorFromMaterials(materials, "_HueVariation"));
|
||||
Settings.AddColorProperty("TransmissionColor", "Transmission Color", "",
|
||||
ShaderControllerSettings.GetColorFromMaterials(materials, "_TransmissionColor"));
|
||||
Settings.AddFloatProperty("AmbientOcclusionBranch", "Ambient Occlusion", "",
|
||||
ShaderControllerSettings.GetFloatFromMaterials(materials, "_AmbientOcclusion"), 0, 1);
|
||||
Settings.AddFloatProperty("GradientBrightnessBranch", "Gradient Brightness", "",
|
||||
ShaderControllerSettings.GetFloatFromMaterials(materials, "_GradientBrightness"), 0, 2);
|
||||
|
||||
Settings.AddLabelProperty("Trunk");
|
||||
Settings.AddFloatProperty("GradientBrightnessTrunk", "Gradient Brightness", "",
|
||||
ShaderControllerSettings.GetFloatFromMaterials(materials, "_GradientBrightness"), 0, 2);
|
||||
Settings.AddFloatProperty("AmbientOcclusionTrunk", "Ambient Occlusion", "",
|
||||
ShaderControllerSettings.GetFloatFromMaterials(materials, "_AmbientOcclusion"), 0, 1);
|
||||
|
||||
Settings.AddLabelProperty("Branch Wind");
|
||||
Settings.AddFloatProperty("WindInfluence", "Max Strength", "", ShaderControllerSettings.GetFloatFromMaterials(materials, "_MaxWindStrength"), 0, 1);
|
||||
Settings.AddFloatProperty("WindAmplitude", "Amplitude Multiplier", "", ShaderControllerSettings.GetFloatFromMaterials(materials, "_WindAmplitudeMultiplier"), 0, 10);
|
||||
|
||||
}
|
||||
|
||||
public void UpdateMaterial(Material material, EnvironmentSettings environmentSettings)
|
||||
{
|
||||
if (Settings == null) return;
|
||||
|
||||
bool isTrunk = IsTrunkShader(material.shader.name);
|
||||
|
||||
if (isTrunk)
|
||||
{
|
||||
material.SetFloat("_AmbientOcclusion", Settings.GetFloatPropertyValue("AmbientOcclusionTrunk"));
|
||||
material.SetFloat("_GradientBrightness", Settings.GetFloatPropertyValue("GradientBrightnessTrunk"));
|
||||
}
|
||||
else
|
||||
{
|
||||
material.SetColor("_Color", Settings.GetColorPropertyValue("Color"));
|
||||
material.SetColor("_HueVariation", Settings.GetColorPropertyValue("HueVariation"));
|
||||
material.SetColor("_TransmissionColor", Settings.GetColorPropertyValue("TransmissionColor"));
|
||||
material.SetFloat("_AmbientOcclusion", Settings.GetFloatPropertyValue("AmbientOcclusionBranch"));
|
||||
material.SetFloat("_GradientBrightness", Settings.GetFloatPropertyValue("GradientBrightnessBranch"));
|
||||
|
||||
material.SetFloat("_MaxWindStrength", Settings.GetFloatPropertyValue("WindInfluence"));
|
||||
material.SetFloat("_WindAmplitudeMultiplier", Settings.GetFloatPropertyValue("WindAmplitude"));
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateWind(Material material, WindSettings windSettings)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,186 @@
|
||||
// Fantasy Adventure Environment
|
||||
// Copyright Staggart Creations
|
||||
// staggart.xyz
|
||||
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
namespace FAE
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
[ExecuteInEditMode]
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Sets the wind properties of the FAE shaders
|
||||
/// </summary>
|
||||
public class WindController : MonoBehaviour
|
||||
{
|
||||
public Texture2D windVectors;
|
||||
public bool visualizeVectors = false;
|
||||
/// <summary>
|
||||
/// Used to retreive the current state of the wind visualization, either on or off
|
||||
/// </summary>
|
||||
public static bool _visualizeVectors;
|
||||
|
||||
public bool listenToWindZone = false;
|
||||
public WindZone windZone;
|
||||
|
||||
[Range(0f, 1f)]
|
||||
public float windSpeed = 0.33f;
|
||||
[Range(0f, 3f)]
|
||||
public float windStrength = 1f;
|
||||
[Range(0f, 5f)]
|
||||
public float windAmplitude = 14f;
|
||||
|
||||
[Range(0f, 150f)]
|
||||
public float trunkWindSpeed = 10f;
|
||||
[Range(0f, 5f)]
|
||||
public float trunkWindWeight = 1f;
|
||||
[Range(0f, 0.99f)]
|
||||
public float trunkWindSwinging = 0.5f;
|
||||
|
||||
//Current wind parameters to be read externally
|
||||
public static float _windStrength;
|
||||
public static float _windAmplitude;
|
||||
|
||||
private static readonly int _WindVectors = Shader.PropertyToID("_WindVectors");
|
||||
private static readonly int _WindSpeed = Shader.PropertyToID("_WindSpeed");
|
||||
private static readonly int _WindStrength = Shader.PropertyToID("_WindStrength");
|
||||
private static readonly int _WindAmplitude = Shader.PropertyToID("_WindAmplitude");
|
||||
private static readonly int _WindDirection = Shader.PropertyToID("_WindDirection");
|
||||
|
||||
private static readonly int _TrunkWindSpeed = Shader.PropertyToID("_TrunkWindSpeed");
|
||||
private static readonly int _TrunkWindWeight = Shader.PropertyToID("_TrunkWindWeight");
|
||||
private static readonly int _TrunkWindSwinging = Shader.PropertyToID("_TrunkWindSwinging");
|
||||
|
||||
/// <summary>
|
||||
/// Set the wind strength
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
public void SetStrength(float value)
|
||||
{
|
||||
Shader.SetGlobalFloat(_WindStrength, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the trunk weight
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
public void SetTrunkWeight(float value)
|
||||
{
|
||||
Shader.SetGlobalFloat(_TrunkWindWeight, value);
|
||||
}
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
#if UNITY_5_5_OR_NEWER
|
||||
visualizeVectors = (Shader.GetGlobalFloat("_WindDebug") == 1) ? true : false;
|
||||
#endif
|
||||
|
||||
SetShaderParameters();
|
||||
}
|
||||
|
||||
private void OnValidate()
|
||||
{
|
||||
if (!windZone && listenToWindZone)
|
||||
{
|
||||
if (this.GetComponent<WindZone>())
|
||||
{
|
||||
windZone = this.GetComponent<WindZone>();
|
||||
}
|
||||
else
|
||||
{
|
||||
windZone = FindObjectOfType<WindZone>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (windZone && listenToWindZone)
|
||||
{
|
||||
SetStrength(windStrength * windZone.windMain);
|
||||
SetTrunkWeight(trunkWindWeight * windZone.windMain);
|
||||
}
|
||||
|
||||
Shader.SetGlobalVector(_WindDirection, this.transform.rotation * Vector3.back);
|
||||
}
|
||||
|
||||
public void Apply()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
|
||||
//Sync the static var to the local var
|
||||
visualizeVectors = _visualizeVectors;
|
||||
VisualizeVectors(visualizeVectors);
|
||||
|
||||
SetShaderParameters();
|
||||
#endif
|
||||
}
|
||||
|
||||
private void SetShaderParameters()
|
||||
{
|
||||
Shader.SetGlobalTexture(_WindVectors, windVectors);
|
||||
Shader.SetGlobalFloat(_WindSpeed, windSpeed);
|
||||
Shader.SetGlobalFloat(_WindStrength, windStrength);
|
||||
Shader.SetGlobalFloat(_WindAmplitude, windAmplitude);
|
||||
Shader.SetGlobalVector(_WindDirection, this.transform.rotation * Vector3.back);
|
||||
|
||||
Shader.SetGlobalFloat(_TrunkWindSpeed, trunkWindSpeed);
|
||||
Shader.SetGlobalFloat(_TrunkWindWeight, trunkWindWeight);
|
||||
Shader.SetGlobalFloat(_TrunkWindSwinging, trunkWindSwinging);
|
||||
|
||||
//Set static var
|
||||
WindController._windStrength = windStrength;
|
||||
WindController._windAmplitude = windAmplitude;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Toggles the visualization of the wind vectors on all shaders that feature wind animations
|
||||
/// </summary>
|
||||
/// <param name="state">boolean</param>
|
||||
public static void VisualizeVectors(bool state)
|
||||
{
|
||||
_visualizeVectors = state;
|
||||
Shader.SetGlobalFloat("_WindDebug", state ? 1f : 0f);
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
private void OnDisable()
|
||||
{
|
||||
VisualizeVectors(false);
|
||||
|
||||
Shader.SetGlobalVector("_GlobalWindParams", new Vector4(0, 0, 0, 0));
|
||||
}
|
||||
|
||||
void OnDrawGizmosSelected()
|
||||
{
|
||||
Vector3 dir = (transform.position + transform.forward).normalized;
|
||||
|
||||
Gizmos.color = Color.magenta;
|
||||
Vector3 up = transform.up;
|
||||
Vector3 side = transform.right;
|
||||
|
||||
Vector3 end = transform.position + transform.forward * (windSpeed * 10f);
|
||||
Gizmos.DrawLine(transform.position, end);
|
||||
|
||||
float s = windSpeed;
|
||||
Vector3 front = transform.forward * windSpeed;
|
||||
|
||||
Gizmos.DrawLine(end, end - front + up * s);
|
||||
Gizmos.DrawLine(end, end - front - up * s);
|
||||
Gizmos.DrawLine(end, end - front + side * s);
|
||||
Gizmos.DrawLine(end, end - front - side * s);
|
||||
|
||||
Gizmos.DrawLine(end - front - side * s, end - front + up * s);
|
||||
Gizmos.DrawLine(end - front + up * s, end - front + side * s);
|
||||
Gizmos.DrawLine(end - front + side * s, end - front - up * s);
|
||||
Gizmos.DrawLine(end - front - up * s, end - front - side * s);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "sc.fae.runtime",
|
||||
"references": [
|
||||
"GUID:fb58d5396d4f85044a40c7548929c37d"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
Reference in New Issue
Block a user