Shaders 2d Planet shader?

J

Jasnsathome

Guest
I am trying to figure out how to use shaders to make a 2d texture appear as a sphere with a shadow. I found this example that is exactly what I want and tried to make it work in gamemaker but am having problems.
http://clockworkchilli.com/blog/2_3d_shaders_in_a_2d_world
This is my first try at shaders so I do not understand much of it I have been reading tutorials and xors examples but cannot figure out how to make it work right. It will compile and display a square and the lighting part somwhat but the texture displays like a single pixel takes up the whole square.
this is what I have for the fragment and I haven't changed the vertex at all yet.
Code:
uniform float iTime;
uniform sampler2D iTex;
uniform vec3 lightDir; 
uniform vec2 iCoord;

const float PI = 3.14159265358;
vec3 l = normalize(lightDir);
vec2 uv = iCoord.xy;
float radius = length(uv);
vec3 normal = vec3(uv.x, uv.y, sqrt(1. - uv.x*uv.x - uv.y*uv.y));
float ndotl = max(0., dot(normal, l));
float rot = iTime * 0.1;
vec2 texCoords = vec2(0.5 + atan(normal.x, normal.z) / (2.*PI) + rot, asin(normal.y) / PI - 0.5);
vec3 texColor = texture2D(iTex, texCoords, 0.).xyz;
vec3 lightColor = vec3(ndotl) * texColor;
vec4 inside = vec4(lightColor, 1.);
vec4 outside = vec4(0.);
void main()
    {
    gl_FragColor = radius <= 1.? inside: outside;
    }
Does any of this go into the Vertex segment? Do I need to use the inPosition.xy for the fragment part?
If the problem is apparent to someone experienced I would appreciate any help. I'm going to continue to figure out what everything is doing. Thanks.
 
Other than the normalizing of the light direction, I think you want to move all the code below that into the main function.

Here's an alternate version I just tested in gamemaker. You can compare and contrast the two shaders:
Code:
varying vec2 v_vTexcoord;

uniform mat4 rotation;  //rotation matrix (use matrix_build, and pass it in as a uniform float array
uniform sampler2D planet_tex; //planet texture

#define PID2    1.5707963       // PI/2
#define PI      3.1415629
#define TWOPI   6.2831853       // 2PI

vec3 light = vec3(5.0,1.0,3.0);  //light direction (and intensity), you'll probably want to pass in as uniform

void main()
{
        vec2 A = 2.0 * v_vTexcoord - 1.0;                                   //remap texcoord to range -1 to 1.
        float D = dot(A,A);                                                           //get distance^2 of this point from center of planet image (distance^2 of 1 = planet radius)
        vec4 P = vec4(A,sqrt(1.0 - D),1.0);                                          //point on the sphere
        float L = clamp(dot(light,P.xyz),0.1,1.0);                                             //0.1 = min lighting, 1.0 = max lighting
        P *= rotation;                                                                             //rotate planet (move this line 1 line up if you want lighting to rotate with planet).
        vec2 UV = vec2((atan(P.x, P.z) + PI) / TWOPI, (asin(P.y) + PID2) / PI);
        gl_FragColor = vec4(texture2D(planet_tex, UV).xyz * L, float(D < 1.0));             //pixels outside radius will have zero alpha
}

I think you'd be better off just drawing a 3d sphere, the math for doing it in 2d on a per-pixel basis is kind of expensive. Although drawing fewer pixels = less of a burden. But also, this only does orthographic projection, perspective would be even more taxing. Note: planet_tex must be checkmarked used for 3d, or else you'll need to pass in the uv coordinates of that texture into the shader, and do a small bit of math to convert them into the range 0 to 1.
 
Last edited:
J

Jasnsathome

Guest
Thanks you very much for providing such a detailed example and post it works just like I hoped. I've learned more today tinkering with it than I have all week. I'm glad you explained the matrix thing I actually understand the matrix and vector thing now it was hard to wrap my head around it. Thank again you for your time.
 
Dear all,
I have recently been on an epic learning-journey on shaders, and while I am still a novice, my ardent need and desire is to perfect the execution of a planet shader.

