lamina icon indicating copy to clipboard operation
lamina copied to clipboard

Add mask layers

Open supermoos opened this issue 2 years ago • 7 comments

Hi, is it possible to make a layer that's last in line in the fragment shader renderer. The reason I ask is because I'm trying to create a an AlphaGradient Layer, essentially the same as the Gradient layer, except it works as a "mask" for the whole object, so you should be able to use it to fade out an object selectively using the same params as you use to control the Gradient Layer.

Here's a test were I just tried hardcoding the alpha value to be 0.0 to make it invisible, however this quick test revealed that the alpha value doesn't seem to propegate / override the main material?

import { Abstract } from 'lamina/vanilla'

export default class AlphaGradient extends Abstract {
  static u_colorA = 'white'
  static u_colorB = 'black'
  static u_alpha = 1

  static u_start = 1
  static u_end = -1
  static u_contrast = 1

  static vertexShader = `
		varying vec3 v_position;

		vod main() {
      v_position = lamina_mapping_template;
		}
  `

  static fragmentShader = `
    uniform vec3 u_colorA;
    uniform vec3 u_colorB;
    uniform vec3 u_axis;
    uniform float u_alpha;
    uniform float u_start;
    uniform float u_end;
    uniform float u_contrast;

		varying vec3 v_position;

    void main() {

      float f_step = smoothstep(u_start, u_end, v_position.axes_template * u_contrast);
      vec3 f_color = mix(u_colorA, u_colorB, f_step);

      return vec4(f_color, 0.0);
    }
  `

  axes: 'x' | 'y' | 'z' = 'x'
  mapping: 'local' | 'world' | 'uv' = 'local'

  constructor(props?) {
    super(
      AlphaGradient,
      {
        name: 'AlphaGradient',
        ...props,
      },
      (self: AlphaGradient) => {
        self.schema.push({
          value: self.axes,
          label: 'axes',
          options: ['x', 'y', 'z'],
        })

        self.schema.push({
          value: self.mapping,
          label: 'mapping',
          options: ['uv', 'world', 'local'],
        })

        const mapping = AlphaGradient.getMapping(self.mapping)

        self.vertexShader = self.vertexShader.replace('lamina_mapping_template', mapping || 'local')
        self.fragmentShader = self.fragmentShader.replace('axes_template', self.axes || 'x')
      }
    )
  }

  private static getMapping(type?: string) {
    switch (type) {
      default:
      case 'local':
        return `position`
      case 'world':
        return `(modelMatrix * vec4(position,1.0)).xyz`
      case 'uv':
        return `vec3(uv, 0.)`
    }
  }
}

supermoos avatar Apr 29 '22 07:04 supermoos

Nope the alpha for all layers along with the base material must be <0 for the overall material to be transparent. Masking is currently not supported. PRs are welcome though 😊

FarazzShaikh avatar Apr 29 '22 09:04 FarazzShaikh

Got it! do you mean <1 ?

supermoos avatar Apr 29 '22 09:04 supermoos

Ah yes sorry! <1 Oops 😅

FarazzShaikh avatar Apr 29 '22 09:04 FarazzShaikh

Could you give me a pointer on how to start something like an override layer, i.e. a layer that runs last in the shader and can modify the final color output?

supermoos avatar Apr 29 '22 10:04 supermoos

For a layer to appear last it needs to be composed laast in the layer stack.

In react:

<LayerMaterial>
    { /* Some other layers */ }
    <YourLastLayer />
</LayerMaterial>

In vanialla:

new LayerMaterial({
    layers: [
        // Some other layers
        new YourLastLayer()
    ]
})

With the nomal blend mode, the last layer will override all the previous ones

FarazzShaikh avatar Apr 29 '22 10:04 FarazzShaikh

Right, but it only overrides the previous layers right, not the basematerial or did I miss something?

supermoos avatar Apr 29 '22 10:04 supermoos

If you use the basic (default) lighting mode then yeah it will override the base material. In other lighting modes there's shading, so you can think of it only overriding the Diffuse color.

Please reach out on the pmndrs discord for discussions/questions. Link is in the readme

FarazzShaikh avatar Apr 29 '22 10:04 FarazzShaikh