试着做下光影玩法
This commit is contained in:
82
Assets/Scripts/Test/Light/RaycastShadowCollider.cs
Normal file
82
Assets/Scripts/Test/Light/RaycastShadowCollider.cs
Normal file
@@ -0,0 +1,82 @@
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class RaycastShadowCollider : MonoBehaviour
|
||||
{
|
||||
public Light spotLight; // <20>۹<EFBFBD><DBB9><EFBFBD>
|
||||
public GameObject shadowCaster; // Ͷ<><CDB6><EFBFBD><EFBFBD>Ӱ<EFBFBD><D3B0><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
public int rayCount = 36; // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
public float maxShadowDistance = 10f;
|
||||
|
||||
private PolygonCollider2D shadowCollider;
|
||||
|
||||
void Start()
|
||||
{
|
||||
shadowCollider = GetComponent<PolygonCollider2D>();
|
||||
if (shadowCollider == null)
|
||||
shadowCollider = gameObject.AddComponent<PolygonCollider2D>();
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
UpdateShadowCollider();
|
||||
}
|
||||
|
||||
void UpdateShadowCollider()
|
||||
{
|
||||
List<Vector2> shadowPoints = new List<Vector2>();
|
||||
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߽<EFBFBD><DFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ƹⷽ<C6B9><E2B7BD>Ͷ<EFBFBD><CDB6><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
Bounds bounds = shadowCaster.GetComponent<Renderer>().bounds;
|
||||
Vector3[] boundPoints = GetBoundPoints(bounds);
|
||||
|
||||
foreach (Vector3 point in boundPoints)
|
||||
{
|
||||
Vector3 toLight = (spotLight.transform.position - point).normalized;
|
||||
Ray ray = new Ray(point, toLight);
|
||||
RaycastHit hit;
|
||||
|
||||
if (Physics.Raycast(ray, out hit, maxShadowDistance))
|
||||
{
|
||||
if (hit.collider.gameObject == gameObject) // <20><><EFBFBD><EFBFBD>ǽ<EFBFBD><C7BD>
|
||||
{
|
||||
// ת<><D7AA><EFBFBD><EFBFBD>ǽ<EFBFBD><C7BD><EFBFBD>ľֲ<C4BE><D6B2><EFBFBD><EFBFBD><EFBFBD>ϵ
|
||||
Vector3 localHit = transform.InverseTransformPoint(hit.point);
|
||||
shadowPoints.Add(new Vector2(localHit.x, localHit.y));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// <20>Ե<EFBFBD><D4B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>γ<EFBFBD><EFBFBD><CDB9>
|
||||
if (shadowPoints.Count > 2)
|
||||
{
|
||||
List<Vector2> convexHull = ComputeConvexHull(shadowPoints);
|
||||
shadowCollider.SetPath(0, convexHull);
|
||||
}
|
||||
}
|
||||
|
||||
Vector3[] GetBoundPoints(Bounds bounds)
|
||||
{
|
||||
return new Vector3[]
|
||||
{
|
||||
bounds.min,
|
||||
bounds.max,
|
||||
new Vector3(bounds.min.x, bounds.min.y, bounds.max.z),
|
||||
new Vector3(bounds.min.x, bounds.max.y, bounds.min.z),
|
||||
new Vector3(bounds.max.x, bounds.min.y, bounds.min.z),
|
||||
new Vector3(bounds.min.x, bounds.max.y, bounds.max.z),
|
||||
new Vector3(bounds.max.x, bounds.min.y, bounds.max.z),
|
||||
new Vector3(bounds.max.x, bounds.max.y, bounds.min.z)
|
||||
};
|
||||
}
|
||||
|
||||
// <><CDB9><EFBFBD>㷨<EFBFBD><E3B7A8>Graham Scan<61><6E>
|
||||
List<Vector2> ComputeConvexHull(List<Vector2> points)
|
||||
{
|
||||
if (points.Count < 3) return points;
|
||||
|
||||
// ʵ<><CAB5><EFBFBD><CDB9><EFBFBD>㷨...
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><CAB9>Unity<74><79>Collider2D.CreatePrimitive<76><65><EFBFBD>ߵ<EFBFBD><DFB5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
return points; // <20><EFBFBD><F2BBAFB7><EFBFBD>
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Test/Light/RaycastShadowCollider.cs.meta
Normal file
11
Assets/Scripts/Test/Light/RaycastShadowCollider.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 21f7e71103c1a5941af3223174264656
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
124
Assets/Scripts/Test/Light/ShadowColliderGenerator.cs
Normal file
124
Assets/Scripts/Test/Light/ShadowColliderGenerator.cs
Normal file
@@ -0,0 +1,124 @@
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class ShadowColliderGenerator : MonoBehaviour
|
||||
{
|
||||
public Camera shadowCamera; // ר<><D7A8><EFBFBD><EFBFBD>Ⱦ<EFBFBD><C8BE>Ӱ<EFBFBD><D3B0><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
public RenderTexture shadowRT; // <20><>Ⱦ<EFBFBD><C8BE><EFBFBD><EFBFBD>
|
||||
public LayerMask shadowCasterLayer; // Ͷ<><CDB6><EFBFBD><EFBFBD>Ӱ<EFBFBD><D3B0><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
public float colliderPrecision = 0.1f; // <20><>ײ<EFBFBD>徫<EFBFBD><E5BEAB>
|
||||
|
||||
private Texture2D processedTexture;
|
||||
private PolygonCollider2D polygonCollider;
|
||||
|
||||
void Start()
|
||||
{
|
||||
// <20><>ʼ<EFBFBD><CABC><EFBFBD><EFBFBD>Ⱦ<EFBFBD><C8BE><EFBFBD><EFBFBD>
|
||||
shadowRT = new RenderTexture(512, 512, 24);
|
||||
shadowCamera.targetTexture = shadowRT;
|
||||
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>õ<EFBFBD><C3B5><EFBFBD><EFBFBD><EFBFBD>
|
||||
processedTexture = new Texture2D(512, 512, TextureFormat.RGB24, false);
|
||||
|
||||
polygonCollider = GetComponent<PolygonCollider2D>();
|
||||
if (polygonCollider == null)
|
||||
polygonCollider = gameObject.AddComponent<PolygonCollider2D>();
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
GenerateShadowCollider();
|
||||
}
|
||||
|
||||
void GenerateShadowCollider()
|
||||
{
|
||||
// 1. <20><>Ⱦ<EFBFBD><C8BE>Ӱ<EFBFBD><D3B0><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
shadowCamera.Render();
|
||||
|
||||
// 2. <20><>GPU<50><55>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>CPU
|
||||
RenderTexture.active = shadowRT;
|
||||
processedTexture.ReadPixels(new Rect(0, 0, shadowRT.width, shadowRT.height), 0, 0);
|
||||
processedTexture.Apply();
|
||||
RenderTexture.active = null;
|
||||
|
||||
// 3. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ӱ<EFBFBD><D3B0>Ե
|
||||
List<Vector2> edgePoints = DetectEdges(processedTexture);
|
||||
|
||||
// 4. ת<><D7AA>Ϊ<EFBFBD><CEAA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>겢<EFBFBD><EAB2A2><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ײ<EFBFBD><D7B2>
|
||||
if (edgePoints.Count > 2)
|
||||
{
|
||||
List<Vector2> worldPoints = ConvertToWorldCoordinates(edgePoints);
|
||||
polygonCollider.SetPath(0, worldPoints);
|
||||
}
|
||||
}
|
||||
|
||||
List<Vector2> DetectEdges(Texture2D texture)
|
||||
{
|
||||
List<Vector2> edges = new List<Vector2>();
|
||||
Color[] pixels = texture.GetPixels();
|
||||
|
||||
int width = texture.width;
|
||||
int height = texture.height;
|
||||
|
||||
// <20>ı<F2B5A5B5>Ե<EFBFBD><D4B5><EFBFBD><EFBFBD><EFBFBD>㷨
|
||||
for (int y = 1; y < height - 1; y += (int)(1f / colliderPrecision))
|
||||
{
|
||||
for (int x = 1; x < width - 1; x += (int)(1f / colliderPrecision))
|
||||
{
|
||||
int index = y * width + x;
|
||||
|
||||
// <20><><EFBFBD>鵱ǰ<E9B5B1><C7B0><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Χ<EFBFBD><CEA7><EFBFBD>صIJ<D8B5><C4B2><EFBFBD>
|
||||
if (IsEdgePixel(pixels, index, width))
|
||||
{
|
||||
edges.Add(new Vector2(x, y));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return edges;
|
||||
}
|
||||
|
||||
bool IsEdgePixel(Color[] pixels, int index, int width)
|
||||
{
|
||||
Color current = pixels[index];
|
||||
float currentBrightness = current.r + current.g + current.b;
|
||||
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
float[] neighborBrightness = new float[4]
|
||||
{
|
||||
pixels[index - 1].r + pixels[index - 1].g + pixels[index - 1].b, // <20><>
|
||||
pixels[index + 1].r + pixels[index + 1].g + pixels[index + 1].b, // <20><>
|
||||
pixels[index - width].r + pixels[index - width].g + pixels[index - width].b, // <20><>
|
||||
pixels[index + width].r + pixels[index + width].g + pixels[index + width].b // <20><>
|
||||
};
|
||||
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǰ<EFBFBD><C7B0><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ھӲ<DABE><D3B2><EFBFBD><EFBFBD>ϴ<EFBFBD><CFB4><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD>DZ<EFBFBD>Ե
|
||||
float threshold = 0.3f;
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
if (Mathf.Abs(currentBrightness - neighborBrightness[i]) > threshold)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
List<Vector2> ConvertToWorldCoordinates(List<Vector2> texturePoints)
|
||||
{
|
||||
List<Vector2> worldPoints = new List<Vector2>();
|
||||
Bounds wallBounds = GetComponent<Collider2D>().bounds;
|
||||
|
||||
foreach (Vector2 point in texturePoints)
|
||||
{
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ת<EFBFBD><D7AA>Ϊǽ<CEAA><C7BD><EFBFBD>ֲ<EFBFBD><D6B2><EFBFBD><EFBFBD><EFBFBD>
|
||||
Vector2 localPoint = new Vector2(
|
||||
point.x / shadowRT.width * wallBounds.size.x - wallBounds.size.x * 0.5f,
|
||||
point.y / shadowRT.height * wallBounds.size.y - wallBounds.size.y * 0.5f
|
||||
);
|
||||
|
||||
worldPoints.Add(localPoint);
|
||||
}
|
||||
|
||||
return worldPoints;
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Test/Light/ShadowColliderGenerator.cs.meta
Normal file
11
Assets/Scripts/Test/Light/ShadowColliderGenerator.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 28f43899f7559ca4e915497eaf23cc4f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
40
Assets/Scripts/Test/Light/ShadowRT.renderTexture
Normal file
40
Assets/Scripts/Test/Light/ShadowRT.renderTexture
Normal file
@@ -0,0 +1,40 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!84 &8400000
|
||||
RenderTexture:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: ShadowRT
|
||||
m_ImageContentsHash:
|
||||
serializedVersion: 2
|
||||
Hash: 00000000000000000000000000000000
|
||||
m_ForcedFallbackFormat: 4
|
||||
m_DownscaleFallback: 0
|
||||
m_IsAlphaChannelOptional: 0
|
||||
serializedVersion: 5
|
||||
m_Width: 256
|
||||
m_Height: 256
|
||||
m_AntiAliasing: 1
|
||||
m_MipCount: -1
|
||||
m_DepthStencilFormat: 94
|
||||
m_ColorFormat: 8
|
||||
m_MipMap: 0
|
||||
m_GenerateMips: 1
|
||||
m_SRGB: 0
|
||||
m_UseDynamicScale: 0
|
||||
m_BindMS: 0
|
||||
m_EnableCompatibleFormat: 1
|
||||
m_EnableRandomWrite: 0
|
||||
m_TextureSettings:
|
||||
serializedVersion: 2
|
||||
m_FilterMode: 1
|
||||
m_Aniso: 0
|
||||
m_MipBias: 0
|
||||
m_WrapU: 1
|
||||
m_WrapV: 1
|
||||
m_WrapW: 1
|
||||
m_Dimension: 2
|
||||
m_VolumeDepth: 1
|
||||
m_ShadowSamplingMode: 2
|
||||
8
Assets/Scripts/Test/Light/ShadowRT.renderTexture.meta
Normal file
8
Assets/Scripts/Test/Light/ShadowRT.renderTexture.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3746a9ea25b5f084f963f36250ae89a2
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 8400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user