I have tried with a "tri-planar" method, but then the texture repeats itself in 3 places, which is in many cases undesirable.
I am thinking the method above might be suitable, but I have problems;

1A) I do not understand what needs to be done to pass the uniform mat4 in the above example
1B) Only a shadowed blank grey sphere appears, not my selected texture -- what could I be missing?
2) Creating the atmospheric glow ring --[Got a psuedo ring effect going before on the tri-planar shader, but it wasn't authentic enough]
3) Applying a bump normal/specular map --[I have not yet attempted this, and am not sure where to start. Is it even possible?]

Any help overwhelmingly appreciated.

Sincerely,
Nathan.
 
Hi. I'm using GMS1.4, so my answers will all be for GMS1.4.

1A) you should be able to pass in the rotation matrix like this:
Code:
planet_shader_rotation = shader_get_uniform(planet_shader, "rotation");
rotation_matrix = matrix_build(0,0,0,rot_x, rot_y, rot_z, 1, 1, 1);
shader_set_uniform_f_array(planet_shader_rotation, rotation_matrix);
1B) my shader is written so that the planet image that are on their own texture page, otherwise you will need to use the uvs of the image. I don't know what else could be causing a grey sphere.

2) atmospheric glow is a whole different problem, and frankly I'm trying to find a really good solution as well. I was trying to reverse engineer "precomputed atmospheric scattering" for use in gamemaker, but it is kind of difficult because there aren't very many articles on the subject that explain the math very well for a layman.

3) yes bump/normal/specular mapping can be combined with the shader I wrote above. With a normal map, you will need to transform the normal vector according to the position on the sphere. Here, the shader has been modified to do that:
Code:
    varying vec2 v_vTexcoord;
    uniform mat4 rotation;  //rotation matrix (use matrix_build, and pass it in as a uniform float array
    uniform sampler2D s_map_tex; //planet color texture
    uniform sampler2D s_normal_tex; //normal map
    #define PID2    1.5707963       // PI/2
    #define PI      3.1415629
    #define TWOPI   6.2831853       // 2PI
    const vec3 light = vec3(5.0,1.0,3.0);  //light direction (and intensity), you'll probably want to pass in as uniform
    void main()
    {
            vec2 A = 2.0 * v_vTexcoord - 1.0;        //convert texcoord to range (-1 to 1)
            float D = dot(A,A);                   //distance of this fragment from circle center (actually dist^2)
            vec4 P = vec4(A,sqrt(1.0 - D),1.0);            //point on the sphere (in screen space basically)
            vec3 bitangent = cross(P.xyz, vec3(1.0,0.0,0.0));  //bitangent
            vec3 tangent = cross(P.xyz,bitangent);             //tangent
            mat3 normalMatrix = mat3(tangent,bitangent,P.xyz);  //build rotation matrix for normal vector
            P *= rotation;                                       //rotate planet
            vec2 UV = vec2((atan(P.x, P.z) + PI) / TWOPI, (asin(P.y) + PID2) / PI);   //get uvs for planet texture
            //you may find it necessary to normalize the following vec3 if the colors in the texture aren't already normalized.
            vec3 normalTex = texture2D(s_normal_tex,UV).xyz * 2.0 - 1.0;    //read normal vector from texture
            vec3 normalTransformed = normalMatrix * normalTex;               //transform normal with matrix
            float L = dot(normalTransformed ,light);           //get lighting amount
            gl_FragColor = vec4(texture2D(s_map_tex, UV).xyz * L, float(D < 1.0));     //pixels outside radius are zero alpha
    }
I'm not sure how you would use a bump map, if you are using it to create displacement, you will need to look into that yourself. Specular lighting should be pretty simple if you've figured out how to implement the above stuff.

Note: this shader is starting to get a little expensive, if you were drawing a 3d sphere instead, a lot of this math could be done on a per-vertex rather than per-fragment level, which should make it less expensive.

Also note that this shader draws a sphere with an orthographic projection. If you want a perspective projection, you have to do a little more math.

Also, I unclamped the lighting amount so it can go above 1, which I think makes it more realistic. If the light vector has a magnitude greater than 1, it could cause the image to look washed out.

