2015-09-26 73 views
1

我已經開始了一個團結項目,一個滾球遊戲。請記住,我是新手,所以詳細的解釋會有幫助。無論如何,我決定現場看起來不太好,並決定在C#中添加一個光線跟蹤腳本。我是從這個網站上,http://laht.info/ray-tracing-in-unity/在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,POS的Vector3,正常的Vector3)(在資產/腳本/ RayTracer.cs (在資產/腳本/ RayTracer.cs中:102) RayTracer.TraceRay(Ray ray,Color color,Int32 recursiveLevel)(在Assets/Scripts/RayTracer.cs中:102) RayTracer.TraceLight(.RayTracerObject rto,Vector3 viewVector,Vector3 pos,Vector3 normal) /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; 
} 

那麼,這是否將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); 

在這裏我們可以看到,它沒有beeing檢查了GetComponent<RayTracerObject>()調用返回的實際RayTracerObject腳本,而不是空。也許他們希望場景中的每個對象都擁有這個腳本。無論如何,在轉讓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 
      } 

快速調試。

+0

我該如何解決這個問題!= null check?我非常抱歉,但我對這一切都很陌生。會像'if((Physics.Raycast(ray,out hit,maxDist))!= null){object is null}'工作嗎?或者我會在RayTracerObject.cs腳本中執行此操作? –

+0

我已經編輯了答案。 –