将ShaderToy移植到THREE.JS问题

时间:2017-07-16 20:59:06

标签: three.js glsl textures shader

我正在尝试将此着色器https://www.shadertoy.com/view/MsB3WR移植到 THREE.JS实际上它几乎就在那里,但我有一个UV映射问题, 所以现在有这样的事情:

enter image description here

SHADER CODE:

vertexShader:

void main() { gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); }


fragmentShader:


//mouse.z - left click
//mouse.w - right click

//texture A > iChannel0 > assets/textureA.png
//texture B > iChannel1 > assets/textureB.png
//texture C > iChannel2 > assets/textureC.png

#define BUMPFACTOR 0.1
#define EPSILON 0.1
#define BUMPDISTANCE 60.

//(iGlobalTime + 285.)
uniform float time;

uniform sampler2D textureA;
uniform sampler2D textureB;
uniform sampler2D textureC;

uniform vec2 resolution;
uniform vec3 mouse;

mat2 rot(const in float a) { return mat2(cos(a), sin(a), -sin(a), cos(a));  }
const mat2 m2 = mat2( 0.60, -0.80, 0.80, 0.60 );
const mat3 m3 = mat3( 0.00,  0.80,  0.60, -0.80,  0.36, -0.48, -0.60, -0.48,  0.64 );

float noise( const in vec2 x ) {

    vec2 p = floor(x);
    vec2 f = fract(x);
    f = f * f * (3.0 - 2.0 * f);

    vec2 uv = (p.xy) + f.xy;
    return texture2D( textureA, (uv + 0.5) / 256.0, 0.0 ).x;

}

float noise( const in vec3 x ) {

    vec3 p = floor(x);
    vec3 f = fract(x);
    f = f*f*(3.0-2.0*f);

    vec2 uv = (p.xy + vec2(37.0, 17.0) * p.z) + f.xy;
    vec2 rg = texture2D( textureA, (uv + 0.5) / 256.0, 0.0 ).yx;
    return mix( rg.x, rg.y, f.z );

}

float fbm( in vec3 p ) {

    float f = 0.0;
    f += 0.5000 * noise(p); p = m3 * p * 2.02;
    f += 0.2500 * noise(p); p = m3 * p * 2.03;
    f += 0.1250 * noise(p); p = m3 * p * 2.01;
    f += 0.0625 * noise(p);
    return f / 0.9375;

}

float hash( in float n ) { return fract(sin(n) * 43758.5453); }

//INTERSECTION FUNCTION

bool intersectPlane(const in vec3 ro, const in vec3 rd, const in float height, inout float dist) {  

    if (rd.y == 0.0) { return false; }

    float d = -(ro.y - height)/rd.y;
    d = min(100000.0, d);
    if( d > 0. && d < dist ) {
        dist = d;
        return true;
    }

    return false;

}

//LIGHT DIRECTION
vec3 lig = normalize(vec3( 0.3, 0.5, 0.6));

vec3 bgColor( const in vec3 rd ) {

    float sun = clamp( dot(lig, rd), 0.0, 1.0 );
    vec3 col = vec3(0.5, 0.52, 0.55) - rd.y * 0.2 * vec3(1.0, 0.8, 1.0) + 0.15 * 0.75;
    col += vec3(1.0, 0.6, 0.1) * pow( sun, 8.0 );
    col *= 0.95;
    return col;

}

//CLOUDS

#define CLOUDSCALE (500. / (64. * 0.03))

float cloudMap( const in vec3 p, const in float ani ) {

    vec3 r = p / CLOUDSCALE;

    float den = -1.8 + cos(r.y * 5.-4.3);

    float f;
    vec3 q = 2.5 * r * vec3(0.75, 1.0, 0.75) + vec3(1.0, 1.0, 15.0) * ani * 0.15;
    f  = 0.50000 * noise(q); q = q * 2.02 - vec3(-1.0,1.0,-1.0) * ani * 0.15;
    f += 0.25000 * noise(q); q = q * 2.03 + vec3(1.0, -1.0, 1.0) * ani * 0.15;
    f += 0.12500 * noise(q); q = q * 2.01 - vec3(1.0, 1.0, -1.0) * ani * 0.15;
    f += 0.06250 * noise(q); q = q * 2.02 + vec3(1.0, 1.0, 1.0) * ani * 0.15;
    f += 0.03125 * noise(q);

    return 0.065 * clamp( den + 4.4 * f, 0.0, 1.0 );

}