EDIT: here's the math for a perspective projection. I've commented out the orthographic stuff so you can compare them side-by-side:

Code:
    varying vec2 v_vTexcoord;
    uniform mat4 rotation;  //rotation matrix (use matrix_build, and pass it in as a uniform float array
    uniform sampler2D s_map_tex; //planet color texture
    uniform sampler2D s_normal_tex; //normal map
    //-----------------------------------------
    //used for perspective projection
    uniform float D; //distance_to_planet (distance from planet center to camera)
    uniform float C; //4.0 * (distance_to_planet * distance_to_planet - planet_radius * planet_radius)
    uniform float view_multiple;  //0.5 / tan(pi / 2 - arccos(planet_radius/distance_to_planet))
    //-----------------------------------------
    #define PID2    1.5707963       // PI/2
    #define PI      3.1415629
    #define TWOPI   6.2831853       // 2PI
    vec3 light = vec3(1.2, 0.5, 1.5);  //light direction (and intensity), you'll probably want to pass in as uniform
    void main()
    {
            //orthographic
            //vec2 A = 2.0 * v_vTexcoord - 1.0;        //convert texcoord to range (-1 to 1)
            //float D = dot(A,A);                   //distance of this fragment from circle center (actually dist^2)
            //vec4 P = vec4(A,sqrt(1.0 - D),1.0);            //point on the sphere (in screen space basically)
            //-----------------------------------------
            //perspective ray tracing
            vec3 RAY = normalize(vec3((v_vTexcoord - 0.5), view_multiple));
            float B = -2.0 * D * RAY.z;
            float DISC = B * B - C;
            float T = (-B - sqrt(DISC)) * 0.5;
            vec4 P = vec4(normalize(vec3(RAY.x * T, RAY.y * T, -RAY.z * T + D)), 1.0);
            //----------------------------------------- 
            //computing a matrix to transform normal vector
            vec3 bitangent = cross(P.xyz, vec3(1.0, 0.0, 0.0));
            vec3 tangent = cross(P.xyz, bitangent);
            mat3 normalMatrix = mat3(tangent, bitangent, P.xyz);
            //-----------------------------------------
            //rotate ray traced point and then compute texture UVs for this point
            P *= rotation;                                       //rotate planet
            vec2 UV = vec2((atan(P.x, P.z) + PI) / TWOPI, (asin(P.y) + PID2) / PI);   //get uvs for planet texture
            //-----------------------------------------
            //compute normal lighting
            vec3 normalTex = normalize(texture2D(s_normal_tex, UV).xyz * 2.0 - 1.0);     //read normal vector from texture (needs normalizing if not already normalized)
            vec3 normalTransformed = normalMatrix * normalTex;               //transform normal with matrix
            float L = dot(normalTransformed, light);           //get lighting amount 
            //-----------------------------------------
            //orthographic
            //gl_FragColor = vec4(texture2D(s_map_tex, UV).xyz * L, float(D < 1.0));     //pixels outside radius are zero alpha
            //-----------------------------------------
            //perspective
            gl_FragColor = vec4(texture2D(s_map_tex, UV).xyz * L, float(DISC > 0.0));     //pixels outside radius are zero alpha
    }

This project for GMS1.4 demonstrates all of the above. It's 7MB because of a couple of large textures. https://app.box.com/s/ceizme7by6wcig7l9ojc4310rpsjalp1
 
Last edited:
That's a seriously first class effort in tutoring and example provision right there, flyingsaucerinvasion! Many, many thanks!
It is amazing how many ways there are of approaching something.

Questions/thoughts;
1) What exactly is the purpose of the 2x2 sprite, and scaling that up like that? Why not just draw the original sprite? (Double drawing unnecessary?)

