我有一个三个js,类型脚本应用程序,在它里面我使用我自己的定制GLSL着色器.通过设计着色器,我使用了THREE.ShaderMaterial()类,但现在我想重构代码,以便可以使用THREE.MeshStandardMaterial类.
这是我第一次做这样的事情,但无论如何,重构中的一切都很顺利,除了像这样更新动画循环中的uTime一致性:
material.userData.shader.uniforms.uTime.value = timeDivided;
因为现在我收到了这个错误:
Index.ts:71 Uncaught TypeError: Cannot read properties of undefined (reading 'uniforms')
at animate (stackOverflowQuestion.ts:71:28)
at onAnimationFrame (three.module.js:28991:1)
at onAnimationFrame (three.module.js:13332:1)
animate @ stackOverflowQuestion.ts:71
以下是简化的完整应用程序代码:
Index.ts:
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import vertexShaderParse from "./shaders/vertexParse.glsl";
import vertexMain from "./shaders/vertexMain.glsl";
import textureImage from "./assets/images/test-image-1.jpeg";
// renderer
const renderer = new THREE.WebGLRenderer();
renderer.shadowMap.enabled = true;
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// scene
const scene = new THREE.Scene();
scene.background = new THREE.Color("#AADEF0");
// camera
const camera = new THREE.PerspectiveCamera(
60,
window.innerWidth / window.innerHeight,
0.1
);
camera.position.set(0, 5, 5);
scene.add(camera);
// ambient light
const ambientLight = new THREE.AmbientLight(0xffffff, 0.3);
scene.add(ambientLight);
// directional light
const dirLight = new THREE.DirectionalLight(0xffffff, 1.0);
dirLight.shadow.camera.lookAt(0, 0, 0);
scene.add(dirLight);
// orbit controls
const orbitControls = new OrbitControls(camera, renderer.domElement);
orbitControls.target.set(0, 0, 0);
// main object using the shaders
const geometry = new THREE.IcosahedronGeometry(1, 250);
const material = new THREE.MeshStandardMaterial();
material.onBeforeCompile = (shader) => {
// storing a reference to the shader object in userData
material.userData.shader = shader;
// setting uniforms
shader.uniforms.uTime = { value: 0 };
shader.uniforms.uRadius = { value: 0.8 };
shader.uniforms.uTexture = {
value: new THREE.TextureLoader().load(textureImage),
};
const parseVertexString = `#include <displacementmap_pars_vertex>`;
shader.vertexShader = shader.vertexShader.replace(
parseVertexString,
parseVertexString + vertexShaderParse
);
const mainVertexString = `#include <displacementmap_vertex>`;
shader.vertexShader = shader.vertexShader.replace(
mainVertexString,
mainVertexString + vertexMain
);
};
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
const animate = (time: number) => {
const timeDivided = time / 10000;
// this is the part that doesn't work ↓, uncommenting this causes the application to break
material.userData.shader.uniforms.uTime.value = timeDivided;
renderer.render(scene, camera);
};
renderer.setAnimationLoop(animate);
Vertex Main.glsl:
uniform float uTime;
uniform sampler2D uTexture;
varying float vDisplacement;
float getWave(vec3 position) {
return clamp(smoothstep(-0.1, 0.40, abs(mod(position.y * 5., 1.) - 0.5)), 0.4, 1.0);
}
Vertex Main.glsl:
vec3 image = texture2D(uTexture, uv).xyz;
vec3 coords = normal;
coords.y += uTime;
coords += desaturatedImage / 5.;
float wavePattern = getWave(coords);
vDisplacement = wavePattern;
// varyings
float displacement = vDisplacement / 5.;
vec3 displacedNormal = normalize(objectNormal) * displacement;
transformed += displacedNormal;
我应该如何修复这个问题,以便可以设置uTime制服的动画?