2016-02-06 31 views
7

Tôi hiện đang cố gắng chuyển vùng đổ bóng shadertoy.com (Atmospheric Scattering Sample, bản trình diễn tương tác với mã) thành Unity. Trình đổ bóng được viết bằng GLSL và tôi phải khởi động trình chỉnh sửa với C:\Program Files\Unity\Editor>Unity.exe -force-opengl để làm cho trình đổ bóng hiển thị (nếu không, lỗi "Trình đổ bóng này không thể chạy trên GPU này"), nhưng đó không phải là vấn đề ngay bây giờ. Vấn đề là chuyển porter đó sang Unity.Sự cố khi chuyển đổ bóng đổ bóng GLSL sang thống nhất

Các chức năng tán xạ vv đều giống nhau và "runnable" trong trình đổ bóng được chuyển của tôi, điều duy nhất là chức năng mainImage() quản lý máy ảnh, hướng ánh sáng và hướng tia. Điều này đã được ofcourse thay đổi vị trí máy ảnh của Unity Unity, hướng nhìn và nguồn ánh sáng và hướng dẫn được sử dụng.

Chức năng chính của cái nhìn ban đầu như thế này:

void mainImage(out vec4 fragColor, in vec2 fragCoord) 
{ 
    // default ray dir 
    vec3 dir = ray_dir(45.0, iResolution.xy, fragCoord.xy); 

    // default ray origin 
    vec3 eye = vec3(0.0, 0.0, 2.4); 

    // rotate camera 
    mat3 rot = rot3xy(vec2(0.0, iGlobalTime * 0.5)); 
    dir = rot * dir; 
    eye = rot * eye; 

    // sun light dir 
    vec3 l = vec3(0, 0, 1); 

    vec2 e = ray_vs_sphere(eye, dir, R); 
    if (e.x > e.y) { 
     discard; 
    } 

    vec2 f = ray_vs_sphere(eye, dir, R_INNER); 
    e.y = min(e.y, f.x); 

    vec3 I = in_scatter(eye, dir, e, l); 

    fragColor = vec4(I, 1.0); 
} 

Tôi đã đọc qua tài liệu của chức năng đó và làm thế nào đó là nghĩa vụ làm việc tại https://www.shadertoy.com/howto.

Trình tạo bóng hình ảnh triển khai hàm mainImage() để tạo ra hình ảnh thủ tục bằng cách tính màu cho mỗi pixel. Chức năng này được dự kiến ​​sẽ được gọi một lần cho mỗi pixel, và nó là khả năng đáp ứng của ứng dụng máy chủ để cung cấp đầu vào phù hợp với và nhận màu đầu ra từ đó và gán nó cho pixel màn hình. Nguyên mẫu là:

void mainImage (ra vec4 fragMàu, trong vec2 fragCoord);

trong đó fragCoord chứa toạ độ pixel mà bóng đổ cần tính màu. Các tọa độ nằm trong các đơn vị pixel, khác nhau, từ 0,5 đến độ phân giải 0,5, trên bề mặt hiển thị, ở đó độ phân giải được chuyển đến trình đổ bóng thông qua đồng phục iResolution (xem bên dưới).

Màu kết quả được thu thập bằng màu sắc dưới dạng bốn thành phần vectơ, phần cuối cùng trong số đó bị máy khách bỏ qua. Kết quả là được thu thập dưới dạng biến "ngoài" trong hình ảnh của việc bổ sung nhiều mục tiêu kết xuất sau này.

Vì vậy, trong hàm đó, có tham chiếu đến iGlobalTime để làm cho máy ảnh xoay theo thời gian và tham chiếu đến độ phân giải iResolution. Tôi đã nhúng trình đổ bóng vào bộ đổ bóng Unity và cố gắng sửa chữa và kết nối dây chuyền dir, eyel để nó hoạt động với Unity, nhưng tôi hoàn toàn bị kẹt. Tôi nhận được một số loại hình trông "có liên quan" đến đổ bóng ban đầu: (Top là bản gốc, buttom trạng thái thống nhất hiện nay)

