如何仅在特定点的半径范围内渲染对象?

时间:2017-03-15 18:51:52

标签: unity3d mobile

我希望我的相机只渲染特定点半径范围内的物体,这一点与摄像机的位置无关,所以我应该可以绕着我世界的这个部分飞行。该中心点将作为游戏的一部分而改变。

我也希望边缘能够混合而不是立即结束(它将成为移动增强现实游戏)。

是否有现成的技术?可能是着色器还是什么?

1 个答案:

答案 0 :(得分:0)

我玩弄了这个问题,想出了一些东西。我刚刚注意到这个问题仍然在这里,所以我想我会分享解决方案。

将以下脚本添加到相机

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 "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();
    }
}