vec3 raymarchClouds( const in vec3 ro, const in vec3 rd, const in vec3 bgc, const in vec3 fgc, const in float startdist, const in float maxdist, const in float ani ) {

    float t = startdist + CLOUDSCALE * 0.02 * hash(rd.x + 35.6987221 * rd.y + time);

    vec4 sum = vec4( 0.0 );

    for( int i=0; i<64; i++ ) {
        if( sum.a > 0.99 || t > maxdist ) continue;

        vec3 pos = ro + t*rd;
        float a = cloudMap( pos, ani );

        float dif = clamp(0.1 + 0.8*(a - cloudMap( pos + lig*0.15*CLOUDSCALE, ani )), 0., 0.5);
        vec4 col = vec4( (1.+dif)*fgc, a );

        col.rgb *= col.a;
        sum = sum + col*(1.0 - sum.a);  

        t += (0.03*CLOUDSCALE)+t*0.012;
    }

    sum.xyz = mix( bgc, sum.xyz/(sum.w+0.0001), sum.w );

    return clamp( sum.xyz, 0.0, 1.0 );

}

//TERRAIN

float terrainMap( const in vec3 p ) {
    return (texture2D( textureB, (-p.zx*m2)*0.000046, 0. ).x*600.) * smoothstep( 820., 1000., length(p.xz) ) - 2. + noise(p.xz*0.5)*15.;
}

vec3 raymarchTerrain( const in vec3 ro, const in vec3 rd, const in vec3 bgc, const in float startdist, inout float dist ) {

    float t = startdist;

    vec4 sum = vec4( 0.0 );
    bool hit = false;
    vec3 col = bgc;

    for( int i=0; i<80; i++ ) {
        if( hit ) break;

        t += 8. + t/300.;
        vec3 pos = ro + t*rd;

        if( pos.y < terrainMap(pos) ) {
            hit = true;
        }       
    }
    if( hit ) {

        float dt = 4.+t/400.;
        t -= dt;

        vec3 pos = ro + t*rd;   
        t += (0.5 - step( pos.y , terrainMap(pos) )) * dt;      
        for( int j=0; j<2; j++ ) {
            pos = ro + t*rd;
            dt *= 0.5;
            t += (0.5 - step( pos.y , terrainMap(pos) )) * dt;
        }
        pos = ro + t*rd;

        vec3 dx = vec3( 100.*EPSILON, 0., 0. );
        vec3 dz = vec3( 0., 0., 100.*EPSILON );

        vec3 normal = vec3( 0., 0., 0. );
        normal.x = (terrainMap(pos + dx) - terrainMap(pos-dx) ) / (200. * EPSILON);
        normal.z = (terrainMap(pos + dz) - terrainMap(pos-dz) ) / (200. * EPSILON);
        normal.y = 1.;
        normal = normalize( normal );       

        col = vec3(0.2) + 0.7 * texture2D( textureC , pos.xz * 0.01 ).xyz * 
                   vec3(1.0, 0.9, 0.6);

        float veg = 0.3*fbm(pos*0.2)+normal.y;

        if( veg > 0.75 ) {
            col = vec3( 0.45, 0.6, 0.3 )*(0.5+0.5*fbm(pos*0.5))*0.6;
        } else 
        if( veg > 0.66 ) {
            col = col*0.6+vec3( 0.4, 0.5, 0.3 )*(0.5+0.5*fbm(pos*0.25))*0.3;
        }
        col *= vec3(0.5, 0.52, 0.65)*vec3(1.,.9,0.8);

        vec3 brdf = col;

        float diff = clamp( dot( normal, -lig ), 0., 1.);

        col = brdf*diff*vec3(1.0,.6,0.1);
        col += brdf*clamp( dot( normal, lig ), 0., 1.)*vec3(0.8,.6,0.5)*0.8;
        col += brdf*clamp( dot( normal, vec3(0.,1.,0.) ), 0., 1.)*vec3(0.8,.8,1.)*0.2;

        dist = t;
        t -= pos.y*3.5;
        col = mix( col, bgc, 1.0-exp(-0.0000005*t*t) );

    }

    return col;

}


float waterMap( vec2 pos ) { vec2 posm = pos * m2; return abs( fbm( vec3( 8. * posm, time ))-0.5 ) * 0.1; }

