我正在尝试重构十年前的 GLSL 顶点位移着色器,该着色器曾经与 Three.js 的旧版本一起使用,但我遇到了从视频源加载纹理的操作顺序到重构着色器的一系列问题对编译器来说更准确。我想我已经解决了大部分问题,除了一个(我希望如此)。请帮忙。
StackBlitz 上有实时代码示例。 https://stackblitz.com/edit/vitejs-vite-t6qqxpfh?file=src%2Fmain.ts
顶点位移是由视频纹理中像素的亮度值和用于映射到几何体尺寸的尺寸驱动的,但现在情况似乎并非如此,GLSL 着色器仅位移一个顶点。
它曾经做过这样的事情:
遗留代码充其量是混乱的,所以我只会粘贴在这里工作的遗留GLSL着色器:
RuttEtraShader = {
uniforms: {
"tDiffuse": { type: "t", value: null },
"multiplier": { type: "f", value: 13.3 },
"displace": { type: "f", value: 7.3 },
"opacity": { type: "f", value: 1.0 },
"originX": { type: "f", value: 0.0 },
"originY": { type: "f", value: 0.0 },
"originZ": { type: "f", value: 0.0 }
},
vertexShader: [
'precision highp int;',
'precision highp float;',
'uniform sampler2D tDiffuse;',
'varying vec3 vColor;',
'varying vec2 vUv;',
'uniform float displace;',
'uniform float multiplier;',
'uniform float originX;',
'uniform float originY;',
'uniform float originZ;',
'void main() {',
'vec4 newVertexPos;',
'vec4 dv;',
'float df;',
'vUv = uv;',
'vec3 origin = vec3 (originX,originY,originZ);',
'dv = texture2D( tDiffuse, vUv.xy );',
'df = multiplier*dv.x + multiplier*dv.y + multiplier*dv.z;',
'newVertexPos = vec4( normalize(position - origin) * df * vec3 (1.0, 1.0, displace), 0.0 ) + vec4( position, 1.0 );',
'vColor = vec3( dv.x, dv.y, dv.z );',
'gl_Position = projectionMatrix * modelViewMatrix * newVertexPos;',
'}'
].join("\n"),
fragmentShader: [
'varying vec3 vColor;',
'uniform float opacity;',
'void main() {',
'gl_FragColor = vec4( vColor.rgb, opacity );',
'}'
].join("\n")
};
我尝试使用三个 0.171.0 的新 GLSL 着色器如下所示:
const RuttEtraShader = {
name: 'RuttEtraShader',
uniforms: {
'tDiffuse': { value: null },
'multiplier': { value: 13.3 },
'displace': { value: 3.3 },
'opacity': { value: 1.0 },
'originX': { value: 0.0 },
'originY': { value: 0.0 },
'originZ': { value: 0.0 }
},
vertexShader: `
precision highp int;
precision highp float;
attribute vec2 uv;
uniform sampler2D tDiffuse;
varying vec2 vUv;
varying vec3 vColor;
varying vec3 position;
uniform float displace;
uniform float multiplier;
uniform float originX;
uniform float originY;
uniform float originZ;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
void main() {
vec4 newVertexPos;
vec4 dv;
float df;
vec3 origin = vec3(originX, originY, originZ);
vUv = uv;
dv = texture2D( tDiffuse, vUv.xy );
df = multiplier * dv.x + multiplier * dv.y + multiplier * dv.z;
newVertexPos = vec4( normalize(position - origin) * df * vec3(1.0, 1.0, displace), 0.0 ) + vec4( position, 1.0 );
vColor = vec3( dv.x, dv.y, dv.z );
gl_Position = projectionMatrix * modelViewMatrix * newVertexPos;
}`,
fragmentShader: `
precision highp float;
varying vec3 vColor;
uniform float opacity;
void main() {
gl_FragColor = vec4( vColor.rgb, opacity );
}`
};
三个.js代码:
import { OrthographicCamera, Scene, Color, PlaneGeometry, Float32BufferAttribute, Uint8BufferAttribute, RawShaderMaterial, DoubleSide, Mesh, WebGLRenderer, VideoTexture, LinearFilter, RGBAFormat, WebGLRenderTarget, NearestFilter, AmbientLight, SpotLight } from 'three';
import { RuttEtraShader } from './shaders/RuttEtraShader';
import { EffectComposer } from './postprocessing/EffectComposer';
import { RenderPass } from './postprocessing/RenderPass';
import { BloomPass } from './postprocessing/BloomPass';
import { HueSaturationShader } from './shaders/HueSaturationShader';
import { ShaderPass } from './postprocessing/ShaderPass';
export class Synth {
container: HTMLElement;
camera: OrthographicCamera;
scene: Scene;
geometry: PlaneGeometry;
material: RawShaderMaterial;
mesh: Mesh;
renderer: WebGLRenderer;
videoInput: HTMLVideoElement;
texture: any;
fill: AmbientLight;
key: SpotLight;
back: SpotLight;
composer: EffectComposer;
renderModel: RenderPass;
effectBloom: BloomPass;
effectHue: ShaderPass;
constructor(container: HTMLElement, videoInput: HTMLVideoElement) {
this.container = container;
this.videoInput = videoInput;
this.camera = new OrthographicCamera( window.innerWidth / - 2, window.innerWidth / 2, window.innerHeight / 2, window.innerHeight / - 2, 1, 10000);
this.camera.position.x = 0;
this.camera.position.y = -1130;
this.camera.position.z = 1680;
this.scene = new Scene();
this.scene.background = new Color( 0x000000 );
this.geometry = new PlaneGeometry(640, 480);
this.mesh = new Mesh( this.geometry );
this.scene.add( this.mesh );
this.fill = new AmbientLight(0x707070); // soft white light
this.scene.add(this.fill);
this.key = new SpotLight(0xffffff);
this.key.position.set(0, 0, 5000).normalize();
this.key.target = this.mesh;
this.key.intensity = 10;
this.key.castShadow = true;
this.scene.add(this.key);
this.back = new SpotLight(0xffffff);
this.back.position.set(0, 0, -5000).normalize();
this.back.target = this.mesh;
this.back.intensity = 100;
this.back.castShadow = true;
this.scene.add(this.back);
const renderTarget = new WebGLRenderTarget(
window.innerWidth, window.innerHeight, {minFilter: LinearFilter, magFilter: NearestFilter});
this.renderer = new WebGLRenderer({
antialias: true,
});
this.renderer.setRenderTarget(renderTarget);
this.renderer.setPixelRatio( window.devicePixelRatio );
this.renderer.setSize( window.innerWidth, window.innerHeight );
this.renderer.setAnimationLoop( this.animate.bind(this) );
this.composer = new EffectComposer(this.renderer, this.renderer.getRenderTarget());
this.composer.setSize(window.innerWidth, window.innerHeight);
this.renderer.getRenderTarget().setSize( window.innerWidth, window.innerHeight );
this.renderModel = new RenderPass(this.scene, this.camera);
this.composer.addPass(this.renderModel);
this.effectBloom = new BloomPass(3.3, 20, 4.0);
this.effectBloom = new BloomPass(1.5, 5.0, 1.4);
this.composer.addPass(this.effectBloom);
this.effectHue = new ShaderPass(HueSaturationShader, null);
this.composer.addPass(this.effectHue);
this.videoInput.addEventListener("loadeddata", this.load.bind(this));
this.videoInput.load();
this.videoInput.loop = true;
window.addEventListener('resize', this.onWindowResize.bind(this), false);
this.container.appendChild( this.renderer.domElement );
}
load() {
this.scene.remove(this.mesh);
this.texture = new VideoTexture(this.videoInput);
this.texture.minFilter = LinearFilter;
this.texture.magFilter = LinearFilter;
this.texture.format = RGBAFormat;
this.texture.generateMipmaps = false;
this.material = new RawShaderMaterial({
uniforms: {
tDiffuse: { value: this.texture },
originX: { value: 0.0 },
originY: { value: 0.0 },
originZ: { value: -2000.0 },
opacity: { value: 0.95 },
multiplier: { value: 13.3 },
displace: { value: 3.3 },
},
vertexShader: RuttEtraShader.vertexShader,
fragmentShader: RuttEtraShader.fragmentShader,
depthWrite: true,
depthTest: true,
wireframe: true,
transparent: true,
side: DoubleSide
});
this.mesh = new Mesh( this.geometry, this.material );
this.scene.add( this.mesh );
}
animate() {
const time = performance.now();
this.camera.aspect = window.innerWidth / window.innerHeight;
this.texture && (this.texture.needsUpdate = true);
this.material && (this.material.needsUpdate = true);
this.material && (this.material.renderToScreen = true);
this.material && (this.material.wireframe = true);
this.camera.lookAt(this.scene.position);
this.renderer.render( this.scene, this.camera );
}
onWindowResize() {
this.camera.aspect = window.innerWidth / window.innerHeight;
this.camera.updateProjectionMatrix();
this.renderer.setSize(window.innerWidth, window.innerHeight);
this.composer.setSize(window.innerWidth, window.innerHeight);
this.renderer.getRenderTarget().setSize( window.innerWidth, window.innerHeight );
}
}
我猜我缺少一些现在需要的配置,而这些配置以前不需要,或者现在似乎有一个针对 GLSL 的编译器,该编译器更加强大,可能引入了重大更改,并且着色器的语法是错误的,虽然我没有看到任何错误。我用最新的三个将逻辑简化为一个简单的例子。
我使用
RawShaderMaterial
而不是 ShaderMaterial
。这就是问题所在。我删除了着色器中声明的重复变量并且它起作用了。