blindepl
blindepl

Reputation: 287

Three.js Texture in shaderMaterial

I could not load texture to my shader material, only what I see are just black dot. This is my shader.js

THREE.ShaderLib['cloud'] = {

    uniforms: {
        texture: { type: "t", value: THREE.ImageUtils.loadTexture("img/cloud.png") }
    },

    vertexShader: [
        "varying vec2 vUv;",
        "void main() {",
            "vUv = uv;",
            "gl_PointSize = 8.0;",
            "gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);",
        "}",
    ].join("\n"),

    fragmentShader: [
            "varying vec2 vUv;",
            "uniform sampler2D texture;",
            "void main() {",
                "gl_FragColor = texture2D(texture, vUv);",
            "}",
    ].join("\n")
};

and this is how I'm trying to load and use it:

var cloudShader = THREE.ShaderLib["cloud"];
var uniforms = THREE.UniformsUtils.clone(cloudShader.uniforms);

var texture = THREE.ImageUtils.loadTexture("img/cloud.png", undefined, function () {

   uniforms.texture.value = texture;
   texture.needsUpdate = true;

   var _material = new THREE.ShaderMaterial({
      fragmentShader: cloudShader.fragmentShader,
      vertexShader: cloudShader.vertexShader,
      uniforms: uniforms                   
   });                    
   _material.uniforms.texture.value.needsUpdate = true;
   var _geometry = new THREE.Geometry();
   _geometry.vertices.push(new THREE.Vector3(0, 0, 0));
   var _mesh = new THREE.Points(_geometry, _material);
   scene.add(_mesh);

 });

As You can see I'm trying to set update texture value two times, before and after material is created. It's really simpy example but I have no idea why it is not working in the way that I'm using it. There is no errors in debug console.

I'm using THREE.Points class, because I'm using it to generate clouds as a particle groups.

Thanks in advance for any help.

Upvotes: 5

Views: 9141

Answers (3)

Vladimir Makhortov
Vladimir Makhortov

Reputation: 38

So if anyone having the same issue now. The reason this doesn't work is not only because of the texture being a reserved keyword in GLSL 4.

When using particles in ThreeJS, and particurarly THREE.Points class, you should always pass gl_PointCoord to the texture2D as a second argument instead of the uv coordinates.

The working example would be:

THREE.ShaderLib['cloud'] = {
  uniforms: {
    uTexture: { type: "t", value: THREE.ImageUtils.loadTexture("img/cloud.png") }
  },   
  vertexShader: [
    "void main() {",
    "gl_PointSize = 8.0;",
    "gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);",
    "}",
  ].join("\n"),
        
  fragmentShader: [
    "uniform sampler2D uTexture;",
    "void main() {",
    "gl_FragColor = texture2D(uTexture, gl_PointCoord);",
    "}",
  ].join("\n")
};

Upvotes: 1

aryankarim
aryankarim

Reputation: 376

   "varying vec2 vUv;",
        "uniform sampler2D texture;",
        "void main() {",
            "gl_FragColor = texture2D(texture, vUv);", // this line
        "}",

As of 2024, this line right there causes an error, because the name texture is reserved by another function in the fragment in threejs's shader material.

Upvotes: 0

blindepl
blindepl

Reputation: 287

So, after some time I have found a solution for this specific problem. I need to move my uniforms from shader.js directly to place where i'm creating shader material. This is enough to fix problem with my texture, but still I don't know why previous code doesn't work. Working shader material looks like this:

 var _material = new THREE.ShaderMaterial({
      fragmentShader: cloudShader.fragmentShader,
      vertexShader: cloudShader.vertexShader,
      uniforms: uniforms: {
        texture: { type: "t", value: THREE.ImageUtils.loadTexture("img/cloud.png") }
      },
 });   

Upvotes: 4

Related Questions