Open marcusx2 opened 2 years ago
@yaustar See these bubbles
They are stretched, this only happens if I use Screen Space. I hope this can be fixed soon, I really need to use screen space after all.
If it's an easy patch and you can tell me how I can do it myself, please let me know.
If you have a public project example that showcases the issue, that will really help if you can link it here please
@yaustar Well it's really simple to reproduce the issue. You just need to use the screenspace ScreenSpaceIssue.zip
The sample project has 2 particle systems, one using screenspace and the other isn't, so you can see how the bubbles are stretched on screen space.
Project to reproduce the issue: https://playcanvas.com/editor/scene/1276844
There are issues/questions around how to control the bounds of the particle effects as it seems very small when a child of an element.
This issue is also reproducible in the engine examples when changing the rendering viewport size. The particles stretch based on the aspect ratio of the canvas.
I pray it's an easy fix! Thanks for looking into this @yaustar
Had a quick chat with the team and unfortunately it's not an easy fix unfortunately. In the short term, you would need to implement a workaround. Eg animated UI sprite or a simple particle implementation in the UI space or mapping the UI position to a world space so that the 3D particle system can be moved so that it is always over/under an element
Had a quick chat with the team and unfortunately it's not an easy fix unfortunately. In the short term, you would need to implement a workaround. Eg animated UI sprite or a simple particle implementation in the UI space or mapping the UI position to a world space so that the 3D particle system can be moved so that it is always over/under an element
Do you have an ETA to fix this? It's ok if not, I'd just like to know if there is. It's not an easy fix, but there is a fix right?
Do you have an ETA to fix this? It's ok if not, I'd just like to know if there is. It's not an easy fix, but there is a fix right?
Afraid not. It's not a straight forward 'this is how we do it'. The solution for it is not yet known and in some ways, a new feature.
I can think of workarounds for this that involve layers and a little scripting that I hope to think about later this week
I can think of workarounds for this that involve layers and a little scripting that I hope to think about later this week
Thanks, I very much appreciate it.
The solution for it is not yet known and in some ways, a new feature.
A new feature? Interesting.
A new feature? Interesting.
The scope of work is 'large' and also undefined at the moment
Work around where the VFX follows the element entity and renders on type: https://playcanvas.com/editor/scene/1278415
It renders on top as it relies on the default UI layer clearing the depth buffer.
If you want to render under the UI layer, you will have create a layer for it that renders before the default UI layer but also has clearDepthBuffer enabled: https://developer.playcanvas.com/en/api/pc.Layer.html#clearDepthBuffer
@yaustar is there a workaround where I can dynamically set the scale of the particles based on the rendering viewport size? So basically I cancel out the scaling that is applied.
@yaustar is there a workaround where I can dynamically set the scale of the particles based on the rendering viewport size? So basically I cancel out the scaling that is applied.
Not easily, no. You would have to scale it according it based on the viewport size and how the UI screen scales the elements.
Or you could potentially get the canvas corners of the element that it is following and depending on the size of that, use that to scale the particles relatively: https://developer.playcanvas.com/en/api/pc.ElementComponent.html#canvasCorners
@yaustar is there a workaround where I can dynamically set the scale of the particles based on the rendering viewport size? So basically I cancel out the scaling that is applied.
Not easily, no. You would have to scale it according it based on the viewport size and how the UI screen scales the elements.
Or you could potentially get the canvas corners of the element that it is following and depending on the size of that, use that to scale the particles relatively: https://developer.playcanvas.com/en/api/pc.ElementComponent.html#canvasCorners
Sorry I'm a bit lost on this. As I understand the idea you are talking about is to check the original dimensions of the particles, then check the canvas corners to determine how much it was scaled? Do you have an example? To get the viewport size it's app.graphicsDevice.width; and app.graphicsDevice.height right, or are you talking about something else? Thanks!
I've updated the example above that scales based on the idea above. It's not perfect but gives an idea on the approach
I've made a fix that works perfectly well
var ParticleScalingFix = pc.createScript('particleScalingFix');
/** @type {pc.Vec3}*/
let originalScale;
// initialize code called once per entity
ParticleScalingFix.prototype.initialize = function() {
originalScale = { ...this.entity.getLocalScale() };
this.app.graphicsDevice.on('resizecanvas', this.onResizeCanvas, this);
this.onResizeCanvas(this.app.graphicsDevice.width, this.app.graphicsDevice.height);
};
ParticleScalingFix.prototype.onResizeCanvas = function(w, h) {
this.entity.setLocalScale(originalScale.x, (w/h) * originalScale.y, originalScale.z);
};
Just need to attach the script to the particle system.
@yaustar
I just noticed another problem with using the screen space. If you switch from portrait to landscape, and then from landscape to portrait, the particles start moving differently. This seems to be another issue entirely. Do you think this is worth another bug report?
Check it out: make some particles that goes from the bottom of the screen to the top using screen space. Then, switch screen orientation to landscape and back to portrait. See what happens.
No, not worth a new report as the particles screen space seems to be bugged generally
I've made a fix that works perfectly well
var ParticleScalingFix = pc.createScript('particleScalingFix'); /** @type {pc.Vec3}*/ let originalScale; // initialize code called once per entity ParticleScalingFix.prototype.initialize = function() { originalScale = { ...this.entity.getLocalScale() }; this.app.graphicsDevice.on('resizecanvas', this.onResizeCanvas, this); this.onResizeCanvas(this.app.graphicsDevice.width, this.app.graphicsDevice.height); }; ParticleScalingFix.prototype.onResizeCanvas = function(w, h) { this.entity.setLocalScale(originalScale.x, (w/h) * originalScale.y, originalScale.z); };
Just need to attach the script to the particle system.
Does that work if the UI screen component blend value is not 0.5?
I've made a fix that works perfectly well
var ParticleScalingFix = pc.createScript('particleScalingFix'); /** @type {pc.Vec3}*/ let originalScale; // initialize code called once per entity ParticleScalingFix.prototype.initialize = function() { originalScale = { ...this.entity.getLocalScale() }; this.app.graphicsDevice.on('resizecanvas', this.onResizeCanvas, this); this.onResizeCanvas(this.app.graphicsDevice.width, this.app.graphicsDevice.height); }; ParticleScalingFix.prototype.onResizeCanvas = function(w, h) { this.entity.setLocalScale(originalScale.x, (w/h) * originalScale.y, originalScale.z); };
Just need to attach the script to the particle system.
Does that work if the UI screen component blend value is not 0.5?
I'm using scale mode none. In fact the scale mode doesn't seem to make any difference. It's working perfectly now, except if the user switches the orientation of the phone, then it glitches a bit...but oh well. I think it's good enough now.
I'm using scale mode none. In fact the scale mode doesn't seem to make any difference. It's working perfectly now, except if the user switches the orientation of the phone, then it glitches a bit...but oh well. I think it's good enough now.
It probably looks a bit odd as you are only scaling along one axis (Y)
I'm using scale mode none. In fact the scale mode doesn't seem to make any difference. It's working perfectly now, except if the user switches the orientation of the phone, then it glitches a bit...but oh well. I think it's good enough now.
It probably looks a bit odd as you are only scaling along one axis (Y)
It doesn't look odd, it looks perfect. The scaling issue only happens on the Y axis. That is the formula to compensate for the stretch on the Y. Why don't you try it? You'll see.
Are you using Screen Space and/or Local Space on the particle effect?
Just Screen Space
var ParticleScalingFix = pc.createScript('particleScalingFix');
/** @type {pc.Vec3}*/
let originalScale;
// initialize code called once per entity
ParticleScalingFix.prototype.initialize = function() {
originalScale = { ...this.entity.getLocalScale() };
this.app.graphicsDevice.on('resizecanvas', this.onResizeCanvas, this);
this.onResizeCanvas(this.app.graphicsDevice.width, this.app.graphicsDevice.height);
};
ParticleScalingFix.prototype.onResizeCanvas = function(w, h) {
this.entity.setLocalScale(originalScale.x, (w/h) * originalScale.y, originalScale.z);
this.entity.particlesystem.reset();
};
Calling this.entity.particlesystem.reset();
fixes the issue of the particles behaving weird when switching the orientation of the phone. Now everything works perfectly. This is the definitive fix for screenspace particles. Maybe you can simply incorporate this code in the particleSystem source? Don't forget to try it out.
To see the weird movement behavior I'm talking about, remove the line this.entity.particlesystem.reset();
, then switch from portait to landscape, and back to portrait, and see what happens.
Ok this is weird. I am using different particles now, and I noticed that the scaling can happen on the Y only, or the X and the Y. Probably only on the X as well. So I modified the script to let the user decide what axis he wants to apply the fix after testing.
var ParticleScalingFix = pc.createScript('particleScalingFix');
ParticleScalingFix.attributes.add('scaleY', { type: 'boolean' });
ParticleScalingFix.attributes.add('scaleX', { type: 'boolean' });
/** @type {pc.Vec3}*/
let originalScale;
// initialize code called once per entity
ParticleScalingFix.prototype.initialize = function() {
originalScale = { ...this.entity.getLocalScale() };
this.app.graphicsDevice.on('resizecanvas', this.onResizeCanvas, this);
this.onResizeCanvas(this.app.graphicsDevice.width, this.app.graphicsDevice.height);
};
ParticleScalingFix.prototype.onResizeCanvas = function(w, h) {
this.entity.setLocalScale(this.scaleX ? h > w ? (h/w) * originalScale.x : (w/h) * originalScale.x : originalScale.x, this.scaleY ? (w/h) * originalScale.y : originalScale.y, originalScale.z);
this.entity.particlesystem.reset();
};
In addition, when it needs to be scaled on the x axis, if the height of the viewport is bigger than the width, h/w needs to be used instead of w/h. The y axis is always w/h. I have no idea why it's like this, but it is.
The reset trick doesn't work if I have a random scale. Does the reset not touch the scale of the particles? T_T. Another bug, this one I couldn't fix. If you have random scales, and switch from potrait to landscape, and then back to portrait, the particles become super small.
Another bug, this one I couldn't fix. If you have random scales, and switch from potrait to landscape, and then back to portrait, the particles become super small.
Sounds like a separate issue with particles. Can you please post in the engine repo with a example project and steps to reproduce the issue?
I can't reproduce the issue without screen space mode. I don't think it's a completely unrelated issue. On another note, do you know how can I check the width and height of the image being used by the particle system? Something like particleSystem.image.width
You can get the texture that the particle system is using via https://developer.playcanvas.com/en/api/pc.ParticleSystemComponent.html#colorMap
However, I don't think it affects the render size and it's done via entity scale and particle scale graph
It does affect how the stretching happens. If the width is bigger than the height, it stretches on the x and y. Otherwise, it stretches only in the y axis. No need to have user input to decide how to fix the stretch. Here's the updated code:
var ParticleScalingFix = pc.createScript('particleScalingFix');
/** @type {pc.Vec3}*/
let originalScale;
// initialize code called once per entity
ParticleScalingFix.prototype.initialize = function() {
originalScale = { ...this.entity.getLocalScale() };
this.app.graphicsDevice.on('resizecanvas', this.onResizeCanvas, this);
this.onResizeCanvas(this.app.graphicsDevice.width, this.app.graphicsDevice.height);
};
ParticleScalingFix.prototype.onResizeCanvas = function(w, h) {
if (this.entity.particlesystem.colorMap.width > this.entity.particlesystem.colorMap.height)
this.entity.setLocalScale(h > w ? (h/w) * originalScale.x : (w/h) * originalScale.x, (w/h) * originalScale.y, originalScale.z);
else {
this.entity.setLocalScale(originalScale.x, (w/h) * originalScale.y, originalScale.z);
}
this.entity.particlesystem.reset();
};
@yaustar Hey yaustar nevermind. The bug of the particles getting super small was my fault. The originalScale variable needs to be in the prototype, otherwise it acts as a global variable that all particleScalingFix can access, instead of being a unique instance of the variable per script. Interesting. Here is the final script, this time I'm having no issues, tested with different particles of different heights and widths.
var ParticleScalingFix = pc.createScript('particleScalingFix');
/** @type {pc.Vec3}*/
ParticleScalingFix.prototype.originalScale = 0;
// initialize code called once per entity
ParticleScalingFix.prototype.initialize = function() {
this.originalScale = { ...this.entity.getLocalScale() };
this.app.graphicsDevice.on('resizecanvas', this.onResizeCanvas, this);
this.onResizeCanvas(this.app.graphicsDevice.width, this.app.graphicsDevice.height);
};
ParticleScalingFix.prototype.onResizeCanvas = function(w, h) {
if (this.entity.particlesystem.colorMap.width > this.entity.particlesystem.colorMap.height) {
this.entity.setLocalScale(h > w ? (h/w) * this.originalScale.x : (w/h) * this.originalScale.x, (w/h) * this.originalScale.y, this.originalScale.z);
}
else {
this.entity.setLocalScale(this.originalScale.x, (w/h) * this.originalScale.y, this.originalScale.z);
}
this.entity.particlesystem.reset();
};
Just a reminder: when it needs to be scaled on the x axis, if the height of the viewport is bigger than the width, h/w needs to be used instead of w/h. The y axis is always w/h. I have no idea why it's like this, but it is.
If the width of the image is bigger than the height, the fix needs to be applied to the x and y axis, otherwise only the y.
FYI, you don't need this line:
/** @type {pc.Vec3}*/
ParticleScalingFix.prototype.originalScale = 0;
You think you can take a look at my patch? I wouldn't mind if this was used to fix screen space instead of a super complex solution.
It's all recorded here in the ticket so the engine team can consider it when it comes to working on this issue.
If you choose Screen Space for the particle system and put it under a Screen Entity, the particles will stretch and behave differently than if it was outside the Screen Entity and not using Screen Space. Furthermore, Local Space doesn't work in combination with Screen Space. If I create a group under the Screen Entity, anchor said group to the bottom of the screen, and place the particle system under the group, the particle system won't be anchored to the bottom of the screen, for example.
TL;DR