2A) I used Normal Map Online (http://cpetry.github.io/NormalMap-Online/) to generate a normal map for the second planet I added to the project--do you have some brief and practical explanations for what works best?

2B) I added in a 'uniformed' repositionable light source and reduced the darkness gradient/intensity to your project that you can see here (http://imgur.com/a/WRMh4), ---but for planets with their own light source those light sources should ignore the shadow. Any ideas on approach?
For interest's sake, afore mentioned adjusted lighting code here:
float I = 1.05 - 0.9*smoothstep(0.9, -0.3, dot(normalTransformed,normalize(light)));
gl_FragColor = vec4(I,I,I, 1.0) * vec4(texture2D(s_map_tex, UV).xyz * I, float(D < 1.0));

3A) With this shader's approach, is there (technically at least if not visually) "distortion" on this 2:1 texture? If not, is that because it has been corrected beforehand in the texture itself?

3B) I heard you can not wrap a 1:1 texture around a sphere without distortion (unless you use tri planar texture mapping). Is this the case?

4) I have been 'tracking' several games that feature planets, and the good ones always have rotating planets, with this soft glow atmospheric ring. Are these all done in Unity in full 3D, and is this effect beyond the capabilities of 2D graphics programming/Gamemaker? (On the assumption the 3D environment is not used)

I have considered using particle effects or drawing a glowing circle behind and in front of the planet--'manually' calculating the diameter of such a ring beforehand to match the planet's diameter---but it just sounds like a poor man's trade, and there will be issues with depth when multiple layers are used.
There is the option of doing great looking "hand drawn" sprites, but you can't have massive planets and/or rotate these slowly without using massive amounts of memory.

I would like to say again, thank you so much for your support here flyingsaucerinvasion, I have learned a good deal so quickly due to your generosity.
 
Last edited:
Hi again.

1) The 2x2 sprite is just to make scaling of your planet easy. If you want to draw a planet 512 pixels across just draw it at 256x scale. The texture in the 2x2 sprite is not actually used at all, so it shouldn't have any impact on performance (except possibly the fact that its texture page is sent to the gpu), so to minimize texture swaps you could draw the ground or normal texture instead, but you will have to scale it correctly (a little more difficult) you will also need to change the respective reference in the shader to the base texture instead of one of the sampler indexes.

2 A) um... lets see. I set up the shader so that red is the x axis, and positive direction is to the left. green is the y axis, and positive direction is up. blue is z axis, positive is toward screen. For planets I would suggest subtlety. Slopes that are too steep will create sparkly jaggies, and will also cause situations where things are visible way past the shadow terminator, even though they probably shouldn't be. That could be mitigated perhaps by adding cast shadows to the the shader (but those can be expensive).

2B) What is the smoothstep doing here exactly?

3A) There is a small amount of pinching near the poles which may or may not be noticable. I can't really see it in the earth texture. Although there is a seam, because the left and right edges have not been blended correctly (easily fixed). The 2:1 ratio for the texture is not technically necessary but it helps preserve the same level of resolution in both the x and y axes.

3B) Not sure, but with the tri-planar texture, you would still be left with the problem of 45 degree angle bluriness.

4) It is absolutely not beyond the capability of gamemaker. If you switch to drawing a 3d sphere, then you can improve the performance by switching most of the math onto the vertex shader. However, if you keep it all in the fragment shader, then the key performance factor is the number of fragments drawn. As long as the planets aren't too big, any gpu should be able to handle it.

All that being said, I would just rendar a static image and then draw that static image, unless the planet rotation is intense enough to be truely noticable by the player. In reality, the only way you would see a planet rotate, would be if you are zooming past it really quickly or at close range. If you are just drifting around at pretty far range, you wont be able to see it rotating from your perspective.

Atmospheric effects are something I am still working on. Here are a couple of things I'm looking at:

http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter16.html

http://www-ljk.imag.fr/Publications....PUBLI_Article@11e7cdda2f7_f64b69/article.pdf

You can see that the math is kind of difficult (I don't have a lot of math background so I'm struggling). Another thing that is difficult is the fact that some shader functionality doesn't exist in gamemaker, which means I have to find work arounds. For example, no 3d textures in gamemaker, however you can get around that by splitting a 2d texture into multiple "frames".
 
Hey there!

1) That's a really neat idea--to date I have always seen (and been using) the "gm_BaseTexture".