void main(void) 
{

    vec2 q = gl_FragCoord.xy / resolution.xy;
    vec2 p = -1.0 + 2.0 * q;
    p.x *= resolution.x / resolution.y;

    vec3 ro = vec3(0.0, 0.5, 0.0);
    vec3 ta = vec3(0.0, 0.45,1.0);

    if (mouse.z >= 1.0) { ta.xz *= rot( (mouse.x / resolution.x - 0.5) * 7.0 ); }

    ta.xz *= rot( mod(time * 0.05, 6.2831852) );

    vec3 ww = normalize( ta - ro);
    vec3 uu = normalize(cross( vec3(0.0,1.0,0.0), ww ));
    vec3 vv = normalize(cross(ww,uu));
    vec3 rd = normalize( p.x*uu + p.y*vv + 2.5*ww );

    float fresnel, refldist = 5000., maxdist = 5000.;
    bool reflected = false;
    vec3 normal, col = bgColor( rd );
    vec3 roo = ro, rdo = rd, bgc = col;

     if( intersectPlane( ro, rd, 0., refldist ) && refldist < 200. ) {
            ro += refldist*rd;  
            vec2 coord = ro.xz;
            float bumpfactor = BUMPFACTOR * (1. - smoothstep( 0., BUMPDISTANCE, refldist) );

            vec2 dx = vec2( EPSILON, 0. );
            vec2 dz = vec2( 0., EPSILON );

            normal = vec3( 0., 1., 0. );
            normal.x = -bumpfactor * (waterMap(coord + dx) - waterMap(coord-dx) ) / (2. * EPSILON);
            normal.z = -bumpfactor * (waterMap(coord + dz) - waterMap(coord-dz) ) / (2. * EPSILON);
            normal = normalize( normal );       

            float ndotr = dot(normal,rd);
            fresnel = pow(1.0-abs(ndotr),5.);

            rd = reflect( rd, normal);

            reflected = true;
            bgc = col = bgColor( rd );
        }

        col = raymarchTerrain( ro, rd, col, reflected?(800.-refldist):800., maxdist );
        col = raymarchClouds( ro, rd, col, bgc, reflected?max(0.,min(150.,(150.-refldist))):150., maxdist, time*0.05 );

        if( reflected ) {

            col = mix( col.xyz, bgc, 1.0-exp(-0.0000005  *refldist * refldist) );
            col *= fresnel * 0.9;       
            vec3 refr = refract( rdo, normal, 1./1.3330 );
            intersectPlane( ro, refr, -2., refldist );
            col += mix( texture2D( textureC, (roo+refldist*refr).xz*1.3 ).xyz * vec3(1.0, 0.9, 0.6), vec3(1.0, 0.9, 0.8)*0.5, clamp( refldist / 3.0, 0.0, 1.0) ) * (1.-fresnel)*0.125;
        }

    col = pow( col, vec3(0.7) );

    col = col * col * (3.0-2.0 * col);
    col = mix( col, vec3(dot(col,vec3(0.33))), -0.5 );
    col *= 0.25 + 0.75*pow( 16.0*q.x*q.y*(1.0-q.x)*(1.0-q.y), 0.1 );

    //vec4 color = texture2D( textureA, vUv );

    gl_FragColor = vec4( col, 1.0 );

}

和JavaScript [初始化]:

    clock = new THREE.Clock();
    mouse = new THREE.Vector4();

    var loaderA = new THREE.TextureLoader();
    var bitmapA = loaderA.load("assets/textureA.png");
    var loaderB = new THREE.TextureLoader();
    var bitmapB = loaderB.load("assets/textureB.png");
    var loaderC = new THREE.TextureLoader();
    var bitmapC = loaderC.load("assets/textureC.png");

    var uniforms = {

    textureA: { type: 't', value: bitmapA },
    textureB: { type: 't', value: bitmapB },
    textureC: { type: 't', value: bitmapC },

    time: {
        type: 'f',
        value: clock.getDelta() + 285.
    },
    resolution: {
        type: 'v2',
        value: new THREE.Vector2( window.innerWidth,  window.innerHeight)
    },
    mouse: {
        type: 'v4',
        value: new THREE.Vector4(window.innerWidth / 2,  window.innerHeight / 2, 0.0, 0.0)
    }

    };

    var glslMat = new THREE.ShaderMaterial( { 

    uniforms: uniforms,
    vertexShader: document.getElementById("vertexShader").textContent,
    fragmentShader: document.getElementById("fragmentShader").textContent

    } );

    var geometry = new THREE.PlaneGeometry(window.innerWidth * 4 , window.innerHeight * 4, 1, 1);

    var plane = new THREE.Mesh(geometry, glslMat);

有什么建议吗?

1 个答案:

答案 0 :(得分:1)

通过实现纹理包装及其采样

解决了这个问题
 var loaderA = new THREE.TextureLoader();
 var bitmapA = loaderA.load( 'assets/originalRGBA.png', function ( texture ) {

    texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
    texture.offset.set( 0, 0 );
    texture.repeat.set( 2, 2 );

 } );