I’m learning Threejs by following this tutorial
I’m stuck at making the boilderplate. It got error: "Uncaught TypeError: Cannot read properties of undefined (reading ‘uniforms’).
In my code, i defined ‘uniforms’ at:
addObjects() {
this.material = new THREE.ShaderMaterial({
vertexShader: vertex,
fragmentShader: fragment,
extensions: {
derivatives:" #extension GL_OES_standard_derivatives: enable"
},
uniforms: {
time: {value:0},
resolution: {value: new THREE.Vector4()},
},
side: THREE.DoubleSide
});
this.geometry = new THREE.PlaneGeometry(1,1,1,1);
this.plane = new THREE.Mesh(this.geometry, this.material);
this.scene.add(this.plane);
}
Then i called it at:
render() {
if(!this.isPlaying) return;
this.time += 0.05;
this.material.uniforms.time.value = this.time;
requestAnimationFrame(this.render.bind(this));
this.renderer.render(this.scene, this.camera);
}
What is the problems, or what should i check to find the problems?
Hi PhiNM,
This is not a good example because WebGL1 is no longer maintained by three.js because it is too old.
WebGL2 and WebGPU are state of the art.
In order to stay as close as possible to your example, I have a WebGL2 shader with material for you here.
const vertexShader = `
precision highp float;
precision highp int;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
uniform mat4 modelMatrix;
uniform mat4 viewMatrix;
// Attributes
in vec3 position;
in vec3 normal;
in vec2 uv;
// Outputs
out vec3 vPosition;
out vec3 vNormal;
out vec2 vUv;
void main() {
vPosition = position;
vNormal = normal;
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`;
const fragmentShader = `
precision highp float;
precision highp int;
uniform vec4 color;
uniform float time;
in vec4 vPosition;
in vec3 vNormal;
in vec2 vUv;
out vec4 outColor;
void main() {
outColor = color;
}
`;
const uniforms = {
color: {value: new THREE.Vector4(1, 0, 0, 1)},
time: {value: 0}
}
this.material = new THREE.RawShaderMaterial({
glslVersion: THREE.GLSL3, //important for WebGL2
uniforms: uniforms,
vertexShader: vertexShader,
fragmentShader: fragmentShader,
side: THREE.DoubleSide,
});
I haven’t used the time in the shader but you can use it.
Describing how the vertex and the fragment shader work would be a bit more extensive, but I explain it if you want.
I don’t see any vertex or fragment shader in your case. If these don’t exist and you use the command:
“this.material.uniforms.time.value = this.time;”
to access the uniforms.time of the material, you will get an error message.
Thank you, here is my shader, hope you take a look:
const fragment = `
precision mediump float;
varying vec2 vCoordinates; // Declare varying variable
void main() {
gl_FragColor = vec4(vCoordinates.x/512.0, vCoordinates.y/512.0, 0.0, 1.0);
}
`;
const vertex = `
varying vec2 vUv;
varying vec2 vCoordinates; // Declare varying variable
attribute vec3 aCoordinates;
void main() {
vUv = uv;
vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);
gl_PointSize = 2000.0 * (1.0 / -mvPosition.z);
gl_Position = projectionMatrix * mvPosition;
vCoordinates = aCoordinates.xy; // Pass aCoordinates to vCoordinates
}
`;
Could the shaders be the reason i got the properties undefined error? Since they just say error about the uniforms properties
I use Edge, and it just automatically use webGL1. Also, since i’m just following the tutorial i don’t really know what version should i use.
You have no time uniform in your shaders but you try to access it with
“this.material.uniforms.time.value = this.time;”
try this:
const fragment = `
precision mediump float;
varying vec2 vCoordinates; // Declare varying variable
uniform float time;
void main() {
gl_FragColor = vec4(vCoordinates.x/512.0, vCoordinates.y/512.0, 0.0, 1.0);
}
`;
Now you have the time uniform in your shader and can use it later. At the moment it is just implemented but not used. But you can access it with
“this.material.uniforms.time.value = this.time;”
and change it.
But I recommend you start with WebGL2 as soon as you learn the ropes because WebGL1 is dying
I suspect the value of ‘this’ is different in your addObjects() and render() functions. Hence the material object not being defined.
What tutorial are you following thats calling bind
and this
in such way. This has unnecessary and advanced javascript concepts that are getting in the way.
My guess is that you are starting “render” before calling “addObjects” so the material isn’t set up yet.