unity shader comparison

Tôi không phải là một chuyên nghiệp đổ bóng, tôi chỉ biết một số điều cơ bản của OpenGL, nhưng phần lớn, tôi viết logic trò chơi trong C#, vì vậy tất cả những gì tôi có thể làm là xem xét các ví dụ khác về bóng và xem cách tôi có thể lấy dữ liệu về máy ảnh, nguồn sáng vv trong mã này, nhưng bạn có thể thấy, không có gì hoạt động, thực sự.

Tôi đã sao chép mã skelton cho trình đổ bóng từ https://en.wikibooks.org/wiki/GLSL_Programming/Unity/Specular_Highlights và một số vectơ từ http://forum.unity3d.com/threads/glsl-shader.39629/.

Tôi hy vọng một người nào đó có thể chỉ cho tôi một số hướng về cách khắc phục trình đổ bóng này/chính xác chuyển nó thành sự hiệp nhất. Dưới đây là mã shader hiện tại, tất cả những gì bạn phải làm để tạo lại nó là tạo một shader mới trong một dự án trống, sao chép mã bên trong, tạo một tài liệu mới, gán shader cho tài liệu đó, sau đó thêm một hình cầu và thêm tài liệu đó trên đó và thêm ánh sáng hướng.

Shader "Unlit/AtmoFragShader" { 
    Properties{ 
     _MainTex("Base (RGB)", 2D) = "white" {} 
    _LC("LC", Color) = (1,0,0,0) /* stuff from the testing shader, now really used */ 
     _LP("LP", Vector) = (1,1,1,1) 
    } 

     SubShader{ 
     Tags{ "Queue" = "Geometry" } //Is this even the right queue? 

     Pass{ 
     //Tags{ "LightMode" = "ForwardBase" } 
     GLSLPROGRAM 

    /* begin port by copying in the constants */ 
    // math const 
    const float PI = 3.14159265359; 
    const float DEG_TO_RAD = PI/180.0; 
    const float MAX = 10000.0; 

    // scatter const 
    const float K_R = 0.166; 
    const float K_M = 0.0025; 
    const float E = 14.3;      // light intensity 
    const vec3 C_R = vec3(0.3, 0.7, 1.0); // 1/wavelength^4 
    const float G_M = -0.85;     // Mie g 

    const float R = 1.0; /* this is the radius of the spehere? this should be set from the geometry or something.. */ 
    const float R_INNER = 0.7; 
    const float SCALE_H = 4.0/(R - R_INNER); 
    const float SCALE_L = 1.0/(R - R_INNER); 

    const int NUM_OUT_SCATTER = 10; 
    const float FNUM_OUT_SCATTER = 10.0; 

    const int NUM_IN_SCATTER = 10; 
    const float FNUM_IN_SCATTER = 10.0; 

    /* begin functions. These are out of the defines because they should be accesible to anyone. */ 

    // angle : pitch, yaw 
    mat3 rot3xy(vec2 angle) { 
     vec2 c = cos(angle); 
     vec2 s = sin(angle); 

     return mat3(
      c.y, 0.0, -s.y, 
      s.y * s.x, c.x, c.y * s.x, 
      s.y * c.x, -s.x, c.y * c.x 
      ); 
    } 

    // ray direction 
    vec3 ray_dir(float fov, vec2 size, vec2 pos) { 
     vec2 xy = pos - size * 0.5; 

     float cot_half_fov = tan((90.0 - fov * 0.5) * DEG_TO_RAD); 
     float z = size.y * 0.5 * cot_half_fov; 

     return normalize(vec3(xy, -z)); 
    } 

    // ray intersects sphere 
    // e = -b +/- sqrt(b^2 - c) 
    vec2 ray_vs_sphere(vec3 p, vec3 dir, float r) { 
     float b = dot(p, dir); 
     float c = dot(p, p) - r * r; 

     float d = b * b - c; 
     if (d < 0.0) { 
      return vec2(MAX, -MAX); 
     } 
     d = sqrt(d); 

     return vec2(-b - d, -b + d); 
    } 

    // Mie 
    // g : (-0.75, -0.999) 
    //  3 * (1 - g^2)    1 + c^2 
    // F = ----------------- * ------------------------------- 
    //  2 * (2 + g^2)  (1 + g^2 - 2 * g * c)^(3/2) 
    float phase_mie(float g, float c, float cc) { 
     float gg = g * g; 

     float a = (1.0 - gg) * (1.0 + cc); 

     float b = 1.0 + gg - 2.0 * g * c; 
     b *= sqrt(b); 
     b *= 2.0 + gg; 

     return 1.5 * a/b; 
    } 

    // Reyleigh 
    // g : 0 
    // F = 3/4 * (1 + c^2) 
    float phase_reyleigh(float cc) { 
     return 0.75 * (1.0 + cc); 
    } 

    float density(vec3 p) { 
     return exp(-(length(p) - R_INNER) * SCALE_H); 
    } 

    float optic(vec3 p, vec3 q) { 
     vec3 step = (q - p)/FNUM_OUT_SCATTER; 
     vec3 v = p + step * 0.5; 

     float sum = 0.0; 
     for (int i = 0; i < NUM_OUT_SCATTER; i++) { 
      sum += density(v); 
      v += step; 
     } 
     sum *= length(step) * SCALE_L; 

     return sum; 
    } 

    vec3 in_scatter(vec3 o, vec3 dir, vec2 e, vec3 l) { 
     float len = (e.y - e.x)/FNUM_IN_SCATTER; 
     vec3 step = dir * len; 
     vec3 p = o + dir * e.x; 
     vec3 v = p + dir * (len * 0.5); 

     vec3 sum = vec3(0.0); 
     for (int i = 0; i < NUM_IN_SCATTER; i++) { 
      vec2 f = ray_vs_sphere(v, l, R); 
      vec3 u = v + l * f.y; 

      float n = (optic(p, v) + optic(v, u)) * (PI * 4.0); 

      sum += density(v) * exp(-n * (K_R * C_R + K_M)); 

      v += step; 
     } 
     sum *= len * SCALE_L; 

     float c = dot(dir, -l); 
     float cc = c * c; 

     return sum * (K_R * C_R * phase_reyleigh(cc) + K_M * phase_mie(G_M, c, cc)) * E; 
    } 
    /* end functions */ 
    /* vertex shader begins here*/ 
#ifdef VERTEX 
    const float SpecularContribution = 0.3; 
    const float DiffuseContribution = 1.0 - SpecularContribution; 

    uniform vec4 _LP; 
    varying vec2 TextureCoordinate; 
    varying float LightIntensity; 
    varying vec4 someOutput; 

    /* transient stuff */ 
    varying vec3 eyeOutput; 
    varying vec3 dirOutput; 
    varying vec3 lOutput; 
    varying vec2 eOutput; 

    /* lighting stuff */ 
    // i.e. one could #include "UnityCG.glslinc" 
    uniform vec3 _WorldSpaceCameraPos; 
    // camera position in world space 
    uniform mat4 _Object2World; // model matrix 
    uniform mat4 _World2Object; // inverse model matrix 
    uniform vec4 _WorldSpaceLightPos0; 
    // direction to or position of light source 
    uniform vec4 _LightColor0; 
    // color of light source (from "Lighting.cginc") 


    void main() 
    { 
     /* code from that example shader */ 
     gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; 

     vec3 ecPosition = vec3(gl_ModelViewMatrix * gl_Vertex); 
     vec3 tnorm = normalize(gl_NormalMatrix * gl_Normal); 
     vec3 lightVec = normalize(_LP.xyz - ecPosition); 

     vec3 reflectVec = reflect(-lightVec, tnorm); 
     vec3 viewVec = normalize(-ecPosition); 

     /* copied from https://en.wikibooks.org/wiki/GLSL_Programming/Unity/Specular_Highlights for testing stuff */ 
     //I have no idea what I'm doing, but hopefully this computes some vectors which I need 
     mat4 modelMatrix = _Object2World; 
     mat4 modelMatrixInverse = _World2Object; // unity_Scale.w 
               // is unnecessary because we normalize vectors 

     vec3 normalDirection = normalize(vec3(
      vec4(gl_Normal, 0.0) * modelMatrixInverse)); 
     vec3 viewDirection = normalize(vec3(
      vec4(_WorldSpaceCameraPos, 1.0) 
      - modelMatrix * gl_Vertex)); 
     vec3 lightDirection; 
     float attenuation; 

     if (0.0 == _WorldSpaceLightPos0.w) // directional light? 
     { 
      attenuation = 1.0; // no attenuation 
      lightDirection = normalize(vec3(_WorldSpaceLightPos0)); 
     } 
     else // point or spot light 
     { 
      vec3 vertexToLightSource = vec3(_WorldSpaceLightPos0 
       - modelMatrix * gl_Vertex); 
      float distance = length(vertexToLightSource); 
      attenuation = 1.0/distance; // linear attenuation 
      lightDirection = normalize(vertexToLightSource); 
     } 
     /* test port */ 
     // default ray dir 
     //That's the direction of the camera here? 
     vec3 dir = viewDirection; //normalDirection;//viewDirection;// tnorm;//lightVec;//lightDirection;//normalDirection; //lightVec;//tnorm;//ray_dir(45.0, iResolution.xy, fragCoord.xy); 

     // default ray origin 
     //I think they mean the position of the camera here? 
     vec3 eye = vec3(_WorldSpaceCameraPos); //vec3(_WorldSpaceLightPos0); //// vec3(0.0, 0.0, 0.0); //_WorldSpaceCameraPos;//ecPosition; //vec3(0.0, 0.0, 2.4); 

     // rotate camera not needed, remove it 

     // sun light dir 
     //I think they mean the direciton of our directional light? 
     vec3 l = lightDirection;//_LightColor0.xyz; //lightDirection; //normalDirection;//normalize(vec3(_WorldSpaceLightPos0));//lightVec;// vec3(0, 0, 1); 

     /* this computes the intersection of the ray and the sphere.. is this really needed?*/ 
     vec2 e = ray_vs_sphere(eye, dir, R); 
     /* copy stuff sothat we can use it on the fragment shader, "discard" is only allowed in fragment shader, 
     so the rest has to be computed in fragment shader */ 
     eOutput = e; 
     eyeOutput = eye; 
     dirOutput = dir; 
     lOutput = dir; 
    } 

#endif 

#ifdef FRAGMENT 

    uniform sampler2D _MainTex; 
    varying vec2 TextureCoordinate; 
    uniform vec4 _LC; 
    varying float LightIntensity; 

    /* transient port */ 
    varying vec3 eyeOutput; 
    varying vec3 dirOutput; 
    varying vec3 lOutput; 
    varying vec2 eOutput; 

    void main() 
    { 
     /* real fragment */ 

     if (eOutput.x > eOutput.y) { 
      //discard; 
     } 

     vec2 f = ray_vs_sphere(eyeOutput, dirOutput, R_INNER); 
     vec2 e = eOutput; 
     e.y = min(e.y, f.x); 

     vec3 I = in_scatter(eyeOutput, dirOutput, eOutput, lOutput); 
     gl_FragColor = vec4(I, 1.0); 

     /*vec4 c2; 
     c2.x = 1.0; 
     c2.y = 1.0; 
     c2.z = 0.0; 
     c2.w = 1.0f; 
     gl_FragColor = c2;*/ 
     //gl_FragColor = c; 
    } 

#endif 

    ENDGLSL 
    } 
    } 
} 

Bất kỳ trợ giúp nào được đánh giá cao, xin lỗi về bài đăng và giải thích dài.

Chỉnh sửa: Tôi vừa phát hiện ra rằng bán kính của quả cầu không có ảnh hưởng đến đồ vật, quả cầu có quy mô 2.0 theo mọi hướng cho kết quả tốt hơn nhiều. Tuy nhiên, hình ảnh vẫn hoàn toàn độc lập với góc nhìn của máy ảnh và bất kỳ đèn nào, đây là hư không gần phiên bản shaderlab.

status2

+1

câu hỏi hay ... – Fattie

+0

@OP Tôi chỉ cần nhảy vào trình đổ bóng. Bạn đã kết thúc giải quyết vấn đề này? – Programmer

+0

@Programmer Đã không làm việc trên nó bao giờ hết - tất cả mọi người có thể cảm thấy tự do để thử và thực hiện các đề xuất trong câu trả lời. –

Trả lời

0

Dường như bạn đang cố gắng hiển thị kết cấu 2D trên hình cầu. Nó có một số cách tiếp cận khác nhau. Đối với những gì bạn đang cố gắng làm, tôi sẽ áp dụng các shader trên một chiếc máy bay vượt qua với hình cầu.

Vì mục đích chung, hãy xem this article cho biết cách chuyển đổi shaderToy thành Unity3D.

Có một số bước mà chúng tôi bao gồm ở đây:

  • Thay iGlobalTime shader đầu vào (“thời gian phát lại đổ bóng trong vài giây”) với _Time.y
  • Thay iResolution.xy (“độ phân giải khung nhìn bằng pixel”) với _ScreenParams.xy
  • Thay thế các loại vec2 với float2, mat2 với float2x2, vv
  • Thay vec3 (1) nhà xây dựng shortcut trong đó tất cả các yếu tố có cùng giá trị với float3 rõ ràng (1,1,1)
  • Thay thế Texture2D bằng Tex2D
  • Thay thế atan (x, y) bằng atan2 (y, x) < - Lưu ý thông số đặt hàng!
  • Thay hỗn hợp() với lerp()
  • Thay thế * = với mul()
  • Remove (thiên vị) tham số thứ ba từ Texture2D tra cứu
  • mainImage (trong vec4 fragColor, trong vec2 fragCoord) là shader mảnh chức năng, tương đương float4 mainImage (float2 fragCoord: SV_POSITION): SV_Target
  • tọa độ UV trong GLSL có 0 ở trên cùng và tăng xuống, trong HLSL 0 ở dưới cùng và tăng lên, vì vậy bạn có thể cần phải sử dụng uv.y = 1 - uv.y tại một số điểm.

thiệu về câu hỏi này:

Tags{ "Queue" = "Geometry" } //Is this even the right queue? 

Queue tham chiếu thứ tự nó sẽ được trả lại, Geometry là một trong những người đầu tiên của, nếu bạn muốn, bạn Shader chạy trên tất cả mọi thứ bạn có thể sử dụng Overlay ví dụ. Chủ đề này là covered here.

  • Bối cảnh - hàng đợi hiển thị này được hiển thị trước mọi người khác. Nó được sử dụng cho skybox và tương tự.
  • Hình học (mặc định) - được sử dụng cho hầu hết các đối tượng.Hình học mờ sử dụng hàng đợi này.
  • AlphaTest - hình học thử nghiệm alpha sử dụng hàng đợi này. Đó là một hàng đợi riêng biệt từ - Hình học một vì hiệu quả hơn khi hiển thị các đối tượng thử nghiệm alpha sau khi tất cả các đối tượng rắn được vẽ.
  • Trong suốt - hàng đợi hiển thị này được hiển thị sau Hình học và AlphaTest, theo thứ tự từ đầu đến trước. Bất kỳ thứ gì được pha trộn alpha (tức là các trình đổ bóng không ghi vào bộ đệm độ sâu) nên đến đây (kính, các hiệu ứng hạt).
  • Lớp phủ - hàng đợi hiển thị này có nghĩa là cho các hiệu ứng lớp phủ. Mọi thứ được hiển thị cuối cùng nên đến đây (ví dụ: pháo sáng ống kính).
Các vấn đề liên quan