기술 자료

Unity Engine


User Manual

Script Reference

Unity Engine


Place Light Probes with a script

An example of forming a ring of Light Probes with a script.
읽는 시간 4분최근 업데이트: 23일 전

Placing Light Probes over large levels by hand can be time consuming. You can automate the placing of light probes by writing your own editor scripts. Your script can create a new GameObject with a LightProbeGroup component, and you can add probe positions individually according to any rules that you choose to program.
For example, this script can place Light Probes in a circle or a ring.
using UnityEngine;using System.Collections.Generic;[RequireComponent (typeof (LightProbeGroup))]public class LightProbesTetrahedralGrid : MonoBehaviour{ // Common public float m_Side = 1.0f; public float m_Radius = 5.0f; public float m_InnerRadius = 0.1f; public float m_Height = 2.0f; public uint m_Levels = 3; const float kMinSide = 0.05f; const float kMinHeight = 0.05f; const float kMinInnerRadius = 0.1f; const uint kMinIterations = 4; public void OnValidate () { m_Side = Mathf.Max (kMinSide, m_Side); m_Height = Mathf.Max (kMinHeight, m_Height); if (m_InnerRadius < kMinInnerRadius) { TriangleProps props = new TriangleProps (m_Side); m_Radius = Mathf.Max (props.circumscribedCircleRadius + 0.01f, m_Radius); } else { m_Radius = Mathf.Max (0.1f, m_Radius); m_InnerRadius = Mathf.Min (m_Radius, m_InnerRadius); } } struct TriangleProps { public TriangleProps (float triangleSide) { side = triangleSide; halfSide = side / 2.0f; height = Mathf.Sqrt (3.0f) * side / 2.0f; inscribedCircleRadius = Mathf.Sqrt (3.0f) * side / 6.0f; circumscribedCircleRadius = 2.0f * height / 3.0f; } public float side; public float halfSide; public float height; public float inscribedCircleRadius; public float circumscribedCircleRadius; }; private TriangleProps m_TriangleProps; public void Generate () { LightProbeGroup lightProbeGroup = GetComponent<LightProbeGroup> (); List<Vector3> positions = new List<Vector3> (); m_TriangleProps = new TriangleProps (m_Side); if (m_InnerRadius < kMinInnerRadius) GenerateCylinder (m_TriangleProps, m_Radius, m_Height, m_Levels, positions); else GenerateRing (m_TriangleProps, m_Radius, m_InnerRadius, m_Height, m_Levels, positions); lightProbeGroup.probePositions = positions.ToArray (); } static void AttemptAdding (Vector3 position, Vector3 center, float distanceCutoffSquared, List<Vector3> outPositions) { if ((position - center).sqrMagnitude < distanceCutoffSquared) outPositions.Add (position); } uint CalculateCylinderIterations (TriangleProps props, float radius) { int iterations = Mathf.CeilToInt ((radius + props.height - props.inscribedCircleRadius) / props.height); if (iterations > 0) return (uint)iterations; return 0; } void GenerateCylinder (TriangleProps props, float radius, float height, uint levels, List<Vector3> outPositions) { uint iterations = CalculateCylinderIterations (props, radius); float distanceCutoff = radius; float distanceCutoffSquared = distanceCutoff * distanceCutoff; Vector3 up = new Vector3 (props.circumscribedCircleRadius, 0.0f, 0.0f); Vector3 leftDown = new Vector3 (-props.inscribedCircleRadius, 0.0f, -props.halfSide); Vector3 rightDown = new Vector3 (-props.inscribedCircleRadius, 0.0f, props.halfSide); for (uint l = 0; l < levels; l++) { float tLevel = levels == 1 ? 0 : (float)l / (float)(levels - 1); Vector3 center = new Vector3 (0.0f, tLevel * height, 0.0f); if (l % 2 == 0) { for (uint i = 0; i < iterations; i++) { Vector3 upCorner = center + up + (float)i * up * 2.0f * 3.0f / 2.0f; Vector3 leftDownCorner = center + leftDown + (float)i * leftDown * 2.0f * 3.0f / 2.0f; Vector3 rightDownCorner = center + rightDown + (float)i * rightDown * 2.0f * 3.0f / 2.0f; AttemptAdding (upCorner, center, distanceCutoffSquared, outPositions); AttemptAdding (leftDownCorner, center, distanceCutoffSquared, outPositions); AttemptAdding (rightDownCorner, center, distanceCutoffSquared, outPositions); Vector3 leftDownUp = upCorner - leftDownCorner; Vector3 upRightDown = rightDownCorner - upCorner; Vector3 rightDownLeftDown = leftDownCorner - rightDownCorner; uint subdiv = 3 * i + 1; for (uint s = 1; s < subdiv; s++) { Vector3 leftDownUpSubdiv = leftDownCorner + leftDownUp * (float)s / (float)subdiv; AttemptAdding (leftDownUpSubdiv, center, distanceCutoffSquared, outPositions); Vector3 upRightDownSubdiv = upCorner + upRightDown * (float)s / (float)subdiv; AttemptAdding (upRightDownSubdiv, center, distanceCutoffSquared, outPositions); Vector3 rightDownLeftDownSubdiv = rightDownCorner + rightDownLeftDown * (float)s / (float)subdiv; AttemptAdding (rightDownLeftDownSubdiv, center, distanceCutoffSquared, outPositions); } } } else { for (uint i = 0; i < iterations; i++) { Vector3 upCorner = center + (float)i * (2.0f * up * 3.0f / 2.0f); Vector3 leftDownCorner = center + (float)i * (2.0f * leftDown * 3.0f / 2.0f); Vector3 rightDownCorner = center + (float)i * (2.0f * rightDown * 3.0f / 2.0f); AttemptAdding (upCorner, center, distanceCutoffSquared, outPositions); AttemptAdding (leftDownCorner, center, distanceCutoffSquared, outPositions); AttemptAdding (rightDownCorner, center, distanceCutoffSquared, outPositions); Vector3 leftDownUp = upCorner - leftDownCorner; Vector3 upRightDown = rightDownCorner - upCorner; Vector3 rightDownLeftDown = leftDownCorner - rightDownCorner; uint subdiv = 3 * i; for (uint s = 1; s < subdiv; s++) { Vector3 leftDownUpSubdiv = leftDownCorner + leftDownUp * (float)s / (float)subdiv; AttemptAdding (leftDownUpSubdiv, center, distanceCutoffSquared, outPositions); Vector3 upRightDownSubdiv = upCorner + upRightDown * (float)s / (float)subdiv; AttemptAdding (upRightDownSubdiv, center, distanceCutoffSquared, outPositions); Vector3 rightDownLeftDownSubdiv = rightDownCorner + rightDownLeftDown * (float)s / (float)subdiv; AttemptAdding (rightDownLeftDownSubdiv, center, distanceCutoffSquared, outPositions); } } } } } void GenerateRing (TriangleProps props, float radius, float innerRadius, float height, uint levels, List<Vector3> outPositions) { float chordLength = props.side; float angle = Mathf.Clamp (2.0f * Mathf.Asin (chordLength / (2.0f * radius)), 0.01f, 2.0f * Mathf.PI); uint slicesAtRadius = (uint)Mathf.FloorToInt (2.0f * Mathf.PI / angle); uint layers = (uint)Mathf.Max (Mathf.Ceil ((radius - innerRadius) / props.height), 0.0f); for (uint level = 0; level < levels; level++) { float tLevel = levels == 1 ? 0 : (float)level / (float)(levels - 1); float y = height * tLevel; float iterationOffset0 = level % 2 == 0 ? 0.0f : 0.5f; for (uint layer = 0; layer < layers; layer++) { float tLayer = layers == 1 ? 1.0f : (float)layer / (float)(layers - 1); float tIterations = (tLayer * (radius - innerRadius) + innerRadius - kMinInnerRadius) / (radius - kMinInnerRadius); uint slices = (uint)Mathf.CeilToInt (Mathf.Lerp (kMinIterations, slicesAtRadius, tIterations)); float x = innerRadius + (radius - innerRadius) * tLayer; Vector3 position = new Vector3 (x, y, 0.0f); float layerSliceOffset = layer % 2 == 0 ? 0.0f : 0.5f; for (uint slice = 0; slice < slices; slice++) { Quaternion rotation = Quaternion.Euler (0.0f, (slice + iterationOffset0 + layerSliceOffset) * 360.0f / (float)slices, 0.0f); outPositions.Add (rotation * position); } } } }}