通过点击或者调用ShowUnitHighLight方法,即可实现同层级内所有节点的材质半透明和指定物体正常材质的功能。
示例图如下
脚本如下
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RaycastTransparency : MonoBehaviour
{
public Material transparentMaterial; // 统一的半透明材质
private Transform lastHitTransform; // 上一次点击的对象
private Dictionary<Transform, Material[]> originalMaterialsCache = new Dictionary<Transform, Material[]>(); // 缓存每个节点的原始材质
void Update()
{
if (Input.GetMouseButtonDown(0)) // 检测鼠标左键点击
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out RaycastHit hit))
{
if (hit.collider != null)
{
ShowUnitHighLight(hit.collider.transform);
}
}
}
}
public void ShowUnitHighLight(Transform hit) {
// 获取点击的对象
Transform hitTransform = hit;
// 如果点击的是新对象
if (hitTransform != lastHitTransform)
{
// 恢复上一次点击的对象及其子节点的原始材质
if (lastHitTransform != null)
{
RestoreMaterialsRecursive(lastHitTransform);
}
// 获取同级对象
Transform parent = hitTransform.parent;
if (parent != null)
{
foreach (Transform sibling in parent)
{
if (sibling != hitTransform)
{
// 将其他同级对象及其子节点设置为半透明材质
SetMaterialRecursive(sibling, transparentMaterial);
}
}
}
// 将当前点击的对象及其子节点恢复为原始材质
RestoreMaterialsRecursive(hitTransform);
// 更新上一次点击的对象
lastHitTransform = hitTransform;
}
}
// 递归设置对象及其子节点的材质
void SetMaterialRecursive(Transform target, Material material)
{
Renderer renderer = target.GetComponent<Renderer>();
if (renderer != null)
{
// 缓存原始材质(如果尚未缓存)
if (!originalMaterialsCache.ContainsKey(target))
{
originalMaterialsCache[target] = renderer.materials;
}
// 设置新材质
Material[] newMaterials = new Material[renderer.materials.Length];
for (int i = 0; i < newMaterials.Length; i++)
{
newMaterials[i] = material;
}
renderer.materials = newMaterials;
}
// 递归设置子节点的材质
foreach (Transform child in target)
{
SetMaterialRecursive(child, material);
}
}
// 递归恢复对象及其子节点的原始材质
void RestoreMaterialsRecursive(Transform target)
{
Renderer renderer = target.GetComponent<Renderer>();
if (renderer != null && originalMaterialsCache.ContainsKey(target))
{
// 恢复原始材质
renderer.materials = originalMaterialsCache[target];
}
// 递归恢复子节点的原始材质
foreach (Transform child in target)
{
RestoreMaterialsRecursive(child);
}
}
}
脚本可随意挂载,需要注意的是hit.collider != null这里只做了碰撞体的判断条件可以根据需求增加其他指定需求,并且改功能只实现了同级节点以及子节点之间的材质交互,碰撞体的父节点无法实现交互。