More on Shader Coordinates vs Screen Coordinates

edited May 2013 in Help request
I wrote a simple shader to demonstrate an issue.

[Object]
Graphic     = OnePixel
Position   = (0., 0., 0.2)
Scale       = (600., 600., 1)
ShaderList  = HexShader

[OnePixel]
Texture = pixel

[HexShader]
ParamList = mousePoint
UseCustomParam = true
mousePoint = (0.5, 0.5, 0.)
Code = "
void main()
{
	vec3 p = gl_TexCoord[0].xyz; // current point
    if (abs(mousePoint.x - p.x) < 0.005 && abs(mousePoint.y - p.y) < 0.005) {
        gl_FragColor = vec4(1., 1., 1., 1.);
    } else {
        discard;
    }
}
"

C code to calculate the mouse coordinates in the shader simply assumes that graphic range is in 0 to 1 coordinate system. Point (0,0) is the left bottom corner of the coordinate system. So, I have to take mouse world coordinates and translate those relatively to the Object shader coordinates.

What I see is a bit confusing. The shader above is supposed to draw a small white rectangle next to mouse cursor. And it does right in the middle of the [Object]. However as I go to the perimeter of the object the white rectangle gets ahead of the cursor. It effectively reaches the edge before the mouse. This indicates to me that shader coordinate system is not 0 to 1 but more like

x: 0.101667 to 0.9
y: 0.1 to 0.901667

I must be calculating the shader coordinate system incorrectly. Is there an easier way to get shader coordinate system? I do something like this:
// shaderRes is the result in the shader coordinates
// point is the screen coordinate to translate
// origin is the left bottom corner of the texture with (0,0) texture coordinate
// size is the size of the texture
orxVECTOR* hemScreenIntoShader(orxVECTOR *shaderRes, orxVECTOR *point, orxVECTOR *origin, orxVECTOR* size) {
    orxVECTOR pointToOrigin;
    pointToOrigin.fX = point->fX - origin->fX;
    pointToOrigin.fY = origin->fY - point->fY;
    pointToOrigin.fZ = origin->fZ;
    orxVector_Div(shaderRes, &pointToOrigin, size);
    //orxLOG("shaderPoint: %f, %f.", shaderPoint.fX, shaderPoint.fY);
    return shaderRes;
}

the actual origin calculation is a bit boring:
    /* Creates object */
    grid = orxObject_CreateFromConfig("Object");
    
    orxObject_GetWorldPosition(grid, &gridPos);
    orxVECTOR size, scale;
    orxObject_GetSize(grid, &size);
    orxObject_GetScale(grid, &scale);
    orxVector_Mul(&gridSize, &scale, &size);
    orxVector_Set(&shaderOrigin, gridPos.fX, gridPos.fY + gridSize.fY, gridPos.fZ);
    orxLOG("grid size: %f, %f, %f", gridSize.fX, gridSize.fY, gridSize.fZ);
    orxLOG("shader origin: %f, %f, %f", shaderOrigin.fX, shaderOrigin.fY, shaderOrigin.fZ);


I think the issue might have to do something with _top, _right, _left and _bottom coordinates passed into the shader as referenced in

http://orx-project.org/wiki/en/orx/config/settings_structure/orxshader?s[]=top

Unfortunately in my case there is no easy access to _top variable as there is no texture variable, but a texture list.