2B) As I move the light around in the scene with the cursor keys, regardless of the rate of change I set in GML step code, the smoothstep is affecting the speed of the light's movement (after a certain positional 'threshold'), and also the circumference of the light itself--which incidentally was initially related to the atmospheric ring attempt I mentioned. But I don't pretend for a minute to fully understand the actual math involved.--EDIT: So I looked up smoothstep, and now I understand how it works, which lead to further advancement on a much better atmospheric ring effect!...will update in future posts. http://www.fundza.com/rman_shaders/smoothstep/

Yes, for more distant planets static sprites will be perfectly fine I think, but there are these scenes where, as you say, there's a large sized planet in close range spinning slowly and I would love to replicate them "cheaply" in 2D.

Yep, 'atmospheric scattering' - beyond me, without question. I'm so awed by all the math wizards such as yourself that take on these endeavours. I wish I was so mathematically gifted.
 
Last edited:
OK! I have been making some good headway into this atmospheric ring! I'm still polishing things around the edges, but I'm almost ready to post a picture/video of the results. The glow and the ring are obviously not going to be scientifically/mathematically accurate like the "atmospheric scattering" you (flyingsaucerinvasion) were talking about, but I think it will be visually acceptable. Standby!
 
S

Sergio Boyko

Guest
Hi again.

1) The 2x2 sprite is just to make scaling of your planet easy. If you want to draw a planet 512 pixels across just draw it at 256x scale. The texture in the 2x2 sprite is not actually used at all, so it shouldn't have any impact on performance (except possibly the fact that its texture page is sent to the gpu), so to minimize texture swaps you could draw the ground or normal texture instead, but you will have to scale it correctly (a little more difficult) you will also need to change the respective reference in the shader to the base texture instead of one of the sampler indexes.

2 A) um... lets see. I set up the shader so that red is the x axis, and positive direction is to the left. green is the y axis, and positive direction is up. blue is z axis, positive is toward screen. For planets I would suggest subtlety. Slopes that are too steep will create sparkly jaggies, and will also cause situations where things are visible way past the shadow terminator, even though they probably shouldn't be. That could be mitigated perhaps by adding cast shadows to the the shader (but those can be expensive).

2B) What is the smoothstep doing here exactly?

3A) There is a small amount of pinching near the poles which may or may not be noticable. I can't really see it in the earth texture. Although there is a seam, because the left and right edges have not been blended correctly (easily fixed). The 2:1 ratio for the texture is not technically necessary but it helps preserve the same level of resolution in both the x and y axes.

3B) Not sure, but with the tri-planar texture, you would still be left with the problem of 45 degree angle bluriness.

4) It is absolutely not beyond the capability of gamemaker. If you switch to drawing a 3d sphere, then you can improve the performance by switching most of the math onto the vertex shader. However, if you keep it all in the fragment shader, then the key performance factor is the number of fragments drawn. As long as the planets aren't too big, any gpu should be able to handle it.

All that being said, I would just rendar a static image and then draw that static image, unless the planet rotation is intense enough to be truely noticable by the player. In reality, the only way you would see a planet rotate, would be if you are zooming past it really quickly or at close range. If you are just drifting around at pretty far range, you wont be able to see it rotating from your perspective.

Atmospheric effects are something I am still working on. Here are a couple of things I'm looking at:

http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter16.html

http://www-ljk.imag.fr/Publications....PUBLI_Article@11e7cdda2f7_f64b69/article.pdf

You can see that the math is kind of difficult (I don't have a lot of math background so I'm struggling). Another thing that is difficult is the fact that some shader functionality doesn't exist in gamemaker, which means I have to find work arounds. For example, no 3d textures in gamemaker, however you can get around that by splitting a 2d texture into multiple "frames".

flyingsaucerinvasion, u r amazing man!!!!!!!!!
 
S

Sergio Boyko

Guest
Hey there!
How to do it that rotate to direction of mouse?
 
S

Sergio Boyko

Guest
In your example a planet rotation with keys "WSAD". I need rotation with direction from planet.xy to mouse.xy.
For example, I clicked on mouse button somewhere in a room and a planet will be rotation with direction from xy to mouse.xy.
Sorry for my English.
 
Last edited by a moderator:
I need this:
So, you want a point on the sphere to point toward the mouse? Try this and see if it gives you good enough results. I don't really know what you're doing, so I'm making some assumptions. Say you were drawing the planet with its center at 128, 128 in the room. Then lets assume the mouse pointer is located at a position 128 pixels "above" the planet, i.e. closer to the viewer (aka camera) than the center of the planet. Then you could get the planet appear to follow the mouse by creating the "rotation" matrix this way.

var _x = darctan2(mouse_x - 128,128);
var _y = darctan2(mouse_y - 128,128);
var _m = matrix_build( 0, 0, 0, _y, -_x, 0, 1, 1, 1 );

pass _m in as the matrix shader uniform.
 
Hi again, the kind of rotation you want is pretty different from anything we've been talking about in this thread so far. In a couple of days I'll have a lot more free time and I might be able to help you at that time.
 
S

Sergio Boyko

Guest
Hi again,
Sorry that could not explain to you right away. I will be grateful to you.
 
Hi again,
Sorry that could not explain to you right away. I will be grateful to you.
Okay, sorry for long wait.

I hope you have gms 1.4, because that's what I wrote all the following for.

I'll show you 4 ways of getting the kind of rotation you want. Two objects use rotation matrices to get the rotations. And two other objects use quaternions. The first one uses built in matrix_build and matrix_multiply functions. The second object uses a script which builds a rotation matrix and uses it to rotate another matrix (this avoids having to create and destroy arrays constantly), the third object uses a quaternion to do the rotation, but converts the present local rotation into a matrix before drawing. The last object uses quaternions to rotation, and instead of converting to a matrix, it just passes a quaternion and a position uniform into a shader, and the shader makes the transformations that way.



By the way, i'm not using the 2d planet shader here, I'm just drawing a sphere using a vertex buffer.

uh, what else? I've only tested with a orthographic projection, with a perspective one, some things will most likely need to be changed, such as the construction of the sphere vertex buffer (because of the y-axis flipping that happens between 2d and 3d projections, also important is where the camera is positioned, for example above or below the xy plane).

here's the project which contains off of that:
https://www.dropbox.com/s/3hzu4eqh2js7muf/matrix_vs_quaternion_rotation.gmz?dl=0

Press arrow keys to move objects around, they should all move in an identical (or very extremely near idential) manner, and rotate in the direction they are moving.
 
Last edited:
S

Sergio Boyko

Guest
Okay, sorry for long wait.

I hope you have gms 1.4, because that's what I wrote all the following for.

I'll show you 4 ways of getting the kind of rotation you want. Two objects use rotation matrices to get the rotations. And two other objects use quaternions. The first one uses built in matrix_build and matrix_multiply functions. The second object uses a script which builds a rotation matrix and uses it to rotate another matrix (this avoids having to create and destroy arrays constantly), the third object uses a quaternion to do the rotation, but converts the present local rotation into a matrix before drawing. The last object uses quaternions to rotation, and instead of converting to a matrix, it just passes a quaternion and a position uniform into a shader, and the shader makes the transformations that way.



By the way, i'm not using the 2d planet shader here, I'm just drawing a sphere using a vertex buffer.

uh, what else? I've only tested with a orthographic projection, with a perspective one, some things will most likely need to be changed, such as the construction of the sphere vertex buffer (because of the y-axis flipping that happens between 2d and 3d projections, also important is where the camera is positioned, for example above or below the xy plane).

here's the project which contains off of that:
https://www.dropbox.com/s/3hzu4eqh2js7muf/matrix_vs_quaternion_rotation.gmz?dl=0

Press arrow keys to move objects around, they should all move in an identical (or very extremely near idential) manner, and rotate in the direction they are moving.
WOW
Very very nice!!!
The most thanks!!!
Yes, I use gms 1.4. I will be testing today.
 
Last edited by a moderator:
S

Sergio Boyko

Guest
Hi,
How do set the shadows and a glare of reflected light for a sphere, if source of light is located in the center of a room and sphere may move anywhere? I tryed to use planet's shader, but it didn't work.
 

Attachments

Continuing my crusade with planet shaders, I finally got around to needing to create my own textures to use on them. I thought I'd leave this information here for anyone wanting to get straight to the chase, without having to hunt around for a tutorial online somewhere. (I found it somewhat hard to find the "perfect" one).
There are two issues; [1] creation of a seamless texture (2:1 ratio), and, [2] correction of "polar pinching" at the poles of the planet

1/3 down the page, this tutorial for Photoshop clearly and concisely deals with the above two issues:
https://forum.kerbalspaceprogram.com/index.php?/topic/165285-planetary-texturing-guide-repository/
 
M

mjadev

Guest
I know it's an old subject but I hope Flyingsaucerinvasion or someone else can explain where the problem comes from.

I try to use shaders to simulate the rotation of a sphere (a billiard ball for example).
To do that, I use the planet shader proposed by FS in message #5 : "This project for GMS1.4 demonstrates all of the above. It's 7MB because of a couple of large textures. https://app.box.com/s/ceizme7by6wcig7l9ojc4310rpsjalp1 "

However, I noticed that a problem appears in a particular case.
When the rotation on the X axis is 90 °, a rotation applied on the Y axis does not give the expected result !

Attached to this post, an image to try to explain the problem.

Here is the code I am using (in GMS2):

FRAGMENT SHADER CODE (vertex shader is not modified)
Code:
//
// Simple passthrough fragment shader
//
varying vec2 v_vTexcoord;
//varying vec4 v_vColour;
   
uniform mat4 rotation;  //rotation matrix (use matrix_build, and pass it in as a uniform float array
uniform sampler2D s_map_tex; //planet color texture

//-----------------------------------------
#define PID2    1.5707963       // PI/2
#define PI      3.1415629
#define TWOPI   6.2831853       // 2PI

void main()
{

    //orthographic
    vec2 A = 2.0 * v_vTexcoord - 1.0;        //convert texcoord to range (-1 to 1)
    float D = dot(A,A);                   //distance of this fragment from circle center (actually dist^2)
    vec4 P = vec4(A,sqrt(1.0 - D),1.0);            //point on the sphere (in screen space basically)

   //rotate ray traced point and then compute texture UVs for this point
   P *= rotation;                                       //rotate planet
   vec2 UV = vec2((atan(P.x, P.z) + PI) / TWOPI, (asin(P.y) + PID2) / PI);   //get uvs for planet texture
     
   //orthographic
    gl_FragColor = vec4(texture2D(s_map_tex, UV).xyz, float(D < 1.0));     //pixels outside radius are zero alpha
}

OBJECT - create event
Code:
xr = 0;
yr = 0;
zr = 0;
shader_draw_sphere_sampler_color = shader_get_sampler_index(shader_draw_sphere, "s_map_tex");
map_tex = sprite_get_texture(sprite_index,0);
shader_draw_sphere_rotation = shader_get_uniform(shader_draw_sphere,"rotation");

OBJECT - step event
Code:
xr += keyboard_check(ord("S")) - keyboard_check(ord("Z"));
yr += keyboard_check(ord("Q")) - keyboard_check(ord("D"));
zr += keyboard_check(ord("A")) - keyboard_check(ord("E"));

OBJECT - draw event
Code:
//rotation angles limits 0-359
xr=scr_wrap(xr, 0, 360); 
yr=scr_wrap(yr, 0, 360);
zr=scr_wrap(zr, 0, 360);
// rotation matrix
rot_mat = matrix_build(0, 0, 0, xr, yr, zr, 1, 1, 1);
shader_set(shader_draw_sphere);
shader_set_uniform_f_array(shader_draw_sphere_rotation, rot_mat);
texture_set_stage(shader_draw_sphere_sampler_color, map_tex);
draw_self();
shader_reset();


NOTES:
The object uses a square sprites (called texture in the image).
The sprite has its own texture page !!
scr_wrap() is a small script to keep angles between 0 and 359, it is also working without using it
 

Attachments

M

mjadev

Guest
I have the feeling that my problem is related to euler's angles limitations (and the gimbal lock effect).
I will have a look to quaternions.
 
Top