繁体   English   中英

Unity错误C#中的光线追踪

[英]Raytracing in Unity error C#

我已经开始一个统一的项目,一个滚球游戏。 请记住,我是新手,因此详细的说明将非常有帮助。 无论如何,我认为场景看起来不太好,并决定在C#中添加光线跟踪脚本。 我从此网站http://laht.info/ray-tracing-in-unity/获得

这是附加在MainCamera上的代码

using UnityEngine;
using System.Collections;

public class RayTracer : MonoBehaviour
{

    public Color backgroundColor = Color.black;
    public float RenderResolution = 1f;
    public float maxDist = 100f;
    public int maxRecursion = 4;


    private Light[] lights;
    private Texture2D renderTexture;

    void Awake()
    {
        renderTexture = new Texture2D((int)(Screen.width * RenderResolution), (int)(Screen.height * RenderResolution));
        lights = FindObjectsOfType(typeof(Light)) as Light[];
    }

    void Start()
    {
        RayTrace();
    }

    void OnGUI()
    {
        GUI.DrawTexture(new Rect(0, 0, Screen.width, Screen.height), renderTexture);
    }

    void RayTrace()
    {
        for (int x = 0; x < renderTexture.width; x++)
        {
            for (int y = 0; y < renderTexture.height; y++)
            {

                Color color = Color.black;
                Ray ray = GetComponent<Camera>().ScreenPointToRay(new Vector3(x / RenderResolution, y / RenderResolution, 0));

                renderTexture.SetPixel(x, y, TraceRay(ray, color, 0));
            }
        }

        renderTexture.Apply();
    }

    Color TraceRay(Ray ray, Color color, int recursiveLevel)
    {

        if (recursiveLevel < maxRecursion)
        {
            RaycastHit hit;
            if (Physics.Raycast(ray, out hit, maxDist))
            {
                Vector3 viewVector = ray.direction;
                Vector3 pos = hit.point + hit.normal * 0.0001f;
                Vector3 normal = hit.normal;

                RayTracerObject rto = hit.collider.gameObject.GetComponent<RayTracerObject>();

                Material mat = hit.collider.GetComponent<Renderer>().material;
                if (mat.mainTexture)
                {
                    color += (mat.mainTexture as Texture2D).GetPixelBilinear(hit.textureCoord.x, hit.textureCoord.y);
                }
                else
                {
                    color += mat.color;
                }

                color *= TraceLight(rto, viewVector, pos, normal);

                if (rto.reflectiveCoeff > 0)
                {
                    float reflet = 2.0f * Vector3.Dot(viewVector, normal);
                    Ray newRay = new Ray(pos, viewVector - reflet * normal);
                    color += rto.reflectiveCoeff * TraceRay(newRay, color, recursiveLevel + 1);
                }

                if (rto.transparentCoeff > 0)
                {
                    Ray newRay = new Ray(hit.point - hit.normal * 0.0001f, viewVector);
                    color += rto.transparentCoeff * TraceRay(newRay, color, recursiveLevel + 1);
                }
            }
        }

        return color;

    }

    Color TraceLight(RayTracerObject rto, Vector3 viewVector, Vector3 pos, Vector3 normal)
    {
        Color c = RenderSettings.ambientLight;

        foreach (Light light in lights)
        {
            if (light.enabled)
            {
                c += LightTrace(rto, light, viewVector, pos, normal);
            }
        }
        return c;
    }