Comments

  • edited May 2013
    My goal in here is simply to be able to calculate mouse coordinate in shader coordinate space for mouse tracking.
  • edited May 2013
    ok. I was able to condense my misunderstanding to a simple configuration file that works with 01_Object tutorial. Simply replace 01_Object.ini content with the one provided here.

    You will observe that coordinate passed into the shader is (0.9, 0.9), but it is displayed at the very top right corner of the application window. So, I can't quite understand why it is 0.9 instead of 1.0.

    My best guess is that view transforms are responsible for changing the coordinate space.
    ; orx - Tutorial config file
    ; Should be used with orx v.1.4+
    
    [Display]
    ScreenWidth   = 800
    ScreenHeight  = 600
    Title         = Shader Tutorial
    
    [Input]
    SetList = MainInput
    
    [MainInput]
    KEY_ESCAPE = Quit
    
    [Viewport]
    Camera            = Camera
    
    [Camera]
    ; We use the same size for the camera than our display on screen so as to obtain a 1:1 ratio
    FrustumWidth  = @Display.ScreenWidth
    FrustumHeight = @Display.ScreenHeight
    FrustumFar    = 1.0
    FrustumNear  = 0.0
    Position      = (0.0, 0.0, -1.0)
    
    [Object]
    Graphic    = OnePixel
    Position   = (-400., -300., -0.)
    Scale      = (800, 600, 1.)
    ShaderList  = HexShader
    
    [OnePixel]
    Texture = pixel
    
    [HexShader]
    ParamList = mousePoint
    mousePoint = (.9, 0.9, 0.)
    Code = "
    void main()
    {
    	vec3 p = gl_TexCoord[0].xyz; // current point
        if (abs(mousePoint.x - p.x) < 0.003 && abs(mousePoint.y - p.y) < 0.003) {
            gl_FragColor = vec4(1., 0., 0., 1.);
        } else {
            discard;
        }
    }
    "
    
  • edited May 2013
    Hi kulak,

    I believe you're mistaking what gl_TexCoord[0] actually is. :)

    It's the normalized coordinates of your texel in your texture, which normally doesn't map to any screen coordinates.

    What you want is the coordinates of your fragment (ie. pixel) in your display/window. This is given by the internal variable gl_FragCoord.
    Also notice that gl_FragCoord isn't normalized.

    In your case, you can simply flip the Y coordinate of your mouse position (something like MousePos.y = ScreenHeight - MousePos.y) and test it against gl_FragCoord in your shader.

    There shouldn't be any need of any other calculations. :)

    As a side note (but not really relevant to your case), whenever you have an array of samplers (aka textures) in your shader, orx will create arrays for _top, _left, _bottom and _right with the same name and size.
    Ex: MyTexture[3] -> MyTexture_left[3], etc...
  • edited May 2013
    Thanks that worked.

    Here is my little test project .c and .ini files to demo mouse tracking with shaders. It simply displays a small red rectangle around mouse pointer.

    INI:
    ; orx - Tutorial config file
    ; Should be used with orx v.1.4+
    
    [Display]
    ScreenWidth   = 800
    ScreenHeight  = 600
    Title         = Shader Tutorial
    
    [Input]
    SetList = MainInput
    
    [MainInput]
    KEY_ESCAPE = Quit
    
    [Viewport]
    Camera            = Camera
    BackgroundColor   = (210, 180, 140)
    
    [Camera]
    ; We use the same size for the camera than our display on screen so as to obtain a 1:1 ratio
    FrustumWidth  = @Display.ScreenWidth
    FrustumHeight = @Display.ScreenHeight
    FrustumFar    = 1.0
    FrustumNear  = 0.0
    Position      = (0.0, 0.0, -1.0)
    
    [Object]
    Graphic    = OnePixel
    Position   = (-350., -200., -0.)
    Scale      = (700, 400, 1.)
    ShaderList  = HexShader
    
    [OnePixel]
    Texture = pixel
    
    [HexShader]
    ParamList = mousePos
    UseCustomParam = true
    mousePos = (799., 599., 0.)
    Code = "
    void main()
    {
    	vec3 p = gl_FragCoord.xyz;
        if (abs(mousePos.x - p.x) < 2. && abs(mousePos.y - p.y) < 2.) {
            gl_FragColor = vec4(1., 0., 0., 1.);
        } else {
            gl_FragColor = vec4(.184, .309, .309, 1.);
        }
    }
    "
    

    C:
    /* Orx - Portable Game Engine
     *
     * Copyright (c) 2008-2010 Orx-Project
     *
     * This software is provided 'as-is', without any express or implied
     * warranty. In no event will the authors be held liable for any damages
     * arising from the use of this software.
     *
     * Permission is granted to anyone to use this software for any purpose,
     * including commercial applications, and to alter it and redistribute it
     * freely, subject to the following restrictions:
     *
     *    1. The origin of this software must not be misrepresented; you must not
     *    claim that you wrote the original software. If you use this software
     *    in a product, an acknowledgment in the product documentation would be
     *    appreciated but is not required.
     *
     *    2. Altered source versions must be plainly marked as such, and must not be
     *    misrepresented as being the original software.
     *
     *    3. This notice may not be removed or altered from any source
     *    distribution.
     */
    
    /**
     * @file 13_Shader.c
     * @date 05/07/2013
     * @author Sergei G
     *
     * Mouse tracking and shader.
     */
    
    
    #include "orx.h"
    
    
    /* This is a basic C tutorial creating a viewport and an object.
     *
     * As orx is data driven, here we just write 2 lines of code to create a viewport
     * and an object. All their properties are defined in the config file (01_Object.ini).
     * As a matter of fact, the viewport is associated with a camera implicitly created from the
     * info given in the config file. You can also set their sizes, positions, the object colors,
     * scales, rotations, animations, physical properties, and so on. You can even request
     * random values for these without having to add a single line of code.
     * In a later tutorial we'll see how to generate your whole scene (all background
     * and landscape objects for example) with a simple for loop written in 3 lines of code.
     *
     * For now, you can try to uncomment some of the lines of 01_Object.ini, play with them,
     * then relaunch this tutorial. For an exhaustive list of options, please look at CreationTemplate.ini.
     */
    
    orxS32 _screenHeight;
    orxVECTOR _texCoord;
    
    static orxSTATUS orxFASTCALL handleShaderEvent(const orxEVENT *currentEvent) {
        switch(currentEvent->eID){
            case orxSHADER_EVENT_SET_PARAM: {
                /* Gets its payload */
                orxSHADER_EVENT_PAYLOAD *pstPayload = (orxSHADER_EVENT_PAYLOAD *)currentEvent->pstPayload;
                /* look for parameter of interest */
                if(!orxString_Compare(pstPayload->zParamName, "mousePos")) {
                    orxVector_Copy(&pstPayload->vValue, &_texCoord);
                }
            }
        }
        return orxSTATUS_SUCCESS;
    }
    
    /** Inits the tutorial
     */
    orxSTATUS orxFASTCALL Init()
    {
        /* Displays a small hint in console */
        orxLOG("none
    * This tutorial creates a viewport/camera couple and an object with shader"
               "none
    * You can play with the config parameters in ../13_Shader.ini"
               "none
    * After changing them, relaunch the tutorial to see their effects");
        
        orxConfig_PushSection("Display");
        _screenHeight = orxConfig_GetS32("ScreenHeight");
        orxConfig_PopSection();
        
        orxViewport_CreateFromConfig("Viewport");
        orxObject_CreateFromConfig("Object");
        orxEvent_AddHandler(orxEVENT_TYPE_SHADER, handleShaderEvent);
        return orxSTATUS_SUCCESS;
    }
    
    /** Run function
     */
    orxSTATUS orxFASTCALL Run()
    {
        orxSTATUS eResult = orxSTATUS_SUCCESS;
        
        /* Should quit? */
        if(orxInput_IsActive("Quit"))
        {
            /* Updates result */
            eResult = orxSTATUS_FAILURE;
        }
        /* stores current mouse position */
        orxVECTOR mouse;
        orxMouse_GetPosition(&mouse);
        _texCoord.fX = mouse.fX;
        _texCoord.fY = _screenHeight - mouse.fY;
        _texCoord.fZ = 0.;
        /* Done! */
        return eResult;
    }
    
    /** Exit function
     */
    void orxFASTCALL Exit()
    {
        /* We're a bit lazy here so we let orx clean all our mess! :) */
    }
    
    /** Main function
     */
    int main(int argc, char **argv)
    {
        /* Executes a new instance of tutorial */
        orx_Execute(argc, argv, Init, Run, Exit);
        
        return EXIT_SUCCESS;
    }
    
    
    #ifdef __orxMSVC__
    
    // Here's an example for a console-less program under windows with visual studio
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
    {
        // Inits and executes orx
        orx_WinExecute(Init, Run, Exit);
        
        // Done!
        return EXIT_SUCCESS;
    }
    
    #endif // __orxMSVC__
    
  • edited May 2013
    I saw you created a community tutorial, thanks! :)

    One small remark though: in order to get the ScreenHeight parameter, you query the config system.

    The issue with that is: if you change your resolution at runtime (by calling orxDisplay_SetVideoMode()), the config value won't change and only reflect the initial value.

    You might want to call orxDisplay_GetScreenSize() to query the current resolution instead.
  • edited May 2013
    Thanks. I was wondering about how to do handle screen change at runtime. I will adjust the tutorial.
Sign In or Register to comment.