【问题标题】:How do I only render objects within a radius of a specific point?如何仅渲染特定点半径内的对象?
【发布时间】:2017-05-13 04:53:58
【问题描述】:

我希望我的相机仅渲染特定点半径内的对象,该点将独立于相机的位置,因此我应该能够在我的世界的这个子部分飞行。该中心点会随着游戏的进行而改变。

我还希望边缘进行 alpha 混合,而不是立即结束(这将是一款移动增强现实游戏)。

是否有现有的技术可以做到这一点?也许是着色器之类的?

【问题讨论】:

  • Unity OnBecomeInvisible 和 OnBecomeVisible .. 它只在相机看到物体时调用...但我认为它需要改进。
  • 这不是我想要的。该点与相机无关,我只想渲染我的世界的一个子集,任意点的 X 半径内的所有内容。
  • 所以只需在点周围的任何对象中获取所有渲染组件。 docs.unity3d.com/ScriptReference/… .... 并禁用/启用组件。对吧??

标签: unity3d mobile


【解决方案1】:

我想出了一些办法来解决这个问题。我刚刚注意到这个问题仍然存在,所以我想我会分享解决方案。

将以下脚本添加到您的相机

using UnityEngine;

[ExecuteInEditMode]
[RequireComponent(typeof(Camera))]
public class UniverseSubSection : MonoBehaviour
{
    public Shader shader;
    [Header("Center of the universe")]
    public Vector3 fixedCenterOfUniverse;
    public Transform objectAtCenterOfUniverse;
    [Header("Universe configuration")]
    public float universeRadius = 2f;
    public float featheringRadius = 1f;
    public Color chromaKey = new Color(0, 1, 0, 0.618f);
    public bool clipBelowGround = true;
    [Header("Background")]
    public Texture backgroundTexture;
    public MonoBehaviour backgroundTextureProvider;

    Material material;
    new Camera camera;

    void Update()
    {
        GetComponent<Camera>().depthTextureMode = DepthTextureMode.Depth;
    }

    void OnRenderImage(RenderTexture source, RenderTexture destination)
    {
        if (material == null)
        {
            material = new Material(shader);
            material.hideFlags = HideFlags.DontSave;
            camera = GetComponent<Camera>();
            camera.backgroundColor = chromaKey;
        }

        material.SetFloat("_UniverseRadius", universeRadius);
        material.SetFloat("_FeatheringRadius", featheringRadius);
        material.SetColor("_ChromaKey", chromaKey);
        material.SetInt("_ClipBelowGround", clipBelowGround ? 1 : 0);

        var matrix = camera.cameraToWorldMatrix;
        material.SetMatrix("_InverseView", matrix);

        Vector3 centerPosition = objectAtCenterOfUniverse != null ? objectAtCenterOfUniverse.position : fixedCenterOfUniverse;
        material.SetVector("_CenterOfUniverse", centerPosition);

        Texture background = null;
        if (backgroundTexture != null)
            background = backgroundTexture;
        else if (Application.isPlaying && backgroundTextureProvider != null)
        {
            var provider = backgroundTextureProvider as IBackgroundTextureProvider;
            Debug.Assert(provider != null, "BackgroundTextureProvider needs to be an IBackgroundTextureProvider");
            background = provider.GetBackgroundTexture();
        }
        material.SetTexture("_BackgroundTex", background);

        Graphics.Blit(source, destination, material);
    }

    public interface IBackgroundTextureProvider
    {
        Texture GetBackgroundTexture();
    }
}

然后将组件的shader属性链接到下面的shader

Shader "MrPMorris/Universe sub section"
{
    Properties
    {
        _MainTex ("-", 2D) = ""{}
        _CenterOfUniverse("Center of universe", VECTOR) = (0, 0, 0)
        _UniverseRadius("Radius of the universe", float) = 2
        _FeatheringRadius("Additional size to feather out edges of universe", float) = 1
        _ChromaKey("Color in scene to render transparent", COLOR) = (0, 1, 0, 0.618)
        _ClipBelowGround("1 = don't render below universe center, other = render it", INT) = 1
        _BackgroundTex("Background texture", 2D) = ""{}
    }

    CGINCLUDE

    #include "UnityCG.cginc"

    sampler2D _MainTex;
    sampler2D _BackgroundTex;
    half3 _CenterOfUniverse;
    float _UniverseRadius;
    float _FeatheringRadius;
    half4 _ChromaKey;
    int _ClipBelowGround;

    sampler2D_float _CameraDepthTexture;
    float4x4 _InverseView;

    fixed4 frag (v2f_img i) : SV_Target
    {
        const float2 p11_22 = float2(unity_CameraProjection._11, unity_CameraProjection._22);
        const float2 p13_31 = float2(unity_CameraProjection._13, unity_CameraProjection._23);
        const float isOrtho = unity_OrthoParams.w;
        const float near = _ProjectionParams.y;
        const float far = _ProjectionParams.z;

        half2 upsideDownUV = half2(i.uv.x, i.uv.y);
#if UNITY_UV_STARTS_AT_TOP
        upsideDownUV.y = 1 - upsideDownUV.y;
#endif

        float d = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, upsideDownUV);
#if defined(UNITY_REVERSED_Z)
        d = 1 - d;
#endif
        float zOrtho = lerp(near, far, d);
        float zPers = near * far / lerp(far, near, d);
        float vz = lerp(zPers, zOrtho, isOrtho);

        float3 vpos = float3((upsideDownUV * 2 - 1 - p13_31) / p11_22 * lerp(vz, 1, isOrtho), -vz);
        float4 wpos = mul(_InverseView, float4(vpos, 1));

        half4 source = tex2D(_MainTex, i.uv);
        bool forceBackground =
            (_ClipBelowGround == 1 && wpos.y < _CenterOfUniverse.y)
            || (source.r == _ChromaKey.r && source.g == _ChromaKey.g && source.b == _ChromaKey.b && source.a == _ChromaKey.a);

        if (forceBackground)
            return tex2D(_BackgroundTex, upsideDownUV);

        float dist = distance(float4(_CenterOfUniverse, 0), wpos);
        if (dist <= _UniverseRadius)
            return source;

        half4 backgroundPixel = tex2D(_BackgroundTex, upsideDownUV);
        if (dist <= _UniverseRadius + _FeatheringRadius)
        {
            float featherDistance = dist - _UniverseRadius;
            float opacity = (featherDistance / _FeatheringRadius);
            return lerp(source, backgroundPixel, opacity);

        }
        return backgroundPixel;
    }

    ENDCG

    SubShader
    {
        Cull Off ZWrite Off ZTest Always
        Pass
        {
            CGPROGRAM
            #pragma vertex vert_img
            #pragma fragment frag
            ENDCG
        }
    }
}

如果您希望使用网络摄像头图像填充背景,您也可以添加此组件并在 backgroundTextureProvider 属性中引用它。

using UnityEngine;

public class WebCamBackgroundTextureProvider : MonoBehaviour, UniverseSubSection.IBackgroundTextureProvider
{
    WebCamTexture texture;

    public Texture GetBackgroundTexture()
    {
        return texture;
    }

    // Use this for initialization
    void Start()
    {
        if (WebCamTexture.devices.Length > 0)
        {
            texture = new WebCamTexture(WebCamTexture.devices[0].name);
            texture.Play();
        }
    }

    private void OnDestroy()
    {
        if (texture != null)
            texture.Stop();
    }
}

【讨论】:

    猜你喜欢
    • 2021-11-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-16
    • 1970-01-01
    • 2022-08-08
    • 1970-01-01
    相关资源
    最近更新 更多