#Overlaying multiple textures (preferrably without shader)

11 messages · Page 1 of 1 (latest)

sullen drift
#

Hi all!

I'm trying to display a Counter-Strike weapon model. The base texture is grey with wooden accents. On top I want to overlay the texture with the green serpent. Since that has an alpha channel, the base texture should become visible underneath. Just like in the attached image. Additionally I want to add a normal map and an AO map.

I did some extensive googling already and ended up letting AI write a custom shader material, which works, BUT all of the lighting I previously configured will get ignored (e.g. Environment from react-three/drei).

Is there a way to overlay multiple textures without using a shader? (preferred)
Or can I make it that Three.js lighting still affects my model with the custom shader?

Thanks!

(p.s. ignore the different models in the screenshot, you get the idea)

lean roost
#

To include lighting you have to do calculations in MeshStandardMaterial shader before lighting is applied

#

But as to the question itself - nope, it’s not possible to apply multiple textures without a shader

#

Technically what you can do is create a CanvasTexture and paint one texture over another

#

Then apply that canvas texture to the model

#

But that requires UV mapping of all merged textures to be exactly the same

sullen drift
#

Thanks for your quick reply!
I see... I think using a CanvasTexture is not feasable for my case due to some other details. I guess I will have to use a shader then.

#

Do you maybe have an example shader that includes the original lighting? Or some links to resources? I'm new to shaders but willing to get into it.

This is my current AI generated shader:

const texture = useTexture({...})

const fragmentShader = `
  uniform sampler2D uTextureBase;
  uniform sampler2D uTextureSkin;
  uniform sampler2D uNormalMap;
  uniform sampler2D uAoMap;

  uniform vec3 lightDirection;

  varying vec2 vUv;
  varying vec3 vViewPosition;
  varying mat3 vTBN;

  void main() {
    vec4 baseColor = texture2D(uTextureBase, vUv);
    vec4 overlayColor = texture2D(uTextureSkin, vUv);
    float ao = texture2D(uAoMap, vUv).r;

    vec3 color = mix(baseColor.rgb, overlayColor.rgb, overlayColor.a);

    vec3 normalTex = texture2D(uNormalMap, vUv).rgb * 2.0 - 1.0;
    vec3 normal = normalize(vTBN * normalTex);

    float diff = max(dot(normal, normalize(lightDirection)), 0.3);

    color *= diff * ao;

    gl_FragColor = vec4(color, 1.0);
  }
`

const vertexShader = `
  varying vec2 vUv;
  varying vec3 vViewPosition;
  varying mat3 vTBN;

  attribute vec4 tangent;

  void main() {
    vUv = uv;

    vec3 pos = (modelViewMatrix * vec4(position, 1.0)).xyz;
    vViewPosition = -pos;

    vec3 n = normalize(normalMatrix * normal);
    vec3 t = normalize(normalMatrix * tangent.xyz);
    vec3 b = normalize(cross(n, t) * tangent.w);
    vTBN = mat3(t, b, n);

    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
  }
`

const customPaintMaterial = new THREE.ShaderMaterial({
  uniforms: {
    uTextureBase: { value: texture.base },
    uTextureSkin: { value: texture.skin },
    uAoMap: { value: texture.ao },
    uNormalMap: { value: texture.normalMap },
    lightDirection: { value: new THREE.Vector3(0.5, 1.0, 0.3).normalize() },
  },
  vertexShader: vertexShader,
  fragmentShader: fragmentShader,
  lights: false,
})
lean roost
sullen drift
#

Ah I see. Well I guess I'll have to get to work then. Thanks for your time!