In order to speed up the solution to the problem from this thread, i have created a request for a feature: https://github.com/defold/defold/issues/6820
Please, support this request if you think i am right.
I’m now in a need for a billboard solution for sprite (and particles) in 3D world. I tried writing my own function that rotates the sprite towards camera position, but I am failing miserably all the time
Do you guys have any working solution for sprites and how to use it?
Sprites should be easy now with custom vertex attributes + setting attribute data together with go.set. Particles is more difficult since we don’t have support for the setting, but it’s not impossible. You need to pass the center position of the primitive into the shader, perhaps a texture or something?
What I wish to achieve is this effect (without changing sprite’s animation, I will be only slightly moving camera)
The example from the @Pkeod Defold Shaders is as follows:
// Positions can be world or local space, since world and normal
// matrices are identity for world vertex space materials.
// If world vertex space is selected, you can remove the
// normal matrix multiplication for optimal performance.
attribute highp vec4 position;
attribute mediump vec2 texcoord0;
attribute mediump vec3 normal;
uniform mediump mat4 mtx_worldview;
uniform mediump mat4 mtx_view;
uniform mediump mat4 mtx_proj;
uniform mediump mat4 mtx_normal;
uniform mediump vec4 light;
varying highp vec4 var_position;
varying mediump vec3 var_normal;
varying mediump vec2 var_texcoord0;
varying mediump vec4 var_light;
void main()
{
mat4 original_matrix = mtx_worldview;
mat4 model_view;
model_view[0] = vec4(length(original_matrix[0].xyz), 0.0, 0.0, 0.0);
model_view[1] = vec4(0.0, length(original_matrix[1].xyz), 0.0, 0.0);
model_view[2] = vec4(0.0, 0.0, length(original_matrix[2].xyz), 0.0);
model_view[3] = original_matrix[3];
vec4 p = model_view * position;
var_light = mtx_view * vec4(light.xyz, 1.0);
var_position = p;
var_texcoord0 = texcoord0;
var_normal = normalize((mtx_normal * vec4(normal, 0.0)).xyz);
gl_Position = mtx_proj * p;
}
With modified to be simpler fp:
varying highp vec4 var_position;
varying mediump vec3 var_normal;
varying mediump vec2 var_texcoord0;
varying mediump vec4 var_light;
uniform lowp sampler2D tex0;
uniform lowp vec4 tint;
void main()
{
// Pre-multiply alpha since all runtime textures already are
vec4 tint_pm = vec4(tint.xyz * tint.w, tint.w);
gl_FragColor = texture2D(tex0, var_texcoord0.xy) * tint_pm;
}
And it’s slightly ok, but it’s on a model and I don’t know how to make transparent pixels transparent and how to rotate it’s initial texture:
This I don’t understand:
Camera is not rotating in my game, but is slightly tilted and is only moving around (changing only position)
I think @Dragosha has an example somewhere, not sure.
I saw something in this issue True Billboards for 3D (label, sprite, particles components) · Issue #6820 · defold/defold · GitHub
vp hsader:
gl_Position = (view_proj * vec4(position.xyz - local_position.xyz, 1.0)) + (proj * vec4(local_position.xy, 0.0, 0.0));
materials:
attributes {
name: "local_position"
semantic_type: SEMANTIC_TYPE_POSITION
element_count: 3
normalize: false
data_type: TYPE_FLOAT
coordinate_space: COORDINATE_SPACE_LOCAL
double_values {
v: 0.0
v: 0.0
v: 0.0
}
}
Yes, this is the optimised version with full billboard (all axes)
Another variant:
here we remove the y-axis rotation towards the camera
highp vec4 base = vec4(position.x - local_position.x, position.y, position.z - local_position.z, 1.0);
highp vec4 local_pos = vec4(position.x - base.x, position.y - base.y, 0.0, 0.0);
gl_Position = (view_proj * base) + (proj * local_pos);
Thank you!
I started from model.material, added local_position
as Vertex Attribute as defined by @AGulev .
I guess it will be a position of the billboard object, that I will need to set from script:
go.set(url, "local_position", go.get_position(url))
So for test, I set this material to the model, but I don’t see a texture in Editor, but it’s definitely behaving like billboard when rotated:
fp is simplified, maybe here is an erro?
varying highp vec4 var_position;
varying mediump vec3 var_normal;
varying mediump vec2 var_texcoord0;
varying mediump vec4 var_light;
uniform lowp sampler2D tex0;
uniform lowp vec4 tint;
void main()
{
// Pre-multiply alpha since all runtime textures already are
vec4 tint_pm = vec4(tint.xyz * tint.w, tint.w);
gl_FragColor = texture2D(tex0, var_texcoord0.xy) * tint_pm;
}
EDIT. Oh! And I noticed, you use this material on sprites @Dragosha !
you don’t need to set local_position
variable from script.
also in your shader missed var_texcoord0 = texcoord0;
(throw UV coordinate from vertex shader to fragment shader)
Thank you!
It solves my issue
What is it then?
Here is an atricle how it works:
SEMANTIC_TYPE_POSITION automatically setting up by engine.
But I’m not sure that it works with the model component. I tested only with sprites and particles. (model billboard? why?)
Thank you!
No particular reason, I just tend to start every shader play with a model component, since I usually was using some data from textures, but here it’s just out of habit
My game needs label and sprite billboards. With the help from this thread and pointers by @ackle on Discord I’ve managed to create materials for sprites and particles. Thanks!
One thing left - for some reason labels don’t want to billboard properly:
Are there additional considerations for labels when it comes to making them billboards?
A minimal example with the materials used in the video:
Billboard.zip (110.0 KB)
Our text system generates a single quad for each glyph.
I’m assuming you are looking to billboard the entire label, in order to keep the text legible, I’d recommend rotating the label itself.
Okay, that makes sense. Now we’re getting somewhere!
There is something going on with the distance field label for the extreme angles of rotation. This won’t be an issue in my game, but curious as to why it happens?
Billboard.zip (110.1 KB)
Yes, i also get same issue with df font.
I use set_rotation not shader for billboard.
So it is issue for df not billboard.
What if you add log for camera angle? Which angle is break df?
Something wrong with euler.y around 90 and 270
local euler_x = camera.rotation_euler.x
local euler_y = camera.rotation_euler.y
local euler_z = camera.rotation_euler.z
euler_y = LUME.angle_min_deg(euler_y)
local dy_y_1 = math.abs(90 - euler_y)
local dy_y_2 = math.abs(270 - euler_y)
euler_y = dy_y_1 < dy_y_2 and dy_y_1 or dy_y_2
if math.abs(euler_x) + math.abs(euler_z) > 7 or euler_y > 7 then
xmath.quat(camera.rotation_billboard_gui, camera.rotation)
else
xmath.vector3_set_components(TEMP_V, camera.rotation_euler.x + 12, camera.rotation_euler.y, camera.rotation_euler.z)
xmath.euler_to_quat(camera.rotation_billboard_gui, TEMP_V)
end
Thanks for repro case. I make issue:)