我正在尝试将此着色器https://www.shadertoy.com/view/MsB3WR移植到 THREE.JS实际上它几乎就在那里,但我有一个UV映射问题, 所以现在有这样的事情:
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);
有什么建议吗?
答案 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 );
} );