Unity中的光线追踪错误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:对象引用未设置为对象的实例光线跟踪。LightTrace(。RayTracerObject rto, UnityEngine。光,Vector3 viewVector, Vector3 pos, Vector3 normal)(在Assets/Scripts/RayTracer.cs:127)光线跟踪。TraceLight(。RayTracerObject rto, Vector3 viewVector, Vector3 pos, Vector3 normal)(在Assets/Scripts/RayTracerObject .cs:102)光线跟踪。TraceRay (Ray Ray, Color Color, Int32 recursivellevel)(在Assets/Scripts/RayTracer.cs:73)光线跟踪。RayTrace () (at Assets/Scripts/RayTrace .cs:42)

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

张贴发生错误的行将会很有帮助。无论如何,第127行是LightTrace()函数中的这一行。

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

因此,rto变量必须为空。我不知道为什么是空的,虽然。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函数从哪里获得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脚本。在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
            }

快乐调试。

最新更新