Drawing a sphere normal map in the fragment shader










2














I'm trying to draw a simple sphere with normal mapping in the fragment shader with GL_POINTS. At present, I simply draw one point on the screen and apply a fragment shader to "spherify" it.



However, I'm having trouble colouring the sphere correctly (or at least I think I am). It seems that I'm calculating the z correctly but when I apply the 'normal' colours to gl_FragColor it just doesn't look quite right (or is this what one would expect from a normal map?). I'm assuming there is some inconsistency between gl_PointCoord and the fragment coord, but I can't quite figure it out.



Vertex shader



precision mediump float;

attribute vec3 position;

void main()
gl_PointSize = 500.0;
gl_Position = vec4(position.xyz, 1.0);



fragment shader



precision mediump float;

void main()

float x = gl_PointCoord.x * 2.0 - 1.0;
float y = gl_PointCoord.y * 2.0 - 1.0;

float z = sqrt(1.0 - (pow(x, 2.0) + pow(y, 2.0)));

vec3 position = vec3(x, y, z);

float mag = dot(position.xy, position.xy);
if(mag > 1.0) discard;

vec3 normal = normalize(position);

gl_FragColor = vec4(normal, 1.0);



Actual output:



enter image description here



Expected output:



enter image description here










share|improve this question


























    2














    I'm trying to draw a simple sphere with normal mapping in the fragment shader with GL_POINTS. At present, I simply draw one point on the screen and apply a fragment shader to "spherify" it.



    However, I'm having trouble colouring the sphere correctly (or at least I think I am). It seems that I'm calculating the z correctly but when I apply the 'normal' colours to gl_FragColor it just doesn't look quite right (or is this what one would expect from a normal map?). I'm assuming there is some inconsistency between gl_PointCoord and the fragment coord, but I can't quite figure it out.



    Vertex shader



    precision mediump float;

    attribute vec3 position;

    void main()
    gl_PointSize = 500.0;
    gl_Position = vec4(position.xyz, 1.0);



    fragment shader



    precision mediump float;

    void main()

    float x = gl_PointCoord.x * 2.0 - 1.0;
    float y = gl_PointCoord.y * 2.0 - 1.0;

    float z = sqrt(1.0 - (pow(x, 2.0) + pow(y, 2.0)));

    vec3 position = vec3(x, y, z);

    float mag = dot(position.xy, position.xy);
    if(mag > 1.0) discard;

    vec3 normal = normalize(position);

    gl_FragColor = vec4(normal, 1.0);



    Actual output:



    enter image description here



    Expected output:



    enter image description here










    share|improve this question
























      2












      2








      2







      I'm trying to draw a simple sphere with normal mapping in the fragment shader with GL_POINTS. At present, I simply draw one point on the screen and apply a fragment shader to "spherify" it.



      However, I'm having trouble colouring the sphere correctly (or at least I think I am). It seems that I'm calculating the z correctly but when I apply the 'normal' colours to gl_FragColor it just doesn't look quite right (or is this what one would expect from a normal map?). I'm assuming there is some inconsistency between gl_PointCoord and the fragment coord, but I can't quite figure it out.



      Vertex shader



      precision mediump float;

      attribute vec3 position;

      void main()
      gl_PointSize = 500.0;
      gl_Position = vec4(position.xyz, 1.0);



      fragment shader



      precision mediump float;

      void main()

      float x = gl_PointCoord.x * 2.0 - 1.0;
      float y = gl_PointCoord.y * 2.0 - 1.0;

      float z = sqrt(1.0 - (pow(x, 2.0) + pow(y, 2.0)));

      vec3 position = vec3(x, y, z);

      float mag = dot(position.xy, position.xy);
      if(mag > 1.0) discard;

      vec3 normal = normalize(position);

      gl_FragColor = vec4(normal, 1.0);



      Actual output:



      enter image description here



      Expected output:



      enter image description here










      share|improve this question













      I'm trying to draw a simple sphere with normal mapping in the fragment shader with GL_POINTS. At present, I simply draw one point on the screen and apply a fragment shader to "spherify" it.



      However, I'm having trouble colouring the sphere correctly (or at least I think I am). It seems that I'm calculating the z correctly but when I apply the 'normal' colours to gl_FragColor it just doesn't look quite right (or is this what one would expect from a normal map?). I'm assuming there is some inconsistency between gl_PointCoord and the fragment coord, but I can't quite figure it out.



      Vertex shader



      precision mediump float;

      attribute vec3 position;

      void main()
      gl_PointSize = 500.0;
      gl_Position = vec4(position.xyz, 1.0);



      fragment shader



      precision mediump float;

      void main()

      float x = gl_PointCoord.x * 2.0 - 1.0;
      float y = gl_PointCoord.y * 2.0 - 1.0;

      float z = sqrt(1.0 - (pow(x, 2.0) + pow(y, 2.0)));

      vec3 position = vec3(x, y, z);

      float mag = dot(position.xy, position.xy);
      if(mag > 1.0) discard;

      vec3 normal = normalize(position);

      gl_FragColor = vec4(normal, 1.0);



      Actual output:



      enter image description here



      Expected output:



      enter image description here







      glsl webgl






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Nov 12 '18 at 23:13









      LesbaaLesbaa

      11816




      11816






















          2 Answers
          2






          active

          oldest

          votes


















          1














          The color channels are clamped to the range [0, 1]. (0, 0, 0) is black and (1, 1, 1) is completely white.



          Since the normal vector is normalized, its component are in the range [-1, 1].
          To get the expected result you have to map the normal vector from the range [-1, 1] to [0, 1]:



          vec3 normal_col = normalize(position) * 0.5 + 0.5;
          gl_FragColor = vec4(normal_col, 1.0);




          If you use the abs value, then a positive and negative value with the same size have the same color representation. The intensity of the color increases with the grad of the value:



          vec3 normal_col = abs(normalize(position));
          gl_FragColor = vec4(normal_col, 1.0);







          share|improve this answer




















          • I had experimented with 0.5 + 0.5 and it seemed to work correctly, but I didn't know why it was the case and thought I was just chucking numbers in there without any reason. Thanks for your explanation!
            – Lesbaa
            Nov 13 '18 at 9:59


















          0














          First of all, the normal facing the camera [0,0,-1] should be rgb values: [0.5,0.5,1.0]. You have to rescale things to move those negative values to be between 0 and 1.



          Second, the normals of a sphere would not change linearly, but in a sine wave. So you need some trigonometry here. It makes sense to me to to start with the perpendicular normal [0,0,-1] and then then rotate that normal by an angle, because that angle is what changing linearly.



          As a result of playing around this I came up with this:



          http://glslsandbox.com/e#50268.3



          which uses some rotation function from here: https://github.com/yuichiroharai/glsl-y-rotate






          share|improve this answer




















            Your Answer






            StackExchange.ifUsing("editor", function ()
            StackExchange.using("externalEditor", function ()
            StackExchange.using("snippets", function ()
            StackExchange.snippets.init();
            );
            );
            , "code-snippets");

            StackExchange.ready(function()
            var channelOptions =
            tags: "".split(" "),
            id: "1"
            ;
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function()
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled)
            StackExchange.using("snippets", function()
            createEditor();
            );

            else
            createEditor();

            );

            function createEditor()
            StackExchange.prepareEditor(
            heartbeatType: 'answer',
            autoActivateHeartbeat: false,
            convertImagesToLinks: true,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: 10,
            bindNavPrevention: true,
            postfix: "",
            imageUploader:
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            ,
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            );



            );













            draft saved

            draft discarded


















            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53271461%2fdrawing-a-sphere-normal-map-in-the-fragment-shader%23new-answer', 'question_page');

            );

            Post as a guest















            Required, but never shown

























            2 Answers
            2






            active

            oldest

            votes








            2 Answers
            2






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes









            1














            The color channels are clamped to the range [0, 1]. (0, 0, 0) is black and (1, 1, 1) is completely white.



            Since the normal vector is normalized, its component are in the range [-1, 1].
            To get the expected result you have to map the normal vector from the range [-1, 1] to [0, 1]:



            vec3 normal_col = normalize(position) * 0.5 + 0.5;
            gl_FragColor = vec4(normal_col, 1.0);




            If you use the abs value, then a positive and negative value with the same size have the same color representation. The intensity of the color increases with the grad of the value:



            vec3 normal_col = abs(normalize(position));
            gl_FragColor = vec4(normal_col, 1.0);







            share|improve this answer




















            • I had experimented with 0.5 + 0.5 and it seemed to work correctly, but I didn't know why it was the case and thought I was just chucking numbers in there without any reason. Thanks for your explanation!
              – Lesbaa
              Nov 13 '18 at 9:59















            1














            The color channels are clamped to the range [0, 1]. (0, 0, 0) is black and (1, 1, 1) is completely white.



            Since the normal vector is normalized, its component are in the range [-1, 1].
            To get the expected result you have to map the normal vector from the range [-1, 1] to [0, 1]:



            vec3 normal_col = normalize(position) * 0.5 + 0.5;
            gl_FragColor = vec4(normal_col, 1.0);




            If you use the abs value, then a positive and negative value with the same size have the same color representation. The intensity of the color increases with the grad of the value:



            vec3 normal_col = abs(normalize(position));
            gl_FragColor = vec4(normal_col, 1.0);







            share|improve this answer




















            • I had experimented with 0.5 + 0.5 and it seemed to work correctly, but I didn't know why it was the case and thought I was just chucking numbers in there without any reason. Thanks for your explanation!
              – Lesbaa
              Nov 13 '18 at 9:59













            1












            1








            1






            The color channels are clamped to the range [0, 1]. (0, 0, 0) is black and (1, 1, 1) is completely white.



            Since the normal vector is normalized, its component are in the range [-1, 1].
            To get the expected result you have to map the normal vector from the range [-1, 1] to [0, 1]:



            vec3 normal_col = normalize(position) * 0.5 + 0.5;
            gl_FragColor = vec4(normal_col, 1.0);




            If you use the abs value, then a positive and negative value with the same size have the same color representation. The intensity of the color increases with the grad of the value:



            vec3 normal_col = abs(normalize(position));
            gl_FragColor = vec4(normal_col, 1.0);







            share|improve this answer












            The color channels are clamped to the range [0, 1]. (0, 0, 0) is black and (1, 1, 1) is completely white.



            Since the normal vector is normalized, its component are in the range [-1, 1].
            To get the expected result you have to map the normal vector from the range [-1, 1] to [0, 1]:



            vec3 normal_col = normalize(position) * 0.5 + 0.5;
            gl_FragColor = vec4(normal_col, 1.0);




            If you use the abs value, then a positive and negative value with the same size have the same color representation. The intensity of the color increases with the grad of the value:



            vec3 normal_col = abs(normalize(position));
            gl_FragColor = vec4(normal_col, 1.0);








            share|improve this answer












            share|improve this answer



            share|improve this answer










            answered Nov 13 '18 at 5:59









            Rabbid76Rabbid76

            33.8k113045




            33.8k113045











            • I had experimented with 0.5 + 0.5 and it seemed to work correctly, but I didn't know why it was the case and thought I was just chucking numbers in there without any reason. Thanks for your explanation!
              – Lesbaa
              Nov 13 '18 at 9:59
















            • I had experimented with 0.5 + 0.5 and it seemed to work correctly, but I didn't know why it was the case and thought I was just chucking numbers in there without any reason. Thanks for your explanation!
              – Lesbaa
              Nov 13 '18 at 9:59















            I had experimented with 0.5 + 0.5 and it seemed to work correctly, but I didn't know why it was the case and thought I was just chucking numbers in there without any reason. Thanks for your explanation!
            – Lesbaa
            Nov 13 '18 at 9:59




            I had experimented with 0.5 + 0.5 and it seemed to work correctly, but I didn't know why it was the case and thought I was just chucking numbers in there without any reason. Thanks for your explanation!
            – Lesbaa
            Nov 13 '18 at 9:59













            0














            First of all, the normal facing the camera [0,0,-1] should be rgb values: [0.5,0.5,1.0]. You have to rescale things to move those negative values to be between 0 and 1.



            Second, the normals of a sphere would not change linearly, but in a sine wave. So you need some trigonometry here. It makes sense to me to to start with the perpendicular normal [0,0,-1] and then then rotate that normal by an angle, because that angle is what changing linearly.



            As a result of playing around this I came up with this:



            http://glslsandbox.com/e#50268.3



            which uses some rotation function from here: https://github.com/yuichiroharai/glsl-y-rotate






            share|improve this answer

























              0














              First of all, the normal facing the camera [0,0,-1] should be rgb values: [0.5,0.5,1.0]. You have to rescale things to move those negative values to be between 0 and 1.



              Second, the normals of a sphere would not change linearly, but in a sine wave. So you need some trigonometry here. It makes sense to me to to start with the perpendicular normal [0,0,-1] and then then rotate that normal by an angle, because that angle is what changing linearly.



              As a result of playing around this I came up with this:



              http://glslsandbox.com/e#50268.3



              which uses some rotation function from here: https://github.com/yuichiroharai/glsl-y-rotate






              share|improve this answer























                0












                0








                0






                First of all, the normal facing the camera [0,0,-1] should be rgb values: [0.5,0.5,1.0]. You have to rescale things to move those negative values to be between 0 and 1.



                Second, the normals of a sphere would not change linearly, but in a sine wave. So you need some trigonometry here. It makes sense to me to to start with the perpendicular normal [0,0,-1] and then then rotate that normal by an angle, because that angle is what changing linearly.



                As a result of playing around this I came up with this:



                http://glslsandbox.com/e#50268.3



                which uses some rotation function from here: https://github.com/yuichiroharai/glsl-y-rotate






                share|improve this answer












                First of all, the normal facing the camera [0,0,-1] should be rgb values: [0.5,0.5,1.0]. You have to rescale things to move those negative values to be between 0 and 1.



                Second, the normals of a sphere would not change linearly, but in a sine wave. So you need some trigonometry here. It makes sense to me to to start with the perpendicular normal [0,0,-1] and then then rotate that normal by an angle, because that angle is what changing linearly.



                As a result of playing around this I came up with this:



                http://glslsandbox.com/e#50268.3



                which uses some rotation function from here: https://github.com/yuichiroharai/glsl-y-rotate







                share|improve this answer












                share|improve this answer



                share|improve this answer










                answered Nov 13 '18 at 1:30









                Alex WayneAlex Wayne

                104k32234272




                104k32234272



























                    draft saved

                    draft discarded
















































                    Thanks for contributing an answer to Stack Overflow!


                    • Please be sure to answer the question. Provide details and share your research!

                    But avoid


                    • Asking for help, clarification, or responding to other answers.

                    • Making statements based on opinion; back them up with references or personal experience.

                    To learn more, see our tips on writing great answers.





                    Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


                    Please pay close attention to the following guidance:


                    • Please be sure to answer the question. Provide details and share your research!

                    But avoid


                    • Asking for help, clarification, or responding to other answers.

                    • Making statements based on opinion; back them up with references or personal experience.

                    To learn more, see our tips on writing great answers.




                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function ()
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53271461%2fdrawing-a-sphere-normal-map-in-the-fragment-shader%23new-answer', 'question_page');

                    );

                    Post as a guest















                    Required, but never shown





















































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown

































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown







                    這個網誌中的熱門文章

                    How to read a connectionString WITH PROVIDER in .NET Core?

                    Node.js Script on GitHub Pages or Amazon S3

                    Museum of Modern and Contemporary Art of Trento and Rovereto