# 《蜘蛛侠：平行宇宙》的视觉解析与滤镜实现

### 一、视觉表达的创新点

#### 1. 一拍二模拟 2D 动画

1拍2是 2D 动画的传统做法，3D 动画强行这么做可以让人产生 2D 动画的质感错觉，但同时 Sony 选择了背景动画、镜头动画和其它位移动画又保持1拍1，从而保持 3D 动画特有的镜头顺滑的优势。

### 二、视觉效果与滤镜实现

#### 1. HalfTone 半调滤镜

``````precision highp float;
uniform sampler2D inputImageTexture;
varying vec2 textureCoordinate;

vec2 center = vec2(.5, .5);
float angle = 1.57;
float scale = 1.;
vec2 tSize = vec2(1000., 563.);

float blendLighten(float base, float blend) {
return max(blend,base);
}

vec3 blendLighten(vec3 base, vec3 blend) {
return vec3(blendLighten(base.r,blend.r),blendLighten(base.g,blend.g),blendLighten(base.b,blend.b));
}

vec3 blendLighten(vec3 base, vec3 blend, float opacity) {
return (blendLighten(base, blend) * opacity + base * (1.0 - opacity));
}

float pattern() {
float s = sin( angle ), c = cos( angle );
vec2 tex = textureCoordinate * tSize - center;
vec2 point = vec2( c * tex.x - s * tex.y, s * tex.x + c * tex.y ) * scale;
return ( sin( point.x ) * sin( point.y ) ) * 4.0;
}

void main() {
vec4 color = texture2D(inputImageTexture, textureCoordinate);
float average = ( color.r + color.g + color.b ) / 3.0;
vec4 halftone = vec4( vec3( average * 10.0 - 5.0 + pattern() ), color.a );
gl_FragColor = color + vec4(.02)*halftone;
gl_FragColor = vec4(blendLighten(color.rgb, halftone.rgb, .05), 1.);
}

#### 2. Glitch 故障效果

Glitch 故障效果在很多都互联网产品中同样可以看到应用，最典型的比如抖音的 LOGO 动画以及短视频中的滤镜效果。在电影中，由于另外几位蜘蛛侠来自不同的平行世界导致原子不稳定，表现出了差不多的花里胡哨的故障效果。

``````precision highp float;
uniform sampler2D inputImageTexture;
uniform sampler2D inputImageTexture2;
varying vec2 textureCoordinate;
uniform float time;

float amount = 0.1;
float speed = 0.5;

float random1d(float n){
return fract(sin(n) * 43758.5453);
}
float random2d(vec2 n) {
return fract(sin(dot(n, vec2(12.9898, 4.1414))) * 43758.5453);
}
float randomRange (in vec2 seed, in float min, in float max) {
return min + random2d(seed) * (max - min);
}
float insideRange(float v, float bottom, float top) {
return step(bottom, v) - step(top, v);
}
float rand(vec2 co){
return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
}

float blendDarken(float base, float blend) {
return min(blend,base);
}

vec3 blendDarken(vec3 base, vec3 blend) {
return vec3(blendDarken(base.r,blend.r),blendDarken(base.g,blend.g),blendDarken(base.b,blend.b));
}

vec3 blendDarken(vec3 base, vec3 blend, float opacity) {
return (blendDarken(base, blend) * opacity + base * (1.0 - opacity));
}
void main() {
vec2 uv = textureCoordinate;
float sTime = floor(sin(time*0.0005) * speed * 6.0 * 24.0);
vec3 inCol = texture2D(inputImageTexture, uv).rgb;
vec3 outCol = inCol;
float maxOffset = amount/4.0;
vec2 uvOff;
for (float i = 0.0; i < 10.0; i += 1.0) {
if (i > 10.0 * amount) break;
float sliceY = random2d(vec2(sTime + amount, 2345.0 + float(i)));
float sliceH = random2d(vec2(sTime + amount, 9035.0 + float(i))) * 0.25;
float hOffset = randomRange(vec2(sTime + amount, 9625.0 + float(i)), -maxOffset, maxOffset);
uvOff = uv;
uvOff.x += hOffset;
vec2 uvOff = fract(uvOff);
if (insideRange(uv.y, sliceY, fract(sliceY+sliceH)) == 1.0 ){
outCol = texture2D(inputImageTexture, uvOff).rgb;
}
}
float maxColOffset = amount/6.0;
vec2 colOffset = vec2(randomRange(vec2(sTime + amount, 3545.0),-maxColOffset,maxColOffset), randomRange(vec2(sTime , 7205.0),-maxColOffset,maxColOffset));
uvOff = fract(uv + colOffset);
float rnd = random2d(vec2(sTime + amount, 9545.0));
if (rnd < 0.33) {
outCol.r = texture2D(inputImageTexture, uvOff).r;
} else if (rnd < 0.66) {
outCol.g = texture2D(inputImageTexture, uvOff).g;
} else {
outCol.b = texture2D(inputImageTexture, uvOff).b;
}
vec3 inCol2 = texture2D(inputImageTexture2, uv).rgb;
vec3 finalColor = blendDarken(outCol, inCol2);
gl_FragColor = vec4(finalColor, 1.0);
}

#### 3. RGB Shift/Split RGB 分离

``````precision highp float;
uniform sampler2D inputImageTexture;
varying vec2 textureCoordinate;
uniform float time;

float amount = 0.01;
float angle = 0.;

void main() {
vec2 offset = amount * vec2(cos(time*.001), sin(time*.001));
vec4 cr = texture2D(inputImageTexture, textureCoordinate + offset);
vec4 cga = texture2D(inputImageTexture, textureCoordinate);
vec4 cb = texture2D(inputImageTexture, textureCoordinate - offset);
gl_FragColor = vec4(cr.r, cga.g, cb.b, cga.a);
}

• Cang_Wang
11天前
• sumsmile
20天前
• handyTool
1年前
• sumsmile
20天前
• sumsmile
21天前