    Color LightTrace(RayTracerObject rto, Light light, Vector3 viewVector, Vector3 pos, Vector3 normal)
    {


        float dot, distance, contribution;
        Vector3 direction;
        switch (light.type)
        {
            case LightType.Directional:
                contribution = 0;
                direction = -light.transform.forward;
                dot = Vector3.Dot(direction, normal);
                if (dot > 0)
                {
                    if (Physics.Raycast(pos, direction, maxDist))
                    {
                        return Color.black;
                    }

                    if (rto.lambertCoeff > 0)
                    {
                        contribution += dot * rto.lambertCoeff;
                    }
                    if (rto.reflectiveCoeff > 0)
                    {
                        if (rto.phongCoeff > 0)
                        {
                            float reflet = 2.0f * Vector3.Dot(viewVector, normal);
                            Vector3 phongDir = viewVector - reflet * normal;
                            float phongTerm = max(Vector3.Dot(phongDir, viewVector), 0.0f);
                            phongTerm = rto.reflectiveCoeff * Mathf.Pow(phongTerm, rto.phongPower) * rto.phongCoeff;

                            contribution += phongTerm;
                        }
                        if (rto.blinnPhongCoeff > 0)
                        {
                            Vector3 blinnDir = -light.transform.forward - viewVector;
                            float temp = Mathf.Sqrt(Vector3.Dot(blinnDir, blinnDir));
                            if (temp != 0.0f)
                            {
                                blinnDir = (1.0f / temp) * blinnDir;
                                float blinnTerm = max(Vector3.Dot(blinnDir, normal), 0.0f);
                                blinnTerm = rto.reflectiveCoeff * Mathf.Pow(blinnTerm, rto.blinnPhongPower) * rto.blinnPhongCoeff;

                                contribution += blinnTerm;
                            }
                        }
                    }
                }
                return light.color * light.intensity * contribution;
            case LightType.Point:
                contribution = 0;
                direction = (light.transform.position - pos).normalized;
                dot = Vector3.Dot(normal, direction);
                distance = Vector3.Distance(pos, light.transform.position);
                if ((distance < light.range) && (dot > 0))
                {
                    if (Physics.Raycast(pos, direction, distance))
                    {
                        return Color.black;
                    }

                    if (rto.lambertCoeff > 0)
                    {
                        contribution += dot * rto.lambertCoeff;
                    }
                    if (rto.reflectiveCoeff > 0)
                    {
                        if (rto.phongCoeff > 0)
                        {
                            float reflet = 2.0f * Vector3.Dot(viewVector, normal);
                            Vector3 phongDir = viewVector - reflet * normal;
                            float phongTerm = max(Vector3.Dot(phongDir, viewVector), 0.0f);
                            phongTerm = rto.reflectiveCoeff * Mathf.Pow(phongTerm, rto.phongPower) * rto.phongCoeff;

                            contribution += phongTerm;
                        }
                        if (rto.blinnPhongCoeff > 0)
                        {
                            Vector3 blinnDir = -light.transform.forward - viewVector;
                            float temp = Mathf.Sqrt(Vector3.Dot(blinnDir, blinnDir));
                            if (temp != 0.0f)
                            {
                                blinnDir = (1.0f / temp) * blinnDir;
                                float blinnTerm = max(Vector3.Dot(blinnDir, normal), 0.0f);
                                blinnTerm = rto.reflectiveCoeff * Mathf.Pow(blinnTerm, rto.blinnPhongPower) * rto.blinnPhongCoeff;

                                contribution += blinnTerm;
                            }
                        }
                    }
                }
                if (contribution == 0)
                {
                    return Color.black;
                }
                return light.color * light.intensity * contribution;
            case LightType.Spot:
                contribution = 0;
                direction = (light.transform.position - pos).normalized;
                dot = Vector3.Dot(normal, direction);
                distance = Vector3.Distance(pos, light.transform.position);
                if (distance < light.range && dot > 0)
                {
                    float dot2 = Vector3.Dot(-light.transform.forward, direction);
                    if (dot2 > (1 - light.spotAngle / 180))
                    {
                        if (Physics.Raycast(pos, direction, distance))
                        {
                            return Color.black;
                        }
                        if (rto.lambertCoeff > 0)
                        {
                            contribution += dot * rto.lambertCoeff;
                        }
                        if (rto.reflectiveCoeff > 0)
                        {
                            if (rto.phongCoeff > 0)
                            {
                                float reflet = 2.0f * Vector3.Dot(viewVector, normal);
                                Vector3 phongDir = viewVector - reflet * normal;
                                float phongTerm = max(Vector3.Dot(phongDir, viewVector), 0.0f);
                                phongTerm = rto.reflectiveCoeff * Mathf.Pow(phongTerm, rto.phongPower) * rto.phongCoeff;

                                contribution += phongTerm;
                            }
                            if (rto.blinnPhongCoeff > 0)
                            {
                                Vector3 blinnDir = -light.transform.forward - viewVector;
                                float temp = Mathf.Sqrt(Vector3.Dot(blinnDir, blinnDir));
                                if (temp != 0.0f)
                                {
                                    blinnDir = (1.0f / temp) * blinnDir;
                                    float blinnTerm = max(Vector3.Dot(blinnDir, normal), 0.0f);
                                    blinnTerm = rto.reflectiveCoeff * Mathf.Pow(blinnTerm, rto.blinnPhongPower) * rto.blinnPhongCoeff;

                                    contribution += blinnTerm;
                                }
                            }
                        }
                    }
                }
                if (contribution == 0)
                {
                    return Color.black;
                }
                return light.color * light.intensity * contribution;
        }
        return Color.black;
    }

