Comments (5)
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.
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.
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.
Should look like this
from pixi3d.
No problem!
from pixi3d.
Related Issues (20)
- Sprite3D zIndex is not applied to internal ProjectionSprite zIndex HOT 3
- Error: Extension class must have an extension object HOT 4
- vec3/planes changes errors HOT 2
- Unlit mesh color is brighter than it should be HOT 9
- iOS 16.4 rendering issue HOT 3
- Compile errors when using @pixi/math-extras HOT 3
- 3d Model and ImageBasedLighting visibility issue HOT 5
- Can't load GLTF with shape-keys animations HOT 6
- Textures smaller than 200x200 pixels do not render with Sprite3D HOT 15
- Memory not cleared when destroying models HOT 38
- Not an issue, just greetings! HOT 1
- Boilerplate from create-pixi3d-app fails with PixiJs 7.2.4 HOT 2
- render point clouds HOT 13
- Possible to trim CompositeSprite to make it only fit the rendered object? HOT 14
- Is there a use case for pixi v7? The following code will not work properly in v7 HOT 1
- Support of LODs and map level geometry culling HOT 2
- Crashes with "Unrecognized source type to auto-detect resource" when imported in NodeJS HOT 6
- Crashes with "Could not find dependency: '@pixi/<it varies>' relative to '/node_modules/pixi3d/dist/cjs/pixi5/pixi3d.js" HOT 4
- Support for PixiJS 8 HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from pixi3d.