This commit is contained in:
CortexCore
2023-09-01 14:33:54 +08:00
parent 4fadd3a530
commit 8ef5c7ec0a
451 changed files with 1048940 additions and 2028 deletions

View File

@@ -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);
}
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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
}
}

View File

@@ -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;
}
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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
}
}

View File

@@ -0,0 +1,15 @@
{
"name": "sc.fae.runtime",
"references": [
"GUID:fb58d5396d4f85044a40c7548929c37d"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}