    float max(float x0, float x1)
    {
        return x0 > x1 ? x0 : x1;
    }
}

这是附加到场景中对象的代码,例如平面或球体

using UnityEngine;
using System.Collections;

public class RayTracerObject : MonoBehaviour
{

    public float lambertCoeff = 1f;

    public float reflectiveCoeff = 0f;

    public float phongCoeff = 1f;
    public float phongPower = 2f;

    public float blinnPhongCoeff = 1f;
    public float blinnPhongPower = 2f;

    public float transparentCoeff = 0f;


    public Color baseColor = Color.gray;

    void Awake()
    {
        if (!GetComponent<Renderer>().material.mainTexture)
        {
            GetComponent<Renderer>().material.color = baseColor;
        }
    }
}

无论如何,当我尝试运行程序时,会出现此错误。

NullReferenceException:对象引用未设置为对象RayTracer.LightTrace(.RayTracerObject rto,UnityEngine.Light light,Vector3 viewVector,Vector3 pos,Vector3普通)的实例(在Assets / Scripts / RayTracer.cs:127处)RayTracer.TraceLight( .RayTracerObject rto,Vector3 viewVector,Vector3 pos,Vector3普通)(在Assets / Scripts / RayTracer.cs:102)RayTracer.TraceRay(射线,颜色,Int32 recursiveLevel)(在Assets / Scripts / RayTracer.cs:73) RayTracer.RayTrace()(在Assets / Scripts / RayTracer.cs:42处)

如果您能弄清楚这一点,则发布代码会很有帮助。 谢谢。

发布发生错误的行可能会有所帮助。 无论如何,第127行是LightTrace()函数中的这一行。

if (rto.lambertCoeff > 0)
{
    contribution += dot * rto.lambertCoeff;
}

因此, rto变量必须为null。 我不知道为什么它为null。 LightTrace()此处调用LightTrace()函数:

Color TraceLight(RayTracerObject rto, Vector3 viewVector, Vector3 pos, Vector3 normal)
{
    Color c = RenderSettings.ambientLight;

    foreach (Light light in lights)
    {
        if (light.enabled)
        {
            c += LightTrace(rto, light, viewVector, pos, normal);
        }
    }
    return c;
}

那么, TraceLight函数从TraceLight获取rto对象? 从这里开始:(这在TraceRay函数中)

RayTracerObject rto = hit.collider.gameObject.GetComponent<RayTracerObject>();

Material mat = hit.collider.GetComponent<Renderer>().material;
if (mat.mainTexture)
{
    color += (mat.mainTexture as Texture2D).GetPixelBilinear(hit.textureCoord.x, hit.textureCoord.y);
}
else
{
    color += mat.color;
}

color *= TraceLight(rto, viewVector, pos, normal);

在这里我们可以看到,没有检查GetComponent<RayTracerObject>()调用是否返回了实际的RayTracerObject脚本,而不是null。 也许他们希望场景中的每个对象都具有此脚本。 无论如何,在分配给rto变量后立即放置!= null检查,您应该会很好。 另外,您可以继续进行进一步调试,例如Debug.Log()以其命中的确切对象没有RayTracerObject

编辑:因此,您应该通过查看Physics.Raycast()命中的没有RayTracerObject脚本的内容来开始调试场景。 使用该脚本时,应确保绝对可以用RayTracerObject命中的每个对象上都有RayTracerObject脚本。 TraceRay()函数中,添加一些调试。

Color TraceRay(Ray ray, Color color, int recursiveLevel)
{

    if (recursiveLevel < maxRecursion)
    {
        RaycastHit hit;
        if (Physics.Raycast(ray, out hit, maxDist))
        {
            Vector3 viewVector = ray.direction;
            Vector3 pos = hit.point + hit.normal * 0.0001f;
            Vector3 normal = hit.normal;

            RayTracerObject rto = hit.collider.gameObject.GetComponent<RayTracerObject>();
            //Does the object we hit have that script? 
            if(rto == null) 
            {
                 var GO = hit.collider.gameObject;
                 Debug.Log("Raycast hit failure! On " + GO.name + " position " + GO.transform.position.ToString());
                 return color; //exit out
            }

调试愉快。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM