2016-07-21 107 views
0

我想創建一個像MeshLambertMaterial一樣具有光照的ShaderMaterial。我創建了一個vertex and fragment shader,並在ShaderMaterial中包含了來自THREE.ShaderLib ['lambert'] .uniforms的制服。在three.js中將着色添加到ShaderMaterial

如果我錯了,糾正我,但我相信下一步添加照明將是將MeshLambertMaterial中使用的着色器代碼fragmentvertex與我的自定義着色器代碼合併。

合併頂點着色器會很簡單。但是,在片段着色器中,如何爲meshlambert_frag.glsl中的代碼提供基本顏色(將由我的着色器代碼生成)以應用光照計算?片段着色器可能會是這個樣子:

// my custom shader code before the main function 
// meshlambert_frag.glsl shader code before the main function 
void main { 
    vec4 myBaseColor ... // set by my custom fragment shader code 
    // meshlambert_frag.glsl code in the main function would use myBaseColor as a base 
    // color for the lighting calculations before setting gl_FragColor 
} 

此外,正在複製這種大塊的代碼(從meshlambert着色器),在這種情況下不好的做法?什麼會是更好的解決方案?

+0

有些[ShaderMaterial這裏例](http://blog.2pha.com/experimenting-threejs-shaders-and-shadermaterial)包括一些與[燈](HTTP://blog.2pha。 com/demos/threejs/shaders/single_color_point_lights.html) – 2pha

+0

@ 2pha這些都是一些很好的例子,但是由於MAX_POINT_LIGHTS變量不再是連接的燈光已過期用過的。此外,它只支持點光源,不像支持所有three.js燈光的MeshLambertMaterial。 – epitaque

+0

哦,我只是看了一下目前的MechLambertMaterial,看起來材料比他們用的要複雜一點。 – 2pha

回答

0

將顏色傳遞給MeshLambertMaterial中使用的片段着色器代碼的方法是修改diffuseColor變量。因此,您可以使用diffuseColor.rgb * = aVec3在片段着色器中設置顏色。下面是我的着色器的代碼如下所示:

// vertex 
#define LAMBERT 

varying vec3 vLightFront; 

#ifdef DOUBLE_SIDED 

    varying vec3 vLightBack; 

#endif 

#include <common> 
#include <uv_pars_vertex> 
#include <uv2_pars_vertex> 
#include <envmap_pars_vertex> 
#include <bsdfs> 
#include <lights_pars> 
#include <color_pars_vertex> 
#include <morphtarget_pars_vertex> 
#include <skinning_pars_vertex> 
#include <shadowmap_pars_vertex> 
#include <logdepthbuf_pars_vertex> 
#include <clipping_planes_pars_vertex> 

varying vec3 vertexColor; 
varying vec2 vUv; 
varying vec4 worldPosition; 

void main() { 
    vertexColor = vec3(255, 100, 0); 
    vUv = uv; 
    worldPosition = modelMatrix * vec4(position, 1.0); 

    #include <uv_vertex> 
    #include <uv2_vertex> 
    #include <color_vertex> 

    #include <beginnormal_vertex> 
    #include <morphnormal_vertex> 
    #include <skinbase_vertex> 
    #include <skinnormal_vertex> 
    #include <defaultnormal_vertex> 

    #include <begin_vertex> 
    #include <morphtarget_vertex> 
    #include <skinning_vertex> 
    #include <project_vertex> 
    #include <logdepthbuf_vertex> 
    #include <clipping_planes_vertex> 

    #include <worldpos_vertex> 
    #include <envmap_vertex> 
    #include <lights_lambert_vertex> 
    #include <shadowmap_vertex> 

} 
// fragment 
uniform float time; 
varying vec2 vUv; 

vec4 permute(vec4 x) { 

    return mod(((x * 34.0) + 1.0) * x, 289.0); 

} 

vec4 taylorInvSqrt(vec4 r) { 

    return 1.79284291400159 - 0.85373472095314 * r; 

} 

float snoise(vec3 v) { 

    const vec2 C = vec2(1.0/6.0, 1.0/3.0); 
    const vec4 D = vec4(0.0, 0.5, 1.0, 2.0); 

    // First corner 

    vec3 i = floor(v + dot(v, C.yyy)); 
    vec3 x0 = v - i + dot(i, C.xxx); 

    // Other corners 

    vec3 g = step(x0.yzx, x0.xyz); 
    vec3 l = 1.0 - g; 
    vec3 i1 = min(g.xyz, l.zxy); 
    vec3 i2 = max(g.xyz, l.zxy); 

    vec3 x1 = x0 - i1 + 1.0 * C.xxx; 
    vec3 x2 = x0 - i2 + 2.0 * C.xxx; 
    vec3 x3 = x0 - 1. + 3.0 * C.xxx; 

    // Permutations 

    i = mod(i, 289.0); 
    vec4 p = permute(permute(permute(
      i.z + vec4(0.0, i1.z, i2.z, 1.0)) 
     + i.y + vec4(0.0, i1.y, i2.y, 1.0)) 
     + i.x + vec4(0.0, i1.x, i2.x, 1.0)); 

    // Gradients 
    // (N*N points uniformly over a square, mapped onto an octahedron.) 

    float n_ = 1.0/7.0; // N=7 

    vec3 ns = n_ * D.wyz - D.xzx; 

    vec4 j = p - 49.0 * floor(p * ns.z *ns.z); // mod(p,N*N) 

    vec4 x_ = floor(j * ns.z); 
    vec4 y_ = floor(j - 7.0 * x_); // mod(j,N) 

    vec4 x = x_ *ns.x + ns.yyyy; 
    vec4 y = y_ *ns.x + ns.yyyy; 
    vec4 h = 1.0 - abs(x) - abs(y); 

    vec4 b0 = vec4(x.xy, y.xy); 
    vec4 b1 = vec4(x.zw, y.zw); 


    vec4 s0 = floor(b0) * 2.0 + 1.0; 
    vec4 s1 = floor(b1) * 2.0 + 1.0; 
    vec4 sh = -step(h, vec4(0.0)); 

    vec4 a0 = b0.xzyw + s0.xzyw * sh.xxyy; 
    vec4 a1 = b1.xzyw + s1.xzyw * sh.zzww; 

    vec3 p0 = vec3(a0.xy, h.x); 
    vec3 p1 = vec3(a0.zw, h.y); 
    vec3 p2 = vec3(a1.xy, h.z); 
    vec3 p3 = vec3(a1.zw, h.w); 

    // Normalise gradients 

    vec4 norm = taylorInvSqrt(vec4(dot(p0, p0), dot(p1, p1), dot(p2, p2), dot(p3, p3))); 
    p0 *= norm.x; 
    p1 *= norm.y; 
    p2 *= norm.z; 
    p3 *= norm.w; 

    // Mix final noise value 

    vec4 m = max(0.6 - vec4(dot(x0, x0), dot(x1, x1), dot(x2, x2), dot(x3, x3)), 0.0); 
    m = m * m; 
    return 42.0 * dot(m*m, vec4(dot(p0, x0), dot(p1, x1), 
           dot(p2, x2), dot(p3, x3))); 

} 

varying vec4 worldPosition; 

uniform vec3 diffuse; 
uniform vec3 emissive; 
uniform float opacity; 

varying vec3 vLightFront; 

#ifdef DOUBLE_SIDED 

    varying vec3 vLightBack; 

#endif 

#include <common> 
#include <packing> 
#include <color_pars_fragment> 
#include <uv_pars_fragment> 
#include <uv2_pars_fragment> 
#include <map_pars_fragment> 
#include <alphamap_pars_fragment> 
#include <aomap_pars_fragment> 
#include <lightmap_pars_fragment> 
#include <emissivemap_pars_fragment> 
#include <envmap_pars_fragment> 
#include <bsdfs> 
#include <lights_pars> 
#include <fog_pars_fragment> 
#include <shadowmap_pars_fragment> 
#include <shadowmask_pars_fragment> 
#include <specularmap_pars_fragment> 
#include <logdepthbuf_pars_fragment> 
#include <clipping_planes_pars_fragment> 

float sigmoid(float x) { 
    return x/(1.0 + abs(x)); 
} 

varying vec3 vertexColor; 

void main() { 
    #include <clipping_planes_fragment> 


    vec4 diffuseColor = vec4(diffuse, opacity); 
    ReflectedLight reflectedLight = ReflectedLight(vec3(0.0), vec3(0.0), vec3(0.0), vec3(0.0)); 
    vec3 totalEmissiveRadiance = emissive; 

    #include <logdepthbuf_fragment> 
    #include <map_fragment> 
    if(worldPosition.y > 300.0) { //snow 
     float noise = snoise(vec3(worldPosition.x * 4.0, worldPosition.y * 4.0, worldPosition.z * 4.0))/20.0; 
     diffuseColor.rgb *= vec3(1.0 - noise, 1.0 - noise, 1.0 - noise); 
    } 
    else if (worldPosition.y > 100.0) { // dirt 
     float scale = 5.0; 
     float effectscale = 0.2; 
     float noise = (snoise(vec3(worldPosition.x * scale, worldPosition.y * scale, worldPosition.z * scale)) - 0.2) * effectscale; 
     noise = sigmoid(noise); 
     diffuseColor.rgb *= vec3(0.54 + noise, 0.27 + noise, 0.07 + noise); 
    } 
    else { // grass 
     float scale = 4.0; 
     float effectscale = 0.08; 
     float noise = (snoise(vec3(worldPosition.x * scale, worldPosition.y * scale, worldPosition.z * scale)) - 0.2) * effectscale; 
     diffuseColor.rgb *= vec3(0, 0.48 + noise, 0.05 + noise); 

    } 

    #include <color_fragment> 
    #include <alphamap_fragment> 
    #include <alphatest_fragment> 
    #include <specularmap_fragment> 
    #include <emissivemap_fragment> 

    // accumulation 
    reflectedLight.indirectDiffuse = getAmbientLightIrradiance(ambientLightColor); 

    #include <lightmap_fragment> 

    reflectedLight.indirectDiffuse *= BRDF_Diffuse_Lambert(diffuseColor.rgb); 

    #ifdef DOUBLE_SIDED 

     reflectedLight.directDiffuse = (gl_FrontFacing) ? vLightFront : vLightBack; 

    #else 

     reflectedLight.directDiffuse = vLightFront; 

    #endif 

    reflectedLight.directDiffuse *= BRDF_Diffuse_Lambert(diffuseColor.rgb) * getShadowMask(); 

    // modulation 
    #include <aomap_fragment> 

    vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance; 

    #include <normal_flip> 
    #include <envmap_fragment> 

    gl_FragColor = vec4(outgoingLight, diffuseColor.a); 

    #include <premultiplied_alpha_fragment> 
    #include <tonemapping_fragment> 
    #include <encodings_fragment> 
    #include <fog_fragment> 
} 

Result 結果不很好看,但有帶照明的自定義着色器的概念是存在的。您所要做的就是複製MeshLambertShader中使用的代碼並修改diffuseColor.rgb。爲了減少着色器中的代碼量,可以添加MeshLambert着色器代碼的着色器塊(使用THREE.ShaderChunk數組)。然後,您可以在着色器中添加#includes,它們與您剛推入的着色器塊的名稱相對應。例如,您可以添加以下到您的JavaScript文件:

THREE.ShaderChunk["meshlambert_premain_fragment"] = ` 
     uniform vec3 diffuse; 
     uniform vec3 emissive; 
     uniform float opacity; 

     varying vec3 vLightFront; 

     #ifdef DOUBLE_SIDED 

      varying vec3 vLightBack; 

     #endif 

     #include <common> 
     #include <packing> 
     #include <color_pars_fragment> 
     #include <uv_pars_fragment> 
     #include <uv2_pars_fragment> 
     #include <map_pars_fragment> 
     #include <alphamap_pars_fragment> 
     #include <aomap_pars_fragment> 
     #include <lightmap_pars_fragment> 
     #include <emissivemap_pars_fragment> 
     #include <envmap_pars_fragment> 
     #include <bsdfs> 
     #include <lights_pars> 
     #include <fog_pars_fragment> 
     #include <shadowmap_pars_fragment> 
     #include <shadowmask_pars_fragment> 
     #include <specularmap_pars_fragment> 
     #include <logdepthbuf_pars_fragment> 
     #include <clipping_planes_pars_fragment> 
`; 

,後來在要使用MeshLambert照明着色器,你可以編寫以下,大大減少了您的着色器的代碼量文件:

#include <meshlambert_premain_fragment>