init
This commit is contained in:
commit
f5c1616018
679 changed files with 188502 additions and 0 deletions
284
Assets/Pixel3D/Scripts/GrassInstancer.cs
Normal file
284
Assets/Pixel3D/Scripts/GrassInstancer.cs
Normal file
|
@ -0,0 +1,284 @@
|
|||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using static System.Runtime.InteropServices.Marshal;
|
||||
|
||||
[RequireComponent(typeof(MeshGenerator))]
|
||||
public class GrassInstancer : MonoBehaviour
|
||||
{
|
||||
[SerializeField] LayerMask _grassLayer;
|
||||
[SerializeField] Mesh _grassMesh;
|
||||
[SerializeField] Material _material;
|
||||
[SerializeField] float _density = 10;
|
||||
[SerializeField] int _seed = 42;
|
||||
|
||||
MeshGenerator _meshGenerator;
|
||||
RenderParams _renderParams;
|
||||
|
||||
GraphicsBuffer.IndirectDrawIndexedArgs[] commandData;
|
||||
|
||||
struct GrassData
|
||||
{
|
||||
public Vector3 position;
|
||||
public Vector2 colorTexUV;
|
||||
}
|
||||
|
||||
struct GrassChunk
|
||||
{
|
||||
public Vector2Int sampleCount;
|
||||
public GraphicsBuffer commandBuffer;
|
||||
public ComputeBuffer grassBuffer;
|
||||
public Bounds bounds;
|
||||
public Material material;
|
||||
public Vector2 uvMin;
|
||||
public Vector2 uvMax;
|
||||
}
|
||||
|
||||
GrassChunk[] grassChunks;
|
||||
[SerializeField] int chunkCount = 1;
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
Setup();
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
FreeChunks();
|
||||
}
|
||||
|
||||
void Setup()
|
||||
{
|
||||
_meshGenerator = GetComponent<MeshGenerator>();
|
||||
if (_meshGenerator == null)
|
||||
Debug.LogError("MeshGenerator is null");
|
||||
|
||||
var meshRenderer = GetComponent<MeshRenderer>();
|
||||
if (meshRenderer == null)
|
||||
Debug.LogError("MeshRenderer is null");
|
||||
|
||||
if (_material == null)
|
||||
Debug.LogError("Material is null");
|
||||
|
||||
if (_grassMesh == null)
|
||||
Debug.LogError("Grass mesh is null");
|
||||
}
|
||||
|
||||
// Initialize the chunks
|
||||
public void InitChunks()
|
||||
{
|
||||
// Ensure the chunks are freed
|
||||
FreeChunks();
|
||||
|
||||
// Create the chunks
|
||||
grassChunks = new GrassChunk[chunkCount * chunkCount];
|
||||
for (int y = 0; y < chunkCount; y++)
|
||||
{
|
||||
for (int x = 0; x < chunkCount; x++)
|
||||
{
|
||||
var chunkIndex = y * chunkCount + x;
|
||||
var bounds = GetChunkBounds(x, y);
|
||||
var uvMin = new Vector2(x, y) / chunkCount;
|
||||
var uvMax = uvMin + Vector2.one / chunkCount;
|
||||
var size = new Vector2(bounds.size.x, bounds.size.z);
|
||||
var sampleCount = new Vector2Int((int)(_density * size.x), (int)(_density * size.y));
|
||||
grassChunks[chunkIndex] = new GrassChunk
|
||||
{
|
||||
commandBuffer = new GraphicsBuffer(GraphicsBuffer.Target.IndirectArguments, 1, GraphicsBuffer.IndirectDrawIndexedArgs.size),
|
||||
grassBuffer = new ComputeBuffer(sampleCount.x * sampleCount.y, SizeOf<GrassData>()),
|
||||
bounds = bounds,
|
||||
sampleCount = sampleCount,
|
||||
material = _material,
|
||||
uvMin = uvMin,
|
||||
uvMax = uvMax,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Setup a chunk
|
||||
void SetupChunk(GrassChunk chunk)
|
||||
{
|
||||
if (chunk.sampleCount.x <= 0 || chunk.sampleCount.y <= 0)
|
||||
return;
|
||||
|
||||
// Initialize the matrices
|
||||
var grassData = new GrassData[chunk.sampleCount.x * chunk.sampleCount.y];
|
||||
var meshSize = new Vector2(_meshGenerator.size.x, _meshGenerator.size.z);
|
||||
|
||||
// Loop through each grass
|
||||
var index = 0;
|
||||
for (int y = 0; y < chunk.sampleCount.y; y++)
|
||||
{
|
||||
for (int x = 0; x < chunk.sampleCount.x; x++)
|
||||
{
|
||||
// Calculate the position and uvs with random offset
|
||||
var randomOffset = Random.insideUnitCircle / 2;
|
||||
var chunkUV = (new Vector2(x, y) + Vector2.one / 2 + randomOffset) / chunk.sampleCount;
|
||||
var worldUV = new Vector2(
|
||||
Remap(chunkUV.x, 0, 1, chunk.uvMin.x, chunk.uvMax.x),
|
||||
Remap(chunkUV.y, 0, 1, chunk.uvMin.y, chunk.uvMax.y)
|
||||
);
|
||||
var position2D = (worldUV - Vector2.one / 2) * meshSize;
|
||||
var height = _meshGenerator.GetMeshHeight(worldUV);
|
||||
var position = transform.TransformPoint(new Vector3(position2D.x, height, position2D.y));
|
||||
|
||||
// Set the grass data
|
||||
grassData[index] = new GrassData
|
||||
{
|
||||
position = position,
|
||||
colorTexUV = worldUV
|
||||
};
|
||||
|
||||
// Increment the index
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
chunk.grassBuffer.SetData(grassData);
|
||||
commandData = new GraphicsBuffer.IndirectDrawIndexedArgs[1];
|
||||
commandData[0] = new GraphicsBuffer.IndirectDrawIndexedArgs
|
||||
{
|
||||
indexCountPerInstance = _grassMesh.GetIndexCount(0),
|
||||
instanceCount = (uint)(chunk.sampleCount.x * chunk.sampleCount.y),
|
||||
startIndex = _grassMesh.GetIndexStart(0),
|
||||
baseVertexIndex = _grassMesh.GetBaseVertex(0),
|
||||
startInstance = 0,
|
||||
};
|
||||
chunk.commandBuffer.SetData(commandData);
|
||||
}
|
||||
|
||||
// Free the chunks
|
||||
void FreeChunks()
|
||||
{
|
||||
if (grassChunks == null)
|
||||
return;
|
||||
|
||||
foreach (var chunk in grassChunks)
|
||||
{
|
||||
chunk.commandBuffer?.Release();
|
||||
chunk.grassBuffer?.Release();
|
||||
}
|
||||
grassChunks = null;
|
||||
}
|
||||
|
||||
void OnDrawGizmos()
|
||||
{
|
||||
if (grassChunks == null)
|
||||
return;
|
||||
|
||||
foreach (var chunk in grassChunks)
|
||||
{
|
||||
Gizmos.color = Color.red;
|
||||
Gizmos.DrawWireCube(chunk.bounds.center, chunk.bounds.size);
|
||||
}
|
||||
}
|
||||
|
||||
// Get the bounds of a chunk
|
||||
Bounds GetChunkBounds(int x, int y)
|
||||
{
|
||||
var size = new Vector2(_meshGenerator.size.x, _meshGenerator.size.z);
|
||||
var chunkSize = size / chunkCount;
|
||||
var chunkPosition = new Vector2(x, y) * chunkSize - size / 2;
|
||||
var chunkBounds = new Bounds();
|
||||
var min = new Vector3(chunkPosition.x, 0, chunkPosition.y);
|
||||
var max = new Vector3(chunkPosition.x + chunkSize.x, _meshGenerator.size.y, chunkPosition.y + chunkSize.y);
|
||||
chunkBounds.SetMinMax(
|
||||
transform.TransformPoint(min),
|
||||
transform.TransformPoint(max)
|
||||
);
|
||||
return chunkBounds;
|
||||
}
|
||||
|
||||
// Remap a value from one range to another
|
||||
float Remap(float value, float low1, float high1, float low2, float high2)
|
||||
{
|
||||
return low2 + (value - low1) * (high2 - low2) / (high1 - low1);
|
||||
}
|
||||
|
||||
public void Generate()
|
||||
{
|
||||
// Set the seed
|
||||
Random.InitState(_seed);
|
||||
|
||||
// Set the constant render params
|
||||
var block = new MaterialPropertyBlock();
|
||||
block.SetTexture("_ColorTex", _meshGenerator.colorTexture);
|
||||
block.SetFloat("_MeshHeight", _grassMesh.bounds.size.y);
|
||||
_renderParams = new RenderParams(_material)
|
||||
{
|
||||
layer = (int)Mathf.Log(_grassLayer.value, 2),
|
||||
worldBounds = new Bounds(Vector3.zero, 10000 * Vector3.one),
|
||||
matProps = block,
|
||||
receiveShadows = true,
|
||||
};
|
||||
|
||||
// Generate the chunks
|
||||
InitChunks();
|
||||
foreach (var chunk in grassChunks)
|
||||
SetupChunk(chunk);
|
||||
}
|
||||
|
||||
// Update the rotation of the grass
|
||||
void UpdateRotation()
|
||||
{
|
||||
var target = Camera.main.transform.position;
|
||||
var rotation = Quaternion.LookRotation(transform.position - target, Vector3.up);
|
||||
var quaternion = new Vector4(rotation.x, rotation.y, rotation.z, rotation.w);
|
||||
_renderParams.matProps.SetVector("_Rotation", quaternion);
|
||||
}
|
||||
|
||||
void RenderChunks()
|
||||
{
|
||||
// Update the rotation
|
||||
UpdateRotation();
|
||||
|
||||
// Render the chunks
|
||||
foreach (var chunk in grassChunks)
|
||||
{
|
||||
// Frustum culling check for the chunk
|
||||
var frustumPlanes = GeometryUtility.CalculateFrustumPlanes(Camera.main);
|
||||
if (!GeometryUtility.TestPlanesAABB(frustumPlanes, chunk.bounds))
|
||||
continue;
|
||||
|
||||
// Render the chunk
|
||||
_renderParams.matProps.SetBuffer("_GrassData", chunk.grassBuffer);
|
||||
Graphics.RenderMeshIndirect(_renderParams, _grassMesh, chunk.commandBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
// Validation checks
|
||||
if (_meshGenerator == null)
|
||||
Setup();
|
||||
|
||||
if (!_meshGenerator.IsMeshGenerated())
|
||||
_meshGenerator.GenerateTerrainMesh();
|
||||
|
||||
if (transform.lossyScale != Vector3.one)
|
||||
Debug.LogWarning("GrassInstancer does not support scaling");
|
||||
|
||||
if (grassChunks == null || grassChunks.Length == 0)
|
||||
Generate();
|
||||
|
||||
// Render the chunks
|
||||
RenderChunks();
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
// Custom editor which adds a button to generate the terrain
|
||||
[CustomEditor(typeof(GrassInstancer))]
|
||||
public class GrassInstancerEditor : Editor
|
||||
{
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
var script = (GrassInstancer)target;
|
||||
DrawDefaultInspector();
|
||||
GUILayout.Space(10);
|
||||
// GUILayout.Label("Sample Count: " + script.GetSampleCount());
|
||||
if (GUILayout.Button("Generate Grass"))
|
||||
script.Generate();
|
||||
}
|
||||
}
|
||||
#endif
|
11
Assets/Pixel3D/Scripts/GrassInstancer.cs.meta
Normal file
11
Assets/Pixel3D/Scripts/GrassInstancer.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0f0b6253ae2084750ad5801aa8fd8c18
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
51
Assets/Pixel3D/Scripts/IsometricCameraPivot.cs
Normal file
51
Assets/Pixel3D/Scripts/IsometricCameraPivot.cs
Normal file
|
@ -0,0 +1,51 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class IsometricCameraPivot : MonoBehaviour
|
||||
{
|
||||
|
||||
float _targetAngleY;
|
||||
float _currentAngleY;
|
||||
float _targetAngleX;
|
||||
float _currentAngleX;
|
||||
|
||||
[SerializeField] float _mouseSensitivity = 2;
|
||||
[SerializeField] float _rotationSpeed = 5;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
_targetAngleY = transform.eulerAngles.y;
|
||||
_targetAngleX = transform.eulerAngles.x;
|
||||
}
|
||||
|
||||
|
||||
void Update()
|
||||
{
|
||||
float mouseX = Input.GetAxis("Mouse X");
|
||||
float mouseY = Input.GetAxis("Mouse Y");
|
||||
|
||||
if (Input.GetMouseButton(0))
|
||||
{
|
||||
_targetAngleY += mouseX * _mouseSensitivity;
|
||||
_targetAngleX -= mouseY * _mouseSensitivity / 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
_targetAngleY = Mathf.Round(_targetAngleY / 45) * 45;
|
||||
_targetAngleX = Mathf.Round(_targetAngleX / 15) * 15;
|
||||
}
|
||||
|
||||
_targetAngleY = (_targetAngleY + 360) % 360;
|
||||
_targetAngleX = Mathf.Clamp(_targetAngleX, 23, 67);
|
||||
|
||||
_currentAngleY = Mathf.LerpAngle(transform.eulerAngles.y, _targetAngleY, Time.deltaTime * _rotationSpeed);
|
||||
_currentAngleX = Mathf.LerpAngle(transform.eulerAngles.x, _targetAngleX, Time.deltaTime * _rotationSpeed);
|
||||
|
||||
if (Mathf.Abs(_currentAngleY - _targetAngleY) < 0.1f) _currentAngleY = _targetAngleY;
|
||||
if (Mathf.Abs(_currentAngleX - _targetAngleX) < 0.1f) _currentAngleX = _targetAngleX;
|
||||
|
||||
transform.rotation = Quaternion.Euler(_currentAngleX, _currentAngleY, 0);
|
||||
}
|
||||
}
|
11
Assets/Pixel3D/Scripts/IsometricCameraPivot.cs.meta
Normal file
11
Assets/Pixel3D/Scripts/IsometricCameraPivot.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0717b4fb631d34d44a07d1b42a6b73ee
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
192
Assets/Pixel3D/Scripts/LeafInstancer.cs
Normal file
192
Assets/Pixel3D/Scripts/LeafInstancer.cs
Normal file
|
@ -0,0 +1,192 @@
|
|||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using static System.Runtime.InteropServices.Marshal;
|
||||
|
||||
[RequireComponent(typeof(MeshSurfaceSampler))]
|
||||
public class LeafInstancer : MonoBehaviour
|
||||
{
|
||||
[SerializeField] LayerMask _grassLayer;
|
||||
[SerializeField] Mesh _leafMesh;
|
||||
[SerializeField] Material _material;
|
||||
|
||||
MeshSurfaceSampler _meshSurfaceSampler;
|
||||
RenderParams _renderParams;
|
||||
|
||||
GraphicsBuffer commandBuffer;
|
||||
GraphicsBuffer.IndirectDrawIndexedArgs[] commandData;
|
||||
LeafData[] leafData;
|
||||
ComputeBuffer leafBuffer;
|
||||
|
||||
const int commandCount = 1;
|
||||
|
||||
struct LeafData
|
||||
{
|
||||
public Vector3 position;
|
||||
public Vector3 normal;
|
||||
}
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
Setup();
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
commandBuffer?.Release();
|
||||
commandBuffer = null;
|
||||
leafBuffer?.Release();
|
||||
leafBuffer = null;
|
||||
}
|
||||
|
||||
void Setup()
|
||||
{
|
||||
_meshSurfaceSampler = GetComponent<MeshSurfaceSampler>();
|
||||
if (_meshSurfaceSampler == null)
|
||||
Debug.LogError("MeshGenerator is null");
|
||||
|
||||
var meshRenderer = GetComponent<MeshRenderer>();
|
||||
if (meshRenderer == null)
|
||||
Debug.LogError("MeshRenderer is null");
|
||||
|
||||
if (_material == null)
|
||||
Debug.LogError("Material is null");
|
||||
|
||||
if (_leafMesh == null)
|
||||
Debug.LogError("Grass mesh is null");
|
||||
}
|
||||
|
||||
public void GeneratePoints()
|
||||
{
|
||||
_meshSurfaceSampler.GeneratePoints();
|
||||
}
|
||||
|
||||
public Bounds GetBoundingBox()
|
||||
{
|
||||
Bounds boundingBox = new Bounds();
|
||||
|
||||
if (_meshSurfaceSampler.points != null && _meshSurfaceSampler.points.Length > 0)
|
||||
{
|
||||
Vector3 minPoint = _meshSurfaceSampler.points[0];
|
||||
Vector3 maxPoint = _meshSurfaceSampler.points[0];
|
||||
|
||||
for (int i = 1; i < _meshSurfaceSampler.points.Length; i++)
|
||||
{
|
||||
minPoint = Vector3.Min(minPoint, _meshSurfaceSampler.points[i]);
|
||||
maxPoint = Vector3.Max(maxPoint, _meshSurfaceSampler.points[i]);
|
||||
}
|
||||
|
||||
boundingBox.SetMinMax(minPoint, maxPoint);
|
||||
}
|
||||
|
||||
var extrude = _material.GetFloat("_Extrude");
|
||||
boundingBox.Expand(boundingBox.size * extrude);
|
||||
|
||||
return boundingBox;
|
||||
}
|
||||
|
||||
public void Generate()
|
||||
{
|
||||
var count = _meshSurfaceSampler.points.Length;
|
||||
// var count = 1;
|
||||
|
||||
leafData = new LeafData[count];
|
||||
leafBuffer?.Release();
|
||||
leafBuffer = new ComputeBuffer(count, SizeOf<LeafData>());
|
||||
commandBuffer?.Release();
|
||||
commandBuffer = new GraphicsBuffer(GraphicsBuffer.Target.IndirectArguments, commandCount, GraphicsBuffer.IndirectDrawIndexedArgs.size);
|
||||
commandData = new GraphicsBuffer.IndirectDrawIndexedArgs[commandCount];
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
leafData[i] = new LeafData
|
||||
{
|
||||
position = _meshSurfaceSampler.points[i],
|
||||
normal = _meshSurfaceSampler.normals[i]
|
||||
};
|
||||
}
|
||||
|
||||
// Set the buffers
|
||||
var indirectDrawIndexedArgs = new GraphicsBuffer.IndirectDrawIndexedArgs
|
||||
{
|
||||
indexCountPerInstance = _leafMesh.GetIndexCount(0),
|
||||
instanceCount = (uint)count,
|
||||
startIndex = _leafMesh.GetIndexStart(0),
|
||||
baseVertexIndex = _leafMesh.GetBaseVertex(0),
|
||||
startInstance = 0,
|
||||
};
|
||||
for (int i = 0; i < commandCount; i++)
|
||||
commandData[i] = indirectDrawIndexedArgs;
|
||||
|
||||
commandBuffer.SetData(commandData);
|
||||
leafBuffer.SetData(leafData);
|
||||
|
||||
// Set the render params
|
||||
var block = new MaterialPropertyBlock();
|
||||
block.SetBuffer("_LeafData", leafBuffer);
|
||||
|
||||
_renderParams = new RenderParams(_material)
|
||||
{
|
||||
layer = (int)Mathf.Log(_grassLayer.value, 2),
|
||||
worldBounds = new Bounds(Vector3.zero, 10000 * Vector3.one),
|
||||
matProps = block,
|
||||
receiveShadows = true,
|
||||
};
|
||||
|
||||
UpdateRotation();
|
||||
}
|
||||
|
||||
// Update the rotation of the grass
|
||||
void UpdateRotation()
|
||||
{
|
||||
var target = Camera.main.transform.position;
|
||||
var rotation = Quaternion.LookRotation(transform.position - target, Vector3.up);
|
||||
var quaternion = new Vector4(rotation.x, rotation.y, rotation.z, rotation.w);
|
||||
_renderParams.matProps.SetVector("_Rotation", quaternion);
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
// Validation checks
|
||||
if (_meshSurfaceSampler == null)
|
||||
Setup();
|
||||
|
||||
if (!_meshSurfaceSampler.ArePointsGenerated())
|
||||
_meshSurfaceSampler.GeneratePoints();
|
||||
|
||||
// if (transform.lossyScale != Vector3.one)
|
||||
// Debug.LogWarning("GrassInstancer does not support scaling");
|
||||
|
||||
if (leafData == null || leafData.Length == 0)
|
||||
Generate();
|
||||
|
||||
UpdateRotation();
|
||||
|
||||
|
||||
// Frustum culling check for the chunk
|
||||
var frustumPlanes = GeometryUtility.CalculateFrustumPlanes(Camera.main);
|
||||
if (!GeometryUtility.TestPlanesAABB(frustumPlanes, GetBoundingBox()))
|
||||
return;
|
||||
|
||||
// Render the grass
|
||||
Graphics.RenderMeshIndirect(_renderParams, _leafMesh, commandBuffer, commandCount);
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
// Custom editor which adds a button to generate the terrain
|
||||
[CustomEditor(typeof(LeafInstancer))]
|
||||
public class LeafInstancerEditor : Editor
|
||||
{
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
var script = (LeafInstancer)target;
|
||||
DrawDefaultInspector();
|
||||
GUILayout.Space(10);
|
||||
if (GUILayout.Button("Generate Leaves"))
|
||||
{
|
||||
script.GeneratePoints();
|
||||
script.Generate();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
11
Assets/Pixel3D/Scripts/LeafInstancer.cs.meta
Normal file
11
Assets/Pixel3D/Scripts/LeafInstancer.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 271baf40419394e30b857a667e336d88
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
185
Assets/Pixel3D/Scripts/MeshGenerator.cs
Normal file
185
Assets/Pixel3D/Scripts/MeshGenerator.cs
Normal file
|
@ -0,0 +1,185 @@
|
|||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
[RequireComponent(typeof(MeshFilter))]
|
||||
[RequireComponent(typeof(MeshRenderer))]
|
||||
public class MeshGenerator : MonoBehaviour
|
||||
{
|
||||
public Texture2D heightMap;
|
||||
public Vector3 size = new Vector3(10, 3, 10);
|
||||
public Vector2Int sampleCount = new Vector2Int(25, 25);
|
||||
public LayerMask terrainLayer;
|
||||
[HideInInspector] public MeshData meshData;
|
||||
[HideInInspector] public Mesh mesh;
|
||||
[HideInInspector] public RenderTexture colorTexture;
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
var colorCameraObject = new GameObject("Color Camera");
|
||||
colorCameraObject.transform.parent = transform;
|
||||
colorCameraObject.transform.localPosition = Vector3.zero;
|
||||
var offset = new Vector3(0, size.y, 0);
|
||||
var rotation = Quaternion.Euler(90, 0, 0);
|
||||
colorCameraObject.transform.SetLocalPositionAndRotation(offset, rotation);
|
||||
|
||||
var colorCamera = colorCameraObject.AddComponent<Camera>();
|
||||
colorCamera.orthographic = true;
|
||||
colorCamera.orthographicSize = size.z / 2;
|
||||
colorCamera.aspect = size.x / size.z;
|
||||
colorCamera.nearClipPlane = 0;
|
||||
colorCamera.clearFlags = CameraClearFlags.Nothing;
|
||||
colorCamera.depthTextureMode = DepthTextureMode.None;
|
||||
colorCamera.cullingMask = 1 << (int)Mathf.Log(terrainLayer.value, 2);
|
||||
colorTexture = new RenderTexture(1024, 1024, 0, RenderTextureFormat.ARGB32);
|
||||
colorCamera.targetTexture = colorTexture;
|
||||
}
|
||||
|
||||
public void GenerateTerrainMesh()
|
||||
{
|
||||
// Check if the height map is null
|
||||
if (heightMap == null)
|
||||
{
|
||||
Debug.LogError("Height map is null");
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize the mesh data
|
||||
meshData = new MeshData(sampleCount.x, sampleCount.y);
|
||||
|
||||
// Loop through each vertex
|
||||
var index = 0;
|
||||
for (var y = 0; y < sampleCount.y; y++)
|
||||
{
|
||||
for (var x = 0; x < sampleCount.x; x++)
|
||||
{
|
||||
// Calculate the uv, vertex position
|
||||
var uv = new Vector2(x, y) / (sampleCount - Vector2.one);
|
||||
var vertex = (uv - Vector2.one / 2) * new Vector2(size.x, size.z);
|
||||
var heightValue = GetTrueHeight(uv);
|
||||
|
||||
// Set the vertex position and uv
|
||||
meshData.vertices[index] = new Vector3(vertex.x, heightValue, vertex.y);
|
||||
meshData.uvs[index] = uv;
|
||||
|
||||
// Add triangles if not at the edge
|
||||
if (x < sampleCount.x - 1 && y < sampleCount.y - 1)
|
||||
{
|
||||
meshData.AddTriangle(index, index + sampleCount.x + 1, index + sampleCount.x);
|
||||
meshData.AddTriangle(index + sampleCount.x + 1, index, index + 1);
|
||||
}
|
||||
|
||||
// Increment the index
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
// Create the mesh
|
||||
mesh = meshData.CreateMesh();
|
||||
|
||||
var meshFilter = GetComponent<MeshFilter>();
|
||||
if (meshFilter != null)
|
||||
meshFilter.sharedMesh = mesh;
|
||||
else
|
||||
Debug.LogError("Mesh filter is null");
|
||||
|
||||
var meshCollider = GetComponent<MeshCollider>();
|
||||
if (meshCollider != null)
|
||||
meshCollider.sharedMesh = mesh;
|
||||
}
|
||||
|
||||
// Get the height of the terrain at the given uv from the mesh
|
||||
public float GetMeshHeight(Vector2 uv)
|
||||
{
|
||||
// Calculate the precise indices
|
||||
float xIndexPrecise = uv.x * (sampleCount.x - 1);
|
||||
float zIndexPrecise = uv.y * (sampleCount.y - 1);
|
||||
|
||||
// Calculate the indices of the vertices around the point
|
||||
var xIndex = Mathf.FloorToInt(uv.x * (sampleCount.x - 1));
|
||||
var zIndex = Mathf.FloorToInt(uv.y * (sampleCount.y - 1));
|
||||
|
||||
// Ensure indices are within the bounds of the mesh
|
||||
xIndex = Mathf.Clamp(xIndex, 0, sampleCount.x - 2);
|
||||
zIndex = Mathf.Clamp(zIndex, 0, sampleCount.y - 2);
|
||||
|
||||
// Get the four vertices of the square (assuming row major and clockwise order)
|
||||
var v1 = meshData.vertices[zIndex * sampleCount.x + xIndex];
|
||||
var v2 = meshData.vertices[zIndex * sampleCount.x + xIndex + 1];
|
||||
var v3 = meshData.vertices[(zIndex + 1) * sampleCount.x + xIndex];
|
||||
var v4 = meshData.vertices[(zIndex + 1) * sampleCount.x + xIndex + 1];
|
||||
|
||||
// Bilinear interpolation
|
||||
var xRem = xIndexPrecise - xIndex;
|
||||
var zRem = zIndexPrecise - zIndex;
|
||||
var height1 = Mathf.Lerp(v1.y, v2.y, xRem);
|
||||
var height2 = Mathf.Lerp(v3.y, v4.y, xRem);
|
||||
return Mathf.Lerp(height1, height2, zRem);
|
||||
}
|
||||
|
||||
// Get the true height of the terrain at the given uv from the height map
|
||||
public float GetTrueHeight(Vector2 uv)
|
||||
{
|
||||
var x = Mathf.RoundToInt(uv.x * heightMap.width);
|
||||
var y = Mathf.RoundToInt(uv.y * heightMap.height);
|
||||
return heightMap.GetPixel(x, y).grayscale * size.y; ;
|
||||
}
|
||||
|
||||
// Check if the mesh and mesh data are generated
|
||||
public bool IsMeshGenerated()
|
||||
{
|
||||
return mesh != null && meshData != null;
|
||||
}
|
||||
}
|
||||
|
||||
// MeshData class which allows for easy mesh creation
|
||||
public class MeshData
|
||||
{
|
||||
public Vector3[] vertices;
|
||||
public int[] triangles;
|
||||
public Vector2[] uvs;
|
||||
|
||||
int triangleIndex;
|
||||
|
||||
public MeshData(int meshWidth, int meshHeight)
|
||||
{
|
||||
vertices = new Vector3[meshWidth * meshHeight];
|
||||
uvs = new Vector2[meshWidth * meshHeight];
|
||||
triangles = new int[(meshWidth - 1) * (meshHeight - 1) * 6];
|
||||
}
|
||||
|
||||
public void AddTriangle(int a, int b, int c)
|
||||
{
|
||||
triangles[triangleIndex] = a;
|
||||
triangles[triangleIndex + 1] = c;
|
||||
triangles[triangleIndex + 2] = b;
|
||||
triangleIndex += 3;
|
||||
}
|
||||
|
||||
public Mesh CreateMesh()
|
||||
{
|
||||
var mesh = new Mesh
|
||||
{
|
||||
vertices = vertices,
|
||||
triangles = triangles,
|
||||
uv = uvs
|
||||
};
|
||||
mesh.RecalculateNormals();
|
||||
return mesh;
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
// Custom editor which adds a button to generate the terrain
|
||||
[CustomEditor(typeof(MeshGenerator))]
|
||||
public class MeshGeneratorEditor : Editor
|
||||
{
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
var script = (MeshGenerator)target;
|
||||
DrawDefaultInspector();
|
||||
GUILayout.Space(10);
|
||||
if (GUILayout.Button("Generate Terrain"))
|
||||
script.GenerateTerrainMesh();
|
||||
}
|
||||
}
|
||||
#endif
|
11
Assets/Pixel3D/Scripts/MeshGenerator.cs.meta
Normal file
11
Assets/Pixel3D/Scripts/MeshGenerator.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ff993955589c54d1f980c40c04421832
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
80
Assets/Pixel3D/Scripts/MeshSurfaceSampler.cs
Normal file
80
Assets/Pixel3D/Scripts/MeshSurfaceSampler.cs
Normal file
|
@ -0,0 +1,80 @@
|
|||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class MeshSurfaceSampler : MonoBehaviour
|
||||
{
|
||||
|
||||
[SerializeField] float _density = 1;
|
||||
[SerializeField] int seed = 42;
|
||||
|
||||
Mesh _mesh;
|
||||
|
||||
[HideInInspector] public Vector3[] points;
|
||||
[HideInInspector] public Vector3[] normals;
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
_mesh = GetComponent<MeshFilter>().mesh;
|
||||
GeneratePoints();
|
||||
}
|
||||
|
||||
public void GeneratePoints()
|
||||
{
|
||||
Random.InitState(seed);
|
||||
|
||||
var tris = _mesh.triangles;
|
||||
var triangleAreas = new float[tris.Length / 3];
|
||||
|
||||
var totalArea = 0.0f;
|
||||
for (var i = 0; i < tris.Length; i += 3)
|
||||
{
|
||||
var v1 = _mesh.vertices[tris[i]];
|
||||
var v2 = _mesh.vertices[tris[i + 1]];
|
||||
var v3 = _mesh.vertices[tris[i + 2]];
|
||||
var area = TriangleArea(v1, v2, v3);
|
||||
totalArea += area;
|
||||
triangleAreas[i / 3] = area;
|
||||
}
|
||||
|
||||
var pointList = new List<Vector3>();
|
||||
var normalList = new List<Vector3>();
|
||||
|
||||
var totalPoints = Mathf.CeilToInt(totalArea * _density);
|
||||
for (var i = 0; i < triangleAreas.Length; i++)
|
||||
{
|
||||
var pointsInThisTriangle = Mathf.CeilToInt(triangleAreas[i] / totalArea * totalPoints);
|
||||
for (var j = 0; j < pointsInThisTriangle; j++)
|
||||
{
|
||||
(Vector3 point, Vector3 normal) = RandomPointAndNormalInTriangle(
|
||||
_mesh.vertices[tris[i * 3]], _mesh.vertices[tris[i * 3 + 1]], _mesh.vertices[tris[i * 3 + 2]],
|
||||
_mesh.normals[tris[i * 3]], _mesh.normals[tris[i * 3 + 1]], _mesh.normals[tris[i * 3 + 2]]);
|
||||
|
||||
pointList.Add(transform.TransformPoint(point));
|
||||
// normalList.Add(normal);
|
||||
normalList.Add(transform.TransformDirection(normal));
|
||||
// Debug.DrawRay(point, normal, Color.red, 10);
|
||||
}
|
||||
}
|
||||
points = pointList.ToArray();
|
||||
normals = normalList.ToArray();
|
||||
}
|
||||
|
||||
float TriangleArea(Vector3 v1, Vector3 v2, Vector3 v3)
|
||||
{
|
||||
return Vector3.Cross(v1 - v2, v1 - v3).magnitude * 0.5f;
|
||||
}
|
||||
|
||||
(Vector3, Vector3) RandomPointAndNormalInTriangle(Vector3 v1, Vector3 v2, Vector3 v3, Vector3 n1, Vector3 n2, Vector3 n3)
|
||||
{
|
||||
var r1 = Mathf.Sqrt(Random.value);
|
||||
var r2 = Random.value;
|
||||
var point = (1 - r1) * v1 + r1 * (1 - r2) * v2 + r1 * r2 * v3;
|
||||
var normal = ((1 - r1) * n1 + r1 * (1 - r2) * n2 + r1 * r2 * n3).normalized;
|
||||
return (point, normal);
|
||||
}
|
||||
|
||||
public bool ArePointsGenerated()
|
||||
{
|
||||
return points != null && points.Length > 0;
|
||||
}
|
||||
}
|
11
Assets/Pixel3D/Scripts/MeshSurfaceSampler.cs.meta
Normal file
11
Assets/Pixel3D/Scripts/MeshSurfaceSampler.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 99677e4825d094c0eab5be922e28904d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
474
Assets/Pixel3D/Scripts/PostProcesser.cs
Normal file
474
Assets/Pixel3D/Scripts/PostProcesser.cs
Normal file
|
@ -0,0 +1,474 @@
|
|||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
[RequireComponent(typeof(Camera)),
|
||||
// RequireComponent(typeof(SceneColorSetup))
|
||||
]
|
||||
public class PostProcesser : MonoBehaviour
|
||||
{
|
||||
[Header("Grass Overlaying Shaders")]
|
||||
public LayerMask grassLayer;
|
||||
public ShaderState grassState = ShaderState.On;
|
||||
public Shader grassReplacementShader;
|
||||
public float alphaThreshold = 0.5f;
|
||||
private GameObject _grassCameraObject;
|
||||
|
||||
[Header("Pixel Shader")]
|
||||
public ShaderState pixelState = ShaderState.On;
|
||||
public bool dynamicPixelSize = false;
|
||||
public int screenHeight = 192;
|
||||
public float pixelsPerUnit = 24f;
|
||||
[Range(1f / 32f, 1)] public float zoom = 0.125f;
|
||||
|
||||
[Header("Outline Shader")]
|
||||
public ShaderState outlineState = ShaderState.On;
|
||||
public Color outlineColor = Color.black;
|
||||
public Color edgeColor = Color.white;
|
||||
public float depthThreshold = 0.02f;
|
||||
public float normalThreshold = 0.05f;
|
||||
public Vector3 normalEdgeBias = Vector3.one;
|
||||
public float angleThreshold = 0.5f;
|
||||
public int angleFactorScale = 7;
|
||||
|
||||
[Header("Cloud Shader")]
|
||||
public ShaderState cloudState = ShaderState.On;
|
||||
public Texture2D cloudsFineDetail;
|
||||
public Texture2D cloudsMediumDetail;
|
||||
public Texture2D cloudsLargeDetail;
|
||||
public Light lightSource;
|
||||
public float cloudSpeed = 0.1f;
|
||||
[Range(0, 1)] public float cloudThickness = 0.5f;
|
||||
[Range(0, 1)] public float cloudCoverage = 0.5f;
|
||||
[Range(0, 360)] public float cloudDirection = 30f;
|
||||
public float cloudZoom = 10f;
|
||||
|
||||
|
||||
public enum ShaderState
|
||||
{
|
||||
On,
|
||||
Off,
|
||||
Debug,
|
||||
}
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
// Camera.main.depthTextureMode = DepthTextureMode.MotionVectors | DepthTextureMode.DepthNormals | DepthTextureMode.Depth;
|
||||
Camera.main.depthTextureMode = DepthTextureMode.DepthNormals | DepthTextureMode.Depth;
|
||||
if (grassState != ShaderState.Debug)
|
||||
Camera.main.cullingMask = ~(1 << (int)Mathf.Log(grassLayer.value, 2));
|
||||
|
||||
if (grassState == ShaderState.On && _grassCameraObject == null)
|
||||
{
|
||||
_grassCameraObject = new GameObject("GrassCamera");
|
||||
_grassCameraObject.transform.SetParent(Camera.main.transform);
|
||||
_grassCameraObject.AddComponent<Camera>();
|
||||
}
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
if (_grassCameraObject != null)
|
||||
{
|
||||
Destroy(_grassCameraObject);
|
||||
_grassCameraObject = null;
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateZoom()
|
||||
{
|
||||
if (Camera.main == null)
|
||||
return;
|
||||
|
||||
Camera.main.orthographicSize = 1 / zoom;
|
||||
var farPlane = 20 / zoom;
|
||||
var pos = Camera.main.transform.localPosition;
|
||||
pos.z = -farPlane / 2;
|
||||
Camera.main.transform.SetLocalPositionAndRotation(pos, Quaternion.identity);
|
||||
Camera.main.farClipPlane = farPlane;
|
||||
}
|
||||
|
||||
void OnValidate()
|
||||
{
|
||||
UpdateZoom();
|
||||
}
|
||||
|
||||
void OnRenderImage(RenderTexture src, RenderTexture dest)
|
||||
{
|
||||
var outlineMaterial = CoreUtils.CreateEngineMaterial("Custom/PixelPerfectOutline");
|
||||
outlineMaterial.SetFloat("_DepthThreshold", depthThreshold);
|
||||
outlineMaterial.SetFloat("_AngleThreshold", angleThreshold);
|
||||
outlineMaterial.SetFloat("_AngleFactorScale", angleFactorScale);
|
||||
outlineMaterial.SetFloat("_NormalThreshold", normalThreshold);
|
||||
outlineMaterial.SetVector("_NormalEdgeBias", normalEdgeBias);
|
||||
outlineMaterial.SetInteger("_DebugOutline", outlineState == ShaderState.Debug ? 1 : 0);
|
||||
outlineMaterial.SetColor("_OutlineColor", outlineColor);
|
||||
outlineMaterial.SetColor("_EdgeColor", edgeColor);
|
||||
|
||||
var grassBlendingMaterial = CoreUtils.CreateEngineMaterial("Custom/GrassBlending");
|
||||
grassBlendingMaterial.SetFloat("_AlphaThreshold", alphaThreshold);
|
||||
|
||||
UpdateZoom();
|
||||
|
||||
var pixelScreenHeight = screenHeight;
|
||||
|
||||
if (dynamicPixelSize)
|
||||
{
|
||||
pixelScreenHeight = (int)(1 / zoom * pixelsPerUnit);
|
||||
}
|
||||
|
||||
var pixelScreenWidth = (int)(pixelScreenHeight * Camera.main.aspect + 0.5f);
|
||||
|
||||
|
||||
|
||||
var tempTex = RenderTexture.GetTemporary(src.descriptor);
|
||||
var grassTex = RenderTexture.GetTemporary(src.descriptor);
|
||||
var cloudTex = RenderTexture.GetTemporary(2048, 2048);
|
||||
|
||||
var screenSize = new Vector2(Screen.width, Screen.height);
|
||||
|
||||
if (pixelState == ShaderState.On)
|
||||
{
|
||||
src.filterMode = FilterMode.Point;
|
||||
|
||||
tempTex.Release();
|
||||
tempTex.height = pixelScreenHeight;
|
||||
tempTex.width = pixelScreenWidth;
|
||||
tempTex.filterMode = FilterMode.Point;
|
||||
tempTex.Create();
|
||||
|
||||
grassTex.Release();
|
||||
grassTex.height = pixelScreenHeight;
|
||||
grassTex.width = pixelScreenWidth;
|
||||
grassTex.filterMode = FilterMode.Point;
|
||||
grassTex.Create();
|
||||
|
||||
screenSize = new Vector2(pixelScreenWidth, pixelScreenHeight);
|
||||
}
|
||||
else
|
||||
{
|
||||
src.filterMode = FilterMode.Bilinear;
|
||||
|
||||
tempTex.filterMode = FilterMode.Bilinear;
|
||||
tempTex.Release();
|
||||
tempTex.Create();
|
||||
|
||||
grassTex.filterMode = FilterMode.Bilinear;
|
||||
grassTex.Release();
|
||||
grassTex.Create();
|
||||
}
|
||||
|
||||
if (cloudState == ShaderState.On)
|
||||
{
|
||||
var cloudMaterial = CoreUtils.CreateEngineMaterial("Custom/Clouds");
|
||||
cloudMaterial.SetFloat("_Speed", cloudSpeed);
|
||||
cloudMaterial.SetFloat("_Coverage", cloudCoverage);
|
||||
cloudMaterial.SetFloat("_Thickness", cloudThickness);
|
||||
cloudMaterial.SetFloat("_Direction", cloudDirection);
|
||||
cloudMaterial.SetTexture("_FineDetail", cloudsFineDetail);
|
||||
cloudMaterial.SetTexture("_MediumDetail", cloudsMediumDetail);
|
||||
cloudMaterial.SetTexture("_LargeDetail", cloudsLargeDetail);
|
||||
|
||||
var cloudTexTemp = RenderTexture.GetTemporary(2048, 2048);
|
||||
cloudTexTemp.filterMode = FilterMode.Bilinear;
|
||||
cloudTexTemp.wrapMode = TextureWrapMode.Repeat;
|
||||
|
||||
cloudTex.filterMode = FilterMode.Bilinear;
|
||||
cloudTex.wrapMode = TextureWrapMode.Repeat;
|
||||
|
||||
Graphics.Blit(cloudTexTemp, cloudTex, cloudMaterial);
|
||||
|
||||
RenderTexture.ReleaseTemporary(cloudTexTemp);
|
||||
lightSource.cookie = cloudTex;
|
||||
lightSource.cookieSize = cloudZoom;
|
||||
}
|
||||
else
|
||||
{
|
||||
lightSource.cookie = null;
|
||||
}
|
||||
|
||||
outlineMaterial.SetVector("_ScreenSize", screenSize);
|
||||
|
||||
Camera grassCamera = null;
|
||||
if (grassState == ShaderState.On)
|
||||
{
|
||||
grassCamera = _grassCameraObject.GetComponent<Camera>();
|
||||
grassCamera.enabled = false;
|
||||
}
|
||||
|
||||
if (grassState == ShaderState.On && outlineState != ShaderState.Debug && grassCamera != null)
|
||||
{
|
||||
// var grassCameraObject = new GameObject("GrassCamera");
|
||||
// grassCameraObject.transform.SetParent(Camera.main.transform);
|
||||
|
||||
// var grassCamera = _grassCameraObject.GetComponent<Camera>();
|
||||
grassCamera.CopyFrom(Camera.main);
|
||||
grassCamera.targetTexture = grassTex;
|
||||
grassCamera.cullingMask = -1;
|
||||
grassCamera.clearFlags = CameraClearFlags.Nothing;
|
||||
grassCamera.enabled = true;
|
||||
grassCamera.RenderWithShader(grassReplacementShader, "RenderType");
|
||||
grassCamera.enabled = false;
|
||||
|
||||
// Destroy(grassCameraObject);
|
||||
grassBlendingMaterial.SetTexture("_GrassTex", grassTex);
|
||||
}
|
||||
|
||||
if (outlineState != ShaderState.Off)
|
||||
{
|
||||
Graphics.Blit(src, tempTex, outlineMaterial);
|
||||
if (grassState == ShaderState.On && outlineState != ShaderState.Debug)
|
||||
Graphics.Blit(tempTex, dest, grassBlendingMaterial);
|
||||
else
|
||||
Graphics.Blit(tempTex, dest);
|
||||
}
|
||||
else if (grassState == ShaderState.On)
|
||||
{
|
||||
Graphics.Blit(src, tempTex, grassBlendingMaterial);
|
||||
Graphics.Blit(tempTex, dest);
|
||||
}
|
||||
else
|
||||
{
|
||||
Graphics.Blit(src, tempTex);
|
||||
Graphics.Blit(tempTex, dest);
|
||||
}
|
||||
|
||||
if (grassCamera != null)
|
||||
grassCamera.targetTexture = null;
|
||||
|
||||
RenderTexture.ReleaseTemporary(tempTex);
|
||||
RenderTexture.ReleaseTemporary(grassTex);
|
||||
RenderTexture.ReleaseTemporary(cloudTex);
|
||||
|
||||
Graphics.SetRenderTarget(dest);
|
||||
}
|
||||
}
|
||||
|
||||
// using UnityEngine;
|
||||
// using UnityEngine.Rendering;
|
||||
|
||||
// [RequireComponent(typeof(Camera)),
|
||||
// RequireComponent(typeof(SceneColorSetup))]
|
||||
// public class PostProcesser : MonoBehaviour
|
||||
// {
|
||||
// [Header("Grass Overlaying Shaders")]
|
||||
// public LayerMask grassLayer;
|
||||
// public ShaderState grassState = ShaderState.On;
|
||||
// public Shader grassReplacementShader;
|
||||
// public float alphaThreshold = 0.5f;
|
||||
// private GameObject _grassCameraObject;
|
||||
|
||||
// [Header("Pixel Shader")]
|
||||
// public ShaderState pixelState = ShaderState.On;
|
||||
// public bool dynamicPixelSize = false;
|
||||
// public int screenHeight = 192;
|
||||
// public float pixelsPerUnit = 24f;
|
||||
// [Range(1f / 32f, 1)] public float zoom = 0.125f;
|
||||
|
||||
// [Header("Outline Shader")]
|
||||
// public ShaderState outlineState = ShaderState.On;
|
||||
// public Color outlineColor = Color.black;
|
||||
// public Color edgeColor = Color.white;
|
||||
// public float depthThreshold = 0.02f;
|
||||
// public float normalThreshold = 0.05f;
|
||||
// public Vector3 normalEdgeBias = Vector3.one;
|
||||
// public float angleThreshold = 0.5f;
|
||||
// public int angleFactorScale = 7;
|
||||
|
||||
// [Header("Cloud Shader")]
|
||||
// public ShaderState cloudState = ShaderState.On;
|
||||
// public Texture2D cloudsFineDetail;
|
||||
// public Texture2D cloudsMediumDetail;
|
||||
// public Texture2D cloudsLargeDetail;
|
||||
// public Light lightSource;
|
||||
// public float cloudSpeed = 0.1f;
|
||||
// [Range(0, 1)] public float cloudThickness = 0.5f;
|
||||
// [Range(0, 1)] public float cloudCoverage = 0.5f;
|
||||
// [Range(0, 360)] public float cloudDirection = 30f;
|
||||
// public float cloudZoom = 10f;
|
||||
|
||||
|
||||
// public enum ShaderState
|
||||
// {
|
||||
// On,
|
||||
// Off,
|
||||
// Debug,
|
||||
// }
|
||||
|
||||
// void OnEnable()
|
||||
// {
|
||||
// Camera.main.depthTextureMode = DepthTextureMode.DepthNormals;
|
||||
// if (grassState != ShaderState.Debug)
|
||||
// Camera.main.cullingMask = ~(1 << (int)Mathf.Log(grassLayer.value, 2));
|
||||
|
||||
// if (grassState == ShaderState.On && _grassCameraObject == null)
|
||||
// {
|
||||
// _grassCameraObject = new GameObject("GrassCamera");
|
||||
// _grassCameraObject.transform.SetParent(Camera.main.transform);
|
||||
// _grassCameraObject.AddComponent<Camera>();
|
||||
// }
|
||||
// }
|
||||
|
||||
// void OnDisable()
|
||||
// {
|
||||
// if (_grassCameraObject != null)
|
||||
// {
|
||||
// Destroy(_grassCameraObject);
|
||||
// _grassCameraObject = null;
|
||||
// }
|
||||
// }
|
||||
|
||||
// void UpdateZoom()
|
||||
// {
|
||||
// if (Camera.main == null)
|
||||
// return;
|
||||
|
||||
// Camera.main.orthographicSize = 1 / zoom;
|
||||
// var farPlane = 20 / zoom;
|
||||
// var pos = Camera.main.transform.localPosition;
|
||||
// pos.z = -farPlane / 2;
|
||||
// Camera.main.transform.SetLocalPositionAndRotation(pos, Quaternion.identity);
|
||||
// Camera.main.farClipPlane = farPlane;
|
||||
// }
|
||||
|
||||
// void OnValidate()
|
||||
// {
|
||||
// UpdateZoom();
|
||||
// }
|
||||
|
||||
// void OnRenderImage(RenderTexture src, RenderTexture dest)
|
||||
// {
|
||||
// var outlineMaterial = CoreUtils.CreateEngineMaterial("Custom/PixelPerfectOutline");
|
||||
// outlineMaterial.SetFloat("_DepthThreshold", depthThreshold);
|
||||
// outlineMaterial.SetFloat("_AngleThreshold", angleThreshold);
|
||||
// outlineMaterial.SetFloat("_AngleFactorScale", angleFactorScale);
|
||||
// outlineMaterial.SetFloat("_NormalThreshold", normalThreshold);
|
||||
// outlineMaterial.SetVector("_NormalEdgeBias", normalEdgeBias);
|
||||
// outlineMaterial.SetInteger("_DebugOutline", outlineState == ShaderState.Debug ? 1 : 0);
|
||||
// outlineMaterial.SetColor("_OutlineColor", outlineColor);
|
||||
// outlineMaterial.SetColor("_EdgeColor", edgeColor);
|
||||
|
||||
// var grassBlendingMaterial = CoreUtils.CreateEngineMaterial("Custom/GrassBlending");
|
||||
// grassBlendingMaterial.SetFloat("_AlphaThreshold", alphaThreshold);
|
||||
|
||||
// UpdateZoom();
|
||||
|
||||
// var pixelScreenHeight = screenHeight;
|
||||
|
||||
// if (dynamicPixelSize)
|
||||
// {
|
||||
// pixelScreenHeight = (int)(1 / zoom * pixelsPerUnit);
|
||||
// }
|
||||
|
||||
// var pixelScreenWidth = (int)(pixelScreenHeight * Camera.main.aspect + 0.5f);
|
||||
|
||||
|
||||
|
||||
// var tempTex = RenderTexture.GetTemporary(src.descriptor);
|
||||
// var grassTex = RenderTexture.GetTemporary(src.descriptor);
|
||||
// var cloudTex = RenderTexture.GetTemporary(2048, 2048);
|
||||
|
||||
// var screenSize = new Vector2(Screen.width, Screen.height);
|
||||
|
||||
// if (pixelState == ShaderState.On)
|
||||
// {
|
||||
// src.filterMode = FilterMode.Point;
|
||||
|
||||
// tempTex.Release();
|
||||
// tempTex.height = pixelScreenHeight;
|
||||
// tempTex.width = pixelScreenWidth;
|
||||
// tempTex.filterMode = FilterMode.Point;
|
||||
// tempTex.Create();
|
||||
|
||||
// grassTex.Release();
|
||||
// grassTex.height = pixelScreenHeight;
|
||||
// grassTex.width = pixelScreenWidth;
|
||||
// grassTex.filterMode = FilterMode.Point;
|
||||
// grassTex.Create();
|
||||
|
||||
// screenSize = new Vector2(pixelScreenWidth, pixelScreenHeight);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// src.filterMode = FilterMode.Bilinear;
|
||||
|
||||
// tempTex.filterMode = FilterMode.Bilinear;
|
||||
// tempTex.Release();
|
||||
// tempTex.Create();
|
||||
|
||||
// grassTex.filterMode = FilterMode.Bilinear;
|
||||
// grassTex.Release();
|
||||
// grassTex.Create();
|
||||
// }
|
||||
|
||||
// if (cloudState == ShaderState.On)
|
||||
// {
|
||||
// var cloudMaterial = CoreUtils.CreateEngineMaterial("Custom/Clouds");
|
||||
// cloudMaterial.SetFloat("_Speed", cloudSpeed);
|
||||
// cloudMaterial.SetFloat("_Coverage", cloudCoverage);
|
||||
// cloudMaterial.SetFloat("_Thickness", cloudThickness);
|
||||
// cloudMaterial.SetFloat("_Direction", cloudDirection);
|
||||
// cloudMaterial.SetTexture("_FineDetail", cloudsFineDetail);
|
||||
// cloudMaterial.SetTexture("_MediumDetail", cloudsMediumDetail);
|
||||
// cloudMaterial.SetTexture("_LargeDetail", cloudsLargeDetail);
|
||||
|
||||
// var cloudTexTemp = RenderTexture.GetTemporary(2048, 2048);
|
||||
// cloudTexTemp.filterMode = FilterMode.Bilinear;
|
||||
// cloudTexTemp.wrapMode = TextureWrapMode.Repeat;
|
||||
|
||||
// cloudTex.filterMode = FilterMode.Bilinear;
|
||||
// cloudTex.wrapMode = TextureWrapMode.Repeat;
|
||||
|
||||
// Graphics.Blit(cloudTexTemp, cloudTex, cloudMaterial);
|
||||
|
||||
// RenderTexture.ReleaseTemporary(cloudTexTemp);
|
||||
// lightSource.cookie = cloudTex;
|
||||
// lightSource.cookieSize = cloudZoom;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// lightSource.cookie = null;
|
||||
// }
|
||||
|
||||
// outlineMaterial.SetVector("_ScreenSize", screenSize);
|
||||
|
||||
// var grassCamera = _grassCameraObject.GetComponent<Camera>();
|
||||
|
||||
// if (grassState == ShaderState.On && outlineState != ShaderState.Debug)
|
||||
// {
|
||||
// grassCamera.CopyFrom(Camera.main);
|
||||
// grassCamera.targetTexture = grassTex;
|
||||
// grassCamera.cullingMask = -1;
|
||||
// grassCamera.clearFlags = CameraClearFlags.Nothing;
|
||||
// grassCamera.RenderWithShader(grassReplacementShader, "RenderType");
|
||||
// grassBlendingMaterial.SetTexture("_GrassTex", grassTex);
|
||||
// }
|
||||
|
||||
// if (outlineState != ShaderState.Off)
|
||||
// {
|
||||
// Graphics.Blit(src, tempTex, outlineMaterial);
|
||||
// if (grassState == ShaderState.On && outlineState != ShaderState.Debug)
|
||||
// Graphics.Blit(tempTex, dest, grassBlendingMaterial);
|
||||
// else
|
||||
// Graphics.Blit(tempTex, dest);
|
||||
// }
|
||||
// else if (grassState == ShaderState.On)
|
||||
// {
|
||||
// Graphics.Blit(src, tempTex, grassBlendingMaterial);
|
||||
// Graphics.Blit(tempTex, dest);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// Graphics.Blit(src, tempTex);
|
||||
// Graphics.Blit(tempTex, dest);
|
||||
// }
|
||||
|
||||
// if (grassCamera != null)
|
||||
// grassCamera.targetTexture = null;
|
||||
|
||||
// RenderTexture.ReleaseTemporary(tempTex);
|
||||
// RenderTexture.ReleaseTemporary(grassTex);
|
||||
// RenderTexture.ReleaseTemporary(cloudTex);
|
||||
|
||||
// Graphics.SetRenderTarget(dest);
|
||||
// }
|
||||
// }
|
11
Assets/Pixel3D/Scripts/PostProcesser.cs.meta
Normal file
11
Assets/Pixel3D/Scripts/PostProcesser.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5ae31a9a3a3e946d1a6a904b9ab115c4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
17
Assets/Pixel3D/Scripts/Rotator.cs
Normal file
17
Assets/Pixel3D/Scripts/Rotator.cs
Normal file
|
@ -0,0 +1,17 @@
|
|||
using UnityEngine;
|
||||
|
||||
public class Rotator : MonoBehaviour
|
||||
{
|
||||
[SerializeField] float _speedX = 50f;
|
||||
[SerializeField] float _speedY = 50f;
|
||||
[SerializeField] float _speedZ = 50f;
|
||||
|
||||
void Update()
|
||||
{
|
||||
var rotationX = _speedX * Time.deltaTime;
|
||||
var rotationY = _speedY * Time.deltaTime;
|
||||
var rotationZ = _speedZ * Time.deltaTime;
|
||||
|
||||
transform.Rotate(rotationX, rotationY, rotationZ, Space.Self);
|
||||
}
|
||||
}
|
11
Assets/Pixel3D/Scripts/Rotator.cs.meta
Normal file
11
Assets/Pixel3D/Scripts/Rotator.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2aa0b8e5a118943d3a3dd673af44c3aa
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
78
Assets/Pixel3D/Scripts/SceneColorSetup.cs
Normal file
78
Assets/Pixel3D/Scripts/SceneColorSetup.cs
Normal file
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
Copies the camera buffer after rendering opaques, to _CameraOpaqueTexture property so the Scene Color node can work in the Built-in RP.
|
||||
Attach this script to the Main Camera (and any other cameras you want an Opaque Texture for)
|
||||
Will also work for Scene Views (Though if a new window is opened will need to enter & exit play mode)
|
||||
Tested in 2022.2
|
||||
@Cyanilux
|
||||
*/
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
[ExecuteAlways]
|
||||
public class SceneColorSetup : MonoBehaviour
|
||||
{
|
||||
|
||||
private Camera cam;
|
||||
private CommandBuffer cmd, cmd2;
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
cam = GetComponent<Camera>();
|
||||
int rtID = Shader.PropertyToID("_CameraOpaqueTexture");
|
||||
if (cmd == null)
|
||||
{
|
||||
cmd = new CommandBuffer
|
||||
{
|
||||
name = "Setup Opaque Texture"
|
||||
};
|
||||
cmd.GetTemporaryRT(rtID, cam.pixelWidth, cam.pixelHeight, 0);
|
||||
// cmd.Blit(null, rtID);
|
||||
}
|
||||
if (cmd2 == null)
|
||||
{
|
||||
cmd2 = new CommandBuffer
|
||||
{
|
||||
name = "Release Opaque Texture"
|
||||
};
|
||||
cmd2.ReleaseTemporaryRT(rtID);
|
||||
}
|
||||
|
||||
// Game View (camera script is assigned on)
|
||||
cam.AddCommandBuffer(CameraEvent.AfterForwardOpaque, cmd);
|
||||
cam.AddCommandBuffer(CameraEvent.AfterEverything, cmd2);
|
||||
|
||||
// Scene View
|
||||
#if UNITY_EDITOR
|
||||
if (cam.tag == "MainCamera")
|
||||
{
|
||||
Camera[] sceneCameras = UnityEditor.SceneView.GetAllSceneCameras();
|
||||
foreach (Camera c in sceneCameras)
|
||||
{
|
||||
c.AddCommandBuffer(CameraEvent.AfterForwardOpaque, cmd);
|
||||
c.AddCommandBuffer(CameraEvent.AfterEverything, cmd2);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
// Game View (camera script is assigned on)
|
||||
cam.RemoveCommandBuffer(CameraEvent.AfterForwardOpaque, cmd);
|
||||
cam.RemoveCommandBuffer(CameraEvent.AfterEverything, cmd2);
|
||||
|
||||
// Scene View
|
||||
#if UNITY_EDITOR
|
||||
if (cam.tag == "MainCamera")
|
||||
{
|
||||
Camera[] sceneCameras = UnityEditor.SceneView.GetAllSceneCameras();
|
||||
foreach (Camera c in sceneCameras)
|
||||
{
|
||||
c.RemoveCommandBuffer(CameraEvent.AfterForwardOpaque, cmd);
|
||||
c.RemoveCommandBuffer(CameraEvent.AfterEverything, cmd2);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
11
Assets/Pixel3D/Scripts/SceneColorSetup.cs.meta
Normal file
11
Assets/Pixel3D/Scripts/SceneColorSetup.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 885a2b24c00804ed7b6d4990f0849e0e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
21
Assets/Pixel3D/Scripts/WaterLevelShift.cs
Normal file
21
Assets/Pixel3D/Scripts/WaterLevelShift.cs
Normal file
|
@ -0,0 +1,21 @@
|
|||
using UnityEngine;
|
||||
|
||||
public class WaterLevelShift : MonoBehaviour
|
||||
{
|
||||
public float shift = 0.5f;
|
||||
public float speed = 0.5f;
|
||||
|
||||
private float waterLevel = 0f;
|
||||
|
||||
|
||||
void Start()
|
||||
{
|
||||
waterLevel = transform.position.y;
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
float newY = waterLevel + Mathf.Sin(Time.time * speed) * shift;
|
||||
transform.position = new Vector3(transform.position.x, newY, transform.position.z);
|
||||
}
|
||||
}
|
11
Assets/Pixel3D/Scripts/WaterLevelShift.cs.meta
Normal file
11
Assets/Pixel3D/Scripts/WaterLevelShift.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 869babbd4fd3b4bdbb667ec33cc4c4af
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Loading…
Add table
Add a link
Reference in a new issue