我有一个三个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制服的动画?

推荐答案

在第一次渲染之前,您可以访问animate()中的material.userData.shader.在这一点上,onBeforeCompile()从未执行过,因此material.userData.shaderundefined.您应该能够像这样解决该问题:

const shader = material.userData.shader;

if ( shader !== undefined ) {

   shader.uniforms.uTime.value = timeDivided;

} 

renderer.render(scene, camera);

Typescript相关问答推荐

Angular -使用Phone Directive将值粘贴到控件以格式化值时验证器不工作

如何使用axios在前端显示错误体

有没有一种方法可以在保持类型的可选状态的同时更改类型?

如何判断输入是否是TypeScript中的品牌类型?

类型脚本`Return;`vs`Return unfined;`

无法绑定ngModel.条件ngSwitchCase中的错误

类型脚本基于数组作为泛型参数展开类型

匿名静态类推断组成不正确推断

如何在TypeScrip中正确键入元素和事件目标?

通过字符串索引访问对象';S的值时出现文字脚本错误

如何将CSV/TXT文件导入到服务中?

带下拉菜单的Angular 响应式选项卡

在HighChats列时间序列图中,十字准线未按预期工作

为什么我的导航在使用Typescript的React Native中不起作用?

有没有可能创建一种类型,强制在TypeScrip中返回`tyPeof`语句?

S,为什么我的T扩展未定义的条件在属性的上下文中不起作用?

react 路由不响应参数

React-跨组件共享功能的最佳实践

如何使用 runInInjectionContext 中的参数测试功能性路由防护

根据索引将元组拆分为两个块