Ok thanks @gertkeno again but in the end this was not exactly what I was looking for.
Two reasons:
- I explicitly don’t wanted Billboard to be used since the Particles should be rotating freely in space.
- I needed to write my custom process shader anyway because I wanted special behavior I found quite hard to achieve with only tweeking the standard process material
And in the end it turned out what I was doing before opening this questioning here was actually correct but I messed up in assigning the particles a random value to select one of the signs. (I missed a break statement in a for loop…)
However playing around with the billboard solution and converting the standard shader materials into “code shader” convinced me that I was on the correct way before. So here is how I do it (WARNING: Very ugly prototype code with lot of cleanup potential):
Generate a Random Number between 0.0 and 1.0 in the start function of the particle for each particle. Than I map this number between 0 to number of signs I want and save it in the CUSTOM.w (xyz is already used for other stuff in my shader) and that’s the point where I messed up earlier.
// select randomly which sign this should be (the effect will be in the Mesh Shader Material)
int rand_number = int(rand_from_seed(seed4+uint(TIME))*100.0);
int sign_count = 4;
// group up the random dumber in to equally big ranges based on the sign_count...
for(int i=1; i<= sign_count; i++){
if(rand_number <= (100/sign_count)*i){
CUSTOM.w = float(i-1);
break;
}
}
Then in the Material Shader I read out the CUSTOM.w float value in the Vertex function and save it in a varying so it can be accessed later on in the fragment function.
void vertex() {
sign_number = INSTANCE_CUSTOM.w;
}
In the fragment function I use a overly complicated way to map the UV to the position on that the sign is in a given texture and use that as area as an alpha value.
void fragment() {
EMISSION = glow_color.rgb*glow_power;
ALBEDO = glow_color.rgb;
vec2 uv = UV/float(sign_count/2);
// That makes no cśence because all particles are rendered the same... so what ever the last partikle has as the number will be rendered...
//find offest in the UV based on random sign number
float test = sign_number;
float num_rows=sqrt(float(sign_count));
float row_pos = mod(test, num_rows)/2.0;
float col_pos = floor(test/num_rows)/2.0;
// the col must be shifted...
if(col_pos <= 0.0){
col_pos = num_rows-1.0;
}
else{
col_pos = col_pos-1.0;
}
uv = uv+vec2(col_pos, row_pos);
ALPHA = texture(signes_map, uv).x;
}
Again currently very ugly but at least it is working now. Thank’s again @gertkeno your suggestion at east showed me that what I wanted to archive must be possible some way Maybe some day one unlucky person being as stupid as I was finds this helpful and will save some time
This is the result for now:
Full Code:
Custom Process Material Shader Code:
shader_type particles;
uniform float break_speed : hint_range(0.0, 10.0, 0.1);
uniform vec3 expanse;
uniform float scale_facotr : hint_range(0.0, 10.0, 0.1);
uniform float rotation_speed : hint_range(0.0, 100.0, 0.1);
float rand_from_seed(in uint seed) {
int k;
int s = int(seed);
if (s == 0)
s = 305420679;
k = s / 127773;
s = 16807 * (s - k * 127773) - 2836 * k;
if (s < 0)
s += 2147483647;
seed = uint(s);
return float(seed % uint(65536)) / 65535.0;
}
uint hash(uint x) {
x = ((x >> uint(16)) ^ x) * uint(73244475);
x = ((x >> uint(16)) ^ x) * uint(73244475);
x = (x >> uint(16)) ^ x;
return x;
}
vec3 rotate_vector_x(vec3 v, float angle) {
return vec3(
v.x,
cos(angle)*v.y-sin(angle)*v.z,
sin(angle)*v.y+cos(angle)*v.z);
}
vec3 rotate_vector_y(vec3 v, float angle) {
return vec3(
cos(angle)*v.x+sin(angle)*v.z,
v.y,
sin(angle)*v.x*-1.0+cos(angle)*v.z);
}
vec3 rotate_vector_z(vec3 v, float angle) {
return vec3(
cos(angle)*v.x-sin(angle)*v.y,
sin(angle)*v.x+cos(angle)*v.y,
v.z);
}
// returns a mat3 representing a new basis after rotating to the given direction
mat3 rotate_basis_to(mat4 transform, vec3 direction, vec3 up) {
vec3 r = cross(direction, up);
vec3 t = cross(r, direction);
return mat3(normalize(vec3(r.x, r.y, r.z)), normalize(vec3(t.x, t.y, t.z)), normalize(vec3(direction.x, direction.y, direction.z)));
}
void start() {
// generate a seed for each Velocity direction
uint seed1 = hash(NUMBER + uint(1) + RANDOM_SEED);
uint seed2 = hash(NUMBER + uint(27) + RANDOM_SEED);
uint seed3 = hash(NUMBER + uint(111) + RANDOM_SEED);
uint seed4 = hash(NUMBER + uint(345) + RANDOM_SEED);
// generate a random position around the mid point and save in the custom...
CUSTOM.x = rand_from_seed(seed1)-0.5;
CUSTOM.y = rand_from_seed(seed2)-0.5;
CUSTOM.z = rand_from_seed(seed3)-0.5;
// select randomly which sign this should be (the effect will be in the Mesh Shader Material)
int rand_number = int(rand_from_seed(seed4+uint(TIME))*100.0);
int sign_count = 4;
// group up the random dumber in to equally big ranges based on the sign_count...
for(int i=1; i<= sign_count; i++){
if(rand_number <= (100/sign_count)*i){
CUSTOM.w = float(i-1);
break;
}
}
// set position to center
TRANSFORM[3].xyz = vec3(0.0);
// reset rotation
mat3 basis = rotate_basis_to(TRANSFORM, CUSTOM.xyz, vec3(0.0, 1.0, 0.0));
}
void process() {
// calculate the target_pos from random start pos and expanse and scale factor
vec3 target_pos = vec3(CUSTOM.x*expanse.x, CUSTOM.y*expanse.y, CUSTOM.z*expanse.z)*scale_facotr;
// move particle to target pos if to far away
// and ensure that position is never exactly hit by ceeping velocity at a min speed.
if(distance(TRANSFORM[3].xyz, target_pos) >= 0.05){
VELOCITY = target_pos-TRANSFORM[3].xyz;
}
//rotate the particle around x
//TRANSFORM[1].xyz = rotate_x(TRANSFORM[1].xyz, 5.0*DELTA);
//TRANSFORM[2].xyz = rotate_x(TRANSFORM[2].xyz, 5.0*DELTA);
//TRANSFORM[0].xyz = rotate_y(TRANSFORM[0].xyz, 2.0*DELTA);
//TRANSFORM[2].xyz = rotate_y(TRANSFORM[2].xyz, 2.0*DELTA);
uint seed1 = hash(NUMBER + uint(5) + RANDOM_SEED);
uint seed2 = hash(NUMBER + uint(45) + RANDOM_SEED);
uint seed3 = hash(NUMBER + uint(452) + RANDOM_SEED);
uint seed4 = hash(NUMBER + uint(153) + RANDOM_SEED);
uint seed5 = hash(NUMBER + uint(153) + RANDOM_SEED);
float rot_speed = rotation_speed*rand_from_seed(seed5);
//rotate the particles around y
vec3 rot_point = vec3(rand_from_seed(seed1), rand_from_seed(seed2), rand_from_seed(seed3));
//rot_point = rotate_vector_y(rot_point, rand_from_seed(RANDOM_SEED));
//rot_point = rotate_vector_x(rot_point, rand_from_seed(RANDOM_SEED));
rot_point = rotate_vector_z(rot_point, (1.5*rand_from_seed(seed4)+TIME*clamp(rand_from_seed(RANDOM_SEED), 0.0, 1.0))*rot_speed);
mat3 basis = rotate_basis_to(TRANSFORM, rot_point, vec3(0.0, 1.0, 0.0));
TRANSFORM[0].xyz = basis[0];
TRANSFORM[1].xyz = basis[1];
TRANSFORM[2].xyz = basis[2];
normalize(TRANSFORM[0].xyz);
normalize(TRANSFORM[1].xyz);
normalize(TRANSFORM[2].xyz);
}
Particle Material Custom Shader:
shader_type spatial;
render_mode cull_disabled;
uniform vec4 glow_color : source_color;
uniform float glow_power : hint_range(0.0 , 100.0);
uniform sampler2D signes_map : source_color, filter_linear_mipmap, repeat_enable;
uniform int sign_size;
uniform int sign_count;
varying float sign_number;
void vertex() {
sign_number = INSTANCE_CUSTOM.w;
//VERTEX.x = VERTEX.x+sign_number;
}
void fragment() {
EMISSION = glow_color.rgb*glow_power;
ALBEDO = glow_color.rgb;
vec2 uv = UV/float(sign_count/2);
// That makes no cśence because all particles are rendered the same... so what ever the last partikle has as the number will be rendered...
//find offest in the UV based on random sign number
float test = sign_number;
float num_rows=sqrt(float(sign_count));
float row_pos = mod(test, num_rows)/2.0;
float col_pos = floor(test/num_rows)/2.0;
// the col must be shifted...
if(col_pos <= 0.0){
col_pos = num_rows-1.0;
}
else{
col_pos = col_pos-1.0;
}
uv = uv+vec2(col_pos, row_pos);
ALPHA = texture(signes_map, uv).x;
}
//void light() {
// Called for every pixel for every light affecting the material.
// Uncomment to replace the default light processing function with this one.
//}