2015-09-26 3 views
1

Я начал проект в единстве, игра Roll ball. Имейте в виду, я очень новичок, поэтому подробные объяснения действительно помогут. Во всяком случае, я решил, что сцена выглядит не очень хорошо, и решил добавить скрипт raytracing на C#. Я получил его с этого сайта, http://laht.info/ray-tracing-in-unity/Ошибка Raytracing в Unity C#

Вот код, который прилагается к 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 света, Vector3 viewVector, Vector3 поз, Vector3 нормальный) (на активы/скрипты/RayTracer.cs : 127) RayTracer.TraceLight (.RayTracerObject rto, Vector3 viewVector, Vector3 pos, Vector3 normal) (в Assets/Scripts/RayTracer.cs: 102) RayTracer.TraceRay (луч Ray, цветной цвет, Int32 recursiveLevel) (при активах /Scripts/RayTracer.cs:73) RayTracer.RayTrace() (на активы/скрипты/RayTracer.cs: 42)

Если вы можете понять это, размещение кода поможет много. Спасибо.

ответ

0

Публикация строки, в которой произошла ошибка, была бы полезной. В любом случае, строка 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; 
} 

Так где же функция TraceLightrto получить объект из? Отсюда: (Это в пределах функции 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, и вам должно быть хорошо идти. Кроме того, вы можете продолжить его отладку, например, например. Debug.Log() Какой точный объект попал, у которого не было RayTracerObject.

EDIT: Таким образом, вы должны начать отладку сцены, принимая взглянуть на то, Physics.Raycast() хит, который не имел RayTracerObject скрипт на нем. При использовании этого скрипта вы должны убедиться, что absolutley каждого объекта, который может быть поражен raycast, имеет на нем скрипт 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 
      } 

Счастливая отладка.

+0

Как бы я обошел это? = Null проверить? Мне очень жаль, но я новичок во всем этом. Было бы что-то вроде: if ((Physics.Raycast (ray, out hit, maxDist))! = Null) {object is null} 'Work? Или я сделаю это в сценарии RayTracerObject.cs? –

+0

Я отредактировал ответ. –