attribute out --> varying. For fragment shader: in --> varying out --> (delete). For the out of the fragment shader, you can delete the declaration of the variable. Instead, use the.">

Left-Hand-Side Of Assignment Must Not Be Read-Only Attribute

In TypeScript 2.0, the modifier was added to the language. Properties marked with can only be assigned to during initialization or from within a constructor of the same class. All other assignments are disallowed.

Let's take a look at an example. Here's a simple type that declares two read-only properties, and :

We can now create an object representing the point (0|0), the origin, and initialize both and with the value :

However, because and are marked , we cannot change the value of either property afterwards:

A More Realistic Example

While the above example might seem contrived (and it is), consider a function like the following:

The function should not modify the property of the point it was given. Because of the modifier, the TypeScript compiler will yell at you if you try:

Instead, should return a new point with updated property values, which could look like this:

Now the compiler is happy because we're no longer trying to assign a value to a read-only property. We're creating a new point whose properties are initialized with updated values, which is perfectly fine.

Read-Only Class Properties

You can also apply the modifier to properties declared within a class. Here's a class with a read-only property and a gettable property, which is implicitly read-only because there's no setter:

Note that the radius is squared using the ES2016 exponentiation operator. Both the and the property can be read from outside the class (because neither one is marked ), but not written to (because both are marked ):

Read-Only Index Signatures

Additionally, index signatures can be marked with the modifier. The type makes use of such an index signature to prevent assignments to indexed properties:

Because of the read-only index signature, the compiler flags the following assignment as invalid:

vs. Immutability

The modifier is part of TypeScript's type system. It's only used by the compiler to check for illegal property assignments. Once the TypeScript code has been compiled to JavaScript, all notions of are gone. Feel free to play around with this little sample to see how read-only properties are transpiled.

Because is only a compile-time artifact, there's no protection against property assignments at runtime whatsoever. That said, it's another feature of the type system that helps you write correct code by having the compiler check for unintended property assignments from within your TypeScript code base.


This tutorial is based on the directional lights tutorial as most of the code comes from there. The tutorial is based on the difference between a directional light and a point light. A directional light is assumed to be infinitely far away, so that the light rays are parallel when they reach the object. In contrast, a point light has a position, and sends rays in all directions. Furthermore, in a point light, the intensity decays with the distance to the vertex.

From an OpenGL application point of view there are two differences between the two:

  • the w component of the light position field: in a directional light it is zero to indicate that the position is in fact a direction (or vector), where as in a point light the w component of the light position field is 1.
  • The attenuation is specified based on three coefficients: a constant term, a linear term, and a quadratic term

From a computational point of view these differences must be taken care of. For a directional light, the direction of the light rays is constant for every vertex, whereas for a point light it is the vector from the vertex to the lights position. Hence, all that needs to change in the vertex shader is the computation of the lights direction.

The attenuation is computed based on the following formula in OpenGL:

where k0 is the constant attenuation, k1 is the linear attenuation, k2 is the quadratic attenuation and d is the distance from the light’s position to the vertex.

Note that the attenuation does not vary linearly with distance, hence we can’t compute the attenuation per vertex and use the interpolated value in the fragment shader. We can however compute the distance in the vertex shader and use the interpolated distance in the fragment shader to compute the attenuation.

The equation for the color using a point light is:

As shown in the above equation, the ambient term must be spitted in two: one global ambient term using the lighting model ambient setting and a light specific ambient term. The vertex shader must separate the computation of the ambient term accordingly. The new vertex shader is:

varying vec4 diffuse,ambientGlobal,ambient, ecPos; varying vec3 normal,halfVector; void main() { vec3 aux; /* first transform the normal into eye space and normalize the result */ normal = normalize(gl_NormalMatrix * gl_Normal); /* compute the vertex position in camera space. */ ecPos = gl_ModelViewMatrix * gl_Vertex; /* Normalize the halfVector to pass it to the fragment shader */ halfVector = gl_LightSource[0]; /* Compute the diffuse, ambient and globalAmbient terms */ diffuse = gl_FrontMaterial.diffuse * gl_LightSource[0].diffuse; ambient = gl_FrontMaterial.ambient * gl_LightSource[0].ambient; ambientGlobal = gl_LightModel.ambient * gl_FrontMaterial.ambient; gl_Position = ftransform(); }

The fragment shader needs to compute the attenuation.

varying vec4 diffuse,ambientGlobal, ambient, ecPos; varying vec3 normal,halfVector; void main() { vec3 n,halfV,viewV,lightDir; float NdotL,NdotHV; vec4 color = ambientGlobal; float att, dist; /* a fragment shader can't write a verying variable, hence we need a new variable to store the normalized interpolated normal */ n = normalize(normal); // Compute the ligt direction lightDir = vec3(gl_LightSource[0].position-ecPos); /* compute the distance to the light source to a varying variable*/ dist = length(lightDir); /* compute the dot product between normal and ldir */ NdotL = max(dot(n,normalize(lightDir)),0.0); if (NdotL > 0.0) { att = 1.0 / (gl_LightSource[0].constantAttenuation + gl_LightSource[0].linearAttenuation * dist + gl_LightSource[0].quadraticAttenuation * dist * dist); color += att * (diffuse * NdotL + ambient); halfV = normalize(halfVector); NdotHV = max(dot(n,halfV),0.0); color += att * gl_FrontMaterial.specular * gl_LightSource[0].specular * pow(NdotHV,gl_FrontMaterial.shininess); } gl_FragColor = color; }

The following images show the difference between a point light as computed by the fixed functionality, i.e. per vertex, and using the shader in this tutorial, i.e. per pixel.

Fixed FunctionalityPer Pixel


Categories: 1

0 Replies to “Left-Hand-Side Of Assignment Must Not Be Read-Only Attribute”

Leave a comment

L'indirizzo email non verrĂ  pubblicato. I campi obbligatori sono contrassegnati *