Giter Site home page Giter Site logo

Comments (5)

gfcrba avatar gfcrba commented on June 3, 2024 1

Thank you very much. It works like a charm! You saved me a ton of time. Do you have a patreon or smth for small thank you?

from pixi3d.

gfcrba avatar gfcrba commented on June 3, 2024 1

Oh just one notice for ios (at least for 16.4).
uniform vec3 u_Color;
Not used in fragment shader, so it optimise it somehow and reduces uniform buffer so data passing become corrupted.
Hope this will help someone as well.

from pixi3d.

jnsmalm avatar jnsmalm commented on June 3, 2024

Hello and thanks!

For now you need to create a custom material to support this. Maybe I can add this feature in StandardMaterial at a later time.

This is the code for the material (please note that this code will only work when using WebGL 2, let me know if you need to support WebGL 1 as well.):

let vert = `#version 300 es

  precision highp float;

  in vec3 a_Position;

  uniform mat4 u_Model;
  uniform mat4 u_ViewProjection;
  uniform mat4 u_LightViewProjectionMatrix;

  out vec4 v_PositionLightSpace;

  void main() {
    vec4 pos = u_Model * vec4(a_Position, 1.0);
    v_PositionLightSpace = u_LightViewProjectionMatrix * pos;
    gl_Position = u_ViewProjection * u_Model * vec4(a_Position, 1.0);
  }`

let frag = `#version 300 es

  precision highp float;

  in vec4 v_PositionLightSpace;

  out vec4 fragColor;

  uniform vec3 u_Color;
  uniform sampler2D u_ShadowSampler;
  uniform vec4 u_ShadowColor;

  float linstep(float low, float high, float v) {
    return clamp((v-low) / (high-low), 0.0, 1.0);
  }

  float getShadowContribution() {
    vec3 coords = v_PositionLightSpace.xyz / v_PositionLightSpace.w * 0.5 + 0.5;
    if (coords.z < 0.01 || coords.z > 0.99 || coords.x < 0.01 || coords.x > 0.99 || coords.y < 0.01 || coords.y > 0.99) {
        return 1.0;
    }
    vec2 moments = vec2(1.0) - texture(u_ShadowSampler, coords.xy).xy;
    float p = step(coords.z, moments.x);
    float variance = max(moments.y - moments.x * moments.x, 0.00002);
    float d = coords.z - moments.x;
    float pMax = linstep(0.2, 1.0, variance / (variance + d*d));
    return min(max(p, pMax), 1.0);
  }

  void main() {
    float shadow = 1.0 - getShadowContribution();
    vec4 shadowColor = u_ShadowColor * vec4(shadow);
    float shadowAlpha = shadow * shadowColor.a;
    fragColor = vec4(shadowColor.rgb * shadowAlpha, shadowAlpha);
  }`

class TransparentShadowReceiverMaterial extends PIXI3D.Material {
  constructor(shadowCastingLight) {
    super()
    this._shadowCastingLight = shadowCastingLight
    this.shadowColor = new PIXI3D.Color(0, 0, 0, 0.25)
  }

  updateUniforms(mesh, shader) {
    shader.uniforms.u_Model = mesh.worldTransform.array
    shader.uniforms.u_ViewProjection = PIXI3D.Camera.main.viewProjection.array
    shader.uniforms.u_Color = [255, 0, 255]
    if (this._shadowCastingLight) {
      shader.uniforms.u_ShadowSampler = this._shadowCastingLight.shadowTexture
      shader.uniforms.u_LightViewProjectionMatrix = this._shadowCastingLight.lightViewProjection
      shader.uniforms.u_ShadowColor = this.shadowColor.rgba
    }
  }

  createShader() {
    return new PIXI3D.MeshShader(PIXI.Program.from(vert, frag))
  }
}

Here is a complete example:

let app = new PIXI.Application({
  backgroundColor: 0xff00ff, resizeTo: window, antialias: true
})
document.body.appendChild(app.view)

let control = new PIXI3D.CameraOrbitControl(app.view)
control.enableDamping = true

app.loader.add("assets/chromatic/diffuse.cubemap")
app.loader.add("assets/chromatic/specular.cubemap")
app.loader.add("assets/teapot/teapot.gltf")

