BITFALL/Assets/Artists/Scripts/Props/Scope/Prop_ScopeShaderService.cs

105 lines
3.2 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using BITKit;
using UnityEngine;
namespace BITFALL.Props
{
public class Prop_ScopeShaderService : MonoBehaviour
{
private static readonly int ScopePosition = Shader.PropertyToID("_ScopePosition");
private static readonly int ScopeRadius = Shader.PropertyToID("_ScopeRadius");
private static readonly int ScopeDepth = Shader.PropertyToID("_ScopeDepth");
private static readonly int ScopeSizeOffset = Shader.PropertyToID("_ScopeSizeOffset");
[SerializeField] private Shader shader;
[SerializeField] private new Camera camera;
[SerializeField, ReadOnly(HideLabel = true)]
private string buildReport;
private readonly StringBuilder reportBuilder = new StringBuilder();
private void LateUpdate()
{
reportBuilder.Clear();
foreach (var i in Prop_ScopeMeshComponent.List)
{
if (i.IsInitialized is true) continue;
// foreach (var ii in i.GetComponentsInChildren<Renderer>())
// {
// ii.material.shader = i.overrideShader ? i.overrideShader : shader;
// }
if (i.TryGetComponent<Renderer>(out var nextRenderer))
{
nextRenderer.material.shader = i.overrideShader ? i.overrideShader : shader;
}
i.IsInitialized = true;
}
foreach (var x in Prop_ScopeDataComponent.List)
{
reportBuilder.AppendLine($"{x.name}\tRadius:{x.Radius}\tScreenPoint:{x.Position}");
Shader.SetGlobalVector(ScopePosition,x.Position);
Shader.SetGlobalFloat(ScopeRadius,x.Radius);
var position = x.Position + x.Rotation * new Vector3(x.Radius,x.Radius);
var screenPoint = CustomWorldToScreenPoint(position,27);
reportBuilder.AppendLine($"ScreenPoint:{screenPoint}");
screenPoint.x = Mathf.Abs(screenPoint.x - camera.pixelWidth/2f) / camera.pixelWidth * 2;
screenPoint.y =Mathf.Abs(screenPoint.y - camera.pixelHeight/2f) /camera.pixelHeight * 2;
Shader.SetGlobalVector(ScopeSizeOffset,screenPoint);
reportBuilder.AppendLine($"ScreenOffset:{screenPoint}");
}
buildReport = reportBuilder.ToString();
}
public static Vector3 CustomWorldToScreenPoint(Vector3 worldPosition,float customFOV)
{
Camera customCamera = Camera.main!;
// 获取相机属性
float customAspect = customCamera.aspect;
float customNearClipPlane = customCamera.nearClipPlane;
// 将FOV转换为弧度
float customFieldOfViewRad = Mathf.Deg2Rad * customFOV;
// 计算投影矩阵的参数
float tanHalfFOV = Mathf.Tan(customFieldOfViewRad * 0.5f);
float screenHeight = 2.0f * customNearClipPlane * tanHalfFOV;
float screenWidth = screenHeight * customAspect;
// 计算世界坐标相对于相机的位置
Vector3 cameraRelativePosition = worldPosition - customCamera.transform.position;
// 计算归一化设备坐标(NDC)
Vector3 ndc = new Vector3(
cameraRelativePosition.x / (screenWidth * 0.5f),
cameraRelativePosition.y / (screenHeight * 0.5f),
cameraRelativePosition.z / customNearClipPlane
);
// 将归一化设备坐标映射到屏幕坐标
Vector3 screenPoint = new Vector3(
(ndc.x + 1.0f) * 0.5f * customCamera.pixelWidth,
(ndc.y + 1.0f) * 0.5f * customCamera.pixelHeight,
ndc.z
);
return screenPoint;
}
}
}