let vert = `#version 300 es

  precision highp float;

  in vec3 a_Position;

  uniform mat4 u_Model;
  uniform mat4 u_ViewProjection;
  uniform mat4 u_LightViewProjectionMatrix;

  out vec4 v_PositionLightSpace;

  void main() {
    vec4 pos = u_Model * vec4(a_Position, 1.0);
    v_PositionLightSpace = u_LightViewProjectionMatrix * pos;
    gl_Position = u_ViewProjection * u_Model * vec4(a_Position, 1.0);
  }`

let frag = `#version 300 es

  precision highp float;

  in vec4 v_PositionLightSpace;

  out vec4 fragColor;

  uniform vec3 u_Color;
  uniform sampler2D u_ShadowSampler;
  uniform vec4 u_ShadowColor;

  float linstep(float low, float high, float v) {
    return clamp((v-low) / (high-low), 0.0, 1.0);
  }

  float getShadowContribution() {
    vec3 coords = v_PositionLightSpace.xyz / v_PositionLightSpace.w * 0.5 + 0.5;
    if (coords.z < 0.01 || coords.z > 0.99 || coords.x < 0.01 || coords.x > 0.99 || coords.y < 0.01 || coords.y > 0.99) {
        return 1.0;
    }
    vec2 moments = vec2(1.0) - texture(u_ShadowSampler, coords.xy).xy;
    float p = step(coords.z, moments.x);
    float variance = max(moments.y - moments.x * moments.x, 0.00002);
    float d = coords.z - moments.x;
    float pMax = linstep(0.2, 1.0, variance / (variance + d*d));
    return min(max(p, pMax), 1.0);
  }

  void main() {
    float shadow = 1.0 - getShadowContribution();
    vec4 shadowColor = u_ShadowColor * vec4(shadow);
    float shadowAlpha = shadow * shadowColor.a;
    fragColor = vec4(shadowColor.rgb * shadowAlpha, shadowAlpha);
  }`

class TransparentShadowReceiverMaterial extends PIXI3D.Material {
  constructor(shadowCastingLight) {
    super()
    this._shadowCastingLight = shadowCastingLight
    this.shadowColor = new PIXI3D.Color(0, 0, 0, 0.25)
  }

  updateUniforms(mesh, shader) {
    shader.uniforms.u_Model = mesh.worldTransform.array
    shader.uniforms.u_ViewProjection = PIXI3D.Camera.main.viewProjection.array
    shader.uniforms.u_Color = [255, 0, 255]
    if (this._shadowCastingLight) {
      shader.uniforms.u_ShadowSampler = this._shadowCastingLight.shadowTexture
      shader.uniforms.u_LightViewProjectionMatrix = this._shadowCastingLight.lightViewProjection
      shader.uniforms.u_ShadowColor = this.shadowColor.rgba
    }
  }

  createShader() {
    return new PIXI3D.MeshShader(PIXI.Program.from(vert, frag))
  }
}

app.loader.load((_, resources) => {
  PIXI3D.LightingEnvironment.main.imageBasedLighting = new PIXI3D.ImageBasedLighting(
    resources["assets/chromatic/diffuse.cubemap"].cubemap,
    resources["assets/chromatic/specular.cubemap"].cubemap
  )

  let model = app.stage.addChild(
    PIXI3D.Model.from(resources["assets/teapot/teapot.gltf"].gltf))
  model.y = -0.8
  model.meshes.forEach(mesh => {
    mesh.material.exposure = 1.3
  })

  let ground = app.stage.addChild(PIXI3D.Mesh3D.createPlane())
  ground.y = -0.8
  ground.scale.set(10, 1, 10)

  let directionalLight = Object.assign(new PIXI3D.Light(), {
    intensity: 1,
    type: "directional"
  })
  directionalLight.rotationQuaternion.setEulerAngles(25, 120, 0)
  PIXI3D.LightingEnvironment.main.lights.push(directionalLight)

  let shadowCastingLight = new PIXI3D.ShadowCastingLight(
    app.renderer, directionalLight, { shadowTextureSize: 1024, quality: PIXI3D.ShadowQuality.medium })
  shadowCastingLight.softness = 1
  shadowCastingLight.shadowArea = 15

  ground.material = new TransparentShadowReceiverMaterial(shadowCastingLight)

  let pipeline = app.renderer.plugins.pipeline
  pipeline.enableShadows(ground, shadowCastingLight)
  pipeline.enableShadows(model, shadowCastingLight)
})

from pixi3d.

jnsmalm avatar jnsmalm commented on June 3, 2024

Should look like this

image

from pixi3d.

jnsmalm avatar jnsmalm commented on June 3, 2024

No problem!

from pixi3d.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.