Rajveer

Members
  • Content count

    143
  • Joined

  • Last visited

Community Reputation

250 Neutral

About Rajveer

  • Rank
    Member
  1. In the end this looks to be a limitation of the Adreno driver, which doesn't support indexing a uniform array of matrices without a constant integer contrary to what is mandatory within the OpenGL ES spec. A workaround however is to just use a uniform array of vec4s, as it does seem to support indexing these with variables (as is done within their SDK).
  2.   Thanks for the suggestion, unfortunately it didn't work :( If this were the issue though then not everything would get floored to 0, only indicies that should be 1, and there would still be some movement (although with wrong bone indices) no? I also tried reversing the indices just in case but no luck.     Thanks for checking! That...sucks. I'll have to look to see if it's possible to use a uniform with just an offset from another uniform's location (doubt it by the sounds of the last part of your sentence). Bah!
  3.   Hmm, actually I guess you're right, I should be choosing performance over (probably negligible) memory saved, especially on mobile platforms.         Ah that's a shame. I think the next step is for me to find somebody with an Android device with OpenGL ES 3.0 capability without an Adreno 330 (e.g. Note 3 Exynos version) to make sure it's not a problem with my device. If I do have to find a workaround, can you think of any way I can get around this (without resorting to CPU skinning, or having 30-50 individual bone matrices in my shader, unless it's possible to pass an array of uniforms into non-array but sequential locations in the shader)?
  4. I use 50 matrices for now as I'm just maximising the number of uniforms I can have, until all my assets have been finalised. Reducing this number down to around 30 (the max I'm using right now) doesn't have any effect, either way I've done the uniform space calculations at the top of the shader and am currently below the minimum that OpenGL ES guarantees.   I've not tried using the other mat4 matrix yet, just the boneMatrix one. This sounds interesting, and could potentially be the cause of my issues! Do you have any more information or sources regarding this?   Also regarding finalWeight, I only store 3 weights per vertex to reduce space used, as the fourth can just be calculated by doing "1.0 - all other weights".   Thanks!
  5. I am doing GPU skinning in my vertex shader which works fine on PC, and which I'm porting to Android. My vertex shader is below, and the problem is that the creation of the matTransform matrix seems to only use the first matrix in boneMatrices:   #version 300 es   precision highp float; precision highp int;   //Uniform count: projectionMatrix(16) + modelViewMatrix(16) + MVPMatrix(16) + textureMatrix(16) + normalMatrix(9) + lightMVPMatrices(16*5) + nShadowLights(1) + boneMatrices(16*boneMax)  = 73 + 1 + 16*shadowLightMax + 16*boneMax = (out of ~1024 components) //GLSL ES (vectors): projectionMatrix(4) + modelViewMatrix(4) + MVPMatrix(4) + textureMatrix(4) + normalMatrix(3) + lightMVPMatrices(4*5) + nShadowLights(1) + boneMatrices(4*boneMax) = 19 + 4*shadowLightMax + 4*boneMax = 239 out of 256 vectors on Nexus 5 (shadowLightMax = 5, boneMax = 50, 17 vec4s remain, or 4 matrices and 1 vec4) //Matrices //uniform mat4 projectionMatrix; uniform mat4 modelViewMatrix; uniform mat4 MVPMatrix; uniform mat4 textureMatrix; uniform mat3 normalMatrix; uniform mat4 lightMVPMatrices[5]; uniform int nShadowLights;   //Bones uniform mat4 boneMatrices[50];   //Vertex information in vec3 position; in vec4 colour; in vec2 texCoord; in vec3 normal; in vec3 boneWeights; in ivec4 boneIndices;   out vec4 _colour; out vec2 _texCoord; out vec3 _normal; out vec3 _eyePos; out vec4 _lightPos[5];   void main(void) {     vec4 positionSkinned;     vec4 normalSkinned;       mat4 matTransform = boneMatrices[boneIndices[0]] * boneWeights[0];     matTransform += boneMatrices[boneIndices[1]] * boneWeights[1];     matTransform += boneMatrices[boneIndices[2]] * boneWeights[2];     float finalWeight = 1.0 - (boneWeights[0] + boneWeights[1] + boneWeights[2]);     matTransform += boneMatrices[boneIndices[3]] * finalWeight;       positionSkinned = matTransform * vec4(position, 1.0);     //positionSkinned.w = 1.0;     normalSkinned = matTransform * vec4(normal, 0.0);       gl_Position = MVPMatrix * positionSkinned;     _colour = colour;     _texCoord = (textureMatrix * vec4(texCoord, 0.0, 1.0)).xy;     _normal = normalize(normalMatrix * normalize(normalSkinned.xyz));     _eyePos = (modelViewMatrix * positionSkinned).xyz;     for(int i = 0; i < nShadowLights; i++)         _lightPos[i] = lightMVPMatrices[i] * positionSkinned; }   I have verified that:   1) the correct matrices get pushed into boneMatrices   2) the correct bone indexes exist within boneIndices   3) the correct boneWeights exist within boneWeights   4) accessing components of boneIndices with dot notation (.x, .y, .z and .w) doesn't make a different   5) There are no OpenGL errors at all, as I check for errors after every call, and uniform size isn't an issue (if I increase boneMatrices by 5 extra matrices, I get invalid operation errors after each time I push matrices to the shader, but at this size and lower it's fine)   I have checked points 1, 2 and 3 (boneMatrices, boneIndices and boneWeights are correct) by doing the following:   1) using a specific animation which modified a few bones only (e.g. boneMatrix[6]), then hard-coding boneMatrix[6] and verifying that all vertices get properly modified by this single matrix, with the same result on PC and Android   2) drawing out boneIndices by doing the following in the vertex shader: _colour = vec4(float(boneIndices[0]), float(boneIndices[1]), float(boneIndices[2]), float(boneIndices[3]));   and the following in the fragment shader:   gl_FragColor = _colour   with the same colours on PC and Android   3) doing the same as above but with setting _colour to:   _colour = vec4(boneWeights[0], boneWeights[1], boneWeights[2], finalWeight);   I have no idea what else to try, and it definitely seems to be that only the first matrix is used. I have also tried using vec4 instead of ivec4 for boneIndices. This is on a Nexus 5 with an OpenGL ES 3.0 context. Help!   Here are images from it running both on Windows (showing all bone matrices being used) and on Android (showing only the first being used) with bones indices used for colour.   https://www.dropbox.com/s/3h7wwrmqc31dj51/waving-animation-window.png https://www.dropbox.com/s/vik1q7iqlq54lpd/waving-animation-android.png
  6. Thanks guys, I was heading towards a single context as I wanted to display the same world within these windows therefore preventing having to reload data into multiple contexts, but never thought about the vsync stuff, interesting! I wonder if you call SwapBuffers after all windows have been drawn to for that frame, and you are using displays with different refresh rates and vsync enabled, how long the graphics driver would block for? Either way I'll stick to a single context and have some fun experimenting, thanks.   Also quick question, on Windows I create the context when the first window is created with wglCreateContext(HDC) so that I have a device context to pass in, but when destroying the context I don't need a window to exist right, I can destroy my windows then separately I can call wglMakeCurrent(NULL, NULL) followed by wglDeleteContext(HGLRC)? So in theory I could open a window creating a context, delete it so the context exists with no windows open, then create another window which can use the context again (as long as the device context is compatible)? Not that I'd want to, just want to abstract my GL context deletion from window deletion.
  7. I'm adding multiwindow support to my game engine. All drawing will be done on the same render thread, so is there any reason why an OpenGL context per window would be a better idea than sharing a single context between all windows? The latter seems the simplest solution, but I haven't found a concrete example of when one method would be preferred over the other, and therefore an answer.
  8. Thanks for the replies guys. My game won't rely on mouse control as first person shooters do so I'll send it through to my logic thread for handling, and I'll probably handle headtracking directly in the rendering thread.   I'm interested in how fast twitch first person shooters handle this though, do they generally have the logic thread running at >= the frequency of the render thread, or does the render thread handle mouse input and the logic thread read it's latest values e.t.c? What would be the way you handled it?   Also I've got my input event buffer working so I'll stick with it. I'm later looking at making this OS agnostic so having my own event buffer is nice, and this is mainly for learning so why not challenged myself more than I need to :)
  9. I'm looking to create a threaded engine with 3 threads; one for OS input events which I store in a buffer between every tick, one for game logic and the third for rendering. I'm aiming at a constant tick rate with variable frame rate, and the renderer interpolating game states if the tick rate is lower.   Which thread should handle camera rotations e.t.c? I imagine if the tick frequency is lower than the render frequency, then interpreting mouse input and rotating the camera in the game thread would cause camera stuttering and lag, but if the tick frequency is the same or higher then it should be fine? Just wondering what the standard is, and whether I'm overlooking a way to create something independent of tick and frame rates with minimal lag.   I'm also looking to support the Oculus Rift, but I imagine camera control with it will require the same solution for reducing lag as with a mouse.
  10. WM_INPUT polling rate

    When I said polling, I mentioned using GetRawInputBuffer so that even if I were only checking for inputs during a render loop, I'd still get all inputs since the last as I'd be getting an array of events. However, I was going to post another question, and what you're saying about a proper event manager with timestamps pretty much answered it. I was considering the case where between frames, the user taps forward, then taps left, then releases. I'm guessing I should treat all of these events individually - when the user taps forward, check if they collide with anything e.t.c, then again when they tap left e.t.c., rather than combining these movements and testing at a certain increment. The timestep would be used to correctly space tests and game logic out relative to the input events, so I see the benefit in message handling now over polling, even if I were to get a whole array of buffered inputs (don't think they're timestamped). I've never separated game logic, rendering, and event handling before, as I've only developed homebrew games for consoles where 60fps was pretty much guaranteed, so do you have any good resources or tutorials to help me get thinking about the right way to do it? P.S. I took a look at your blog, and funnily enough I came across it a few days ago on Google and have been meaning to read that "Fix your timestep" article you linked to.
  11. WM_INPUT polling rate

    The way I understand it is you can: - Use WM_INPUT to receive every single keyboard/mouse event individually, where you'd get the data for each event using GetRawInputData, update your own key array/mouse pointer structs every time you get that message, then when it comes to your game loop use the latest data, OR - You poll it manually every game loop using GetRawInputBuffer, which gives you a buffer of inputs, which you'd process in one go, update your own key array/mouse pointer structs and use in that game loop. So either way there shouldn't be any missed inputs, in fact the second method sounds nicer to me as there would be less function calls and messages being passed to WndProc, but I may be missing something so am wondering which method is generally used, and is "nicer"
  12. WM_INPUT polling rate

    Figured it out, it's because I was using an if statement with PeekMessage rather than a while loop so only one message was getting processed per game loop (I should have put this in the Game Programming section, and should have also read up on the Win32 message system, sorry!) I guess the polling rate on the other computers was set too low even though I used the same mouse. This post helped: [url="http://www.gamedev.net/topic/296990-getmessage-vs-peekmessage/"]http://www.gamedev.n...vs-peekmessage/[/url] I have another question: I see there being 2 ways of capturing input - either you can call a function every game loop iteration which checks the current keyboard/mouse button/mouse pointer inputs, or you can use the message system, receive messages independently to your main game loop, then process what you've captured every game loop iteration. What is the preferred way of doing this? Bear in mind I'll be using raw mouse input for accuracy, so would it be better to go with the latter, buffer the raw data and then during each game loop iteration just combine all the data in the buffer into a single set of values that can be used in my game?
  13. WM_INPUT polling rate

    Made those changes (commented both printf statements, and returned 0 after both WM_MOUSEMOVE and WM_INPUT) but the problem persists. Just to note, when printing statements, on the laptop when moving the mouse I'd generally get 2-3 WM_INPUT messages then a WM_MOUSEMOVE. On my desktop I get a huge amount of WM_INPUTS with a rare WM_MOUSEMOVE inbetween.
  14. WM_INPUT polling rate

    Yep, tried commenting the printf() statements out and still get the same behaviour.
  15. I'm playing around with WM_INPUT, but am getting an issue where I can't drag or resize my window on my desktop computer (it's fine in a VM or on my laptop). It looks as if my app gets flooded with WM_INPUT messages for a while after I move my mouse, and then stops, and during that flood I can't drag/resize and I get the Windows loading spinner icon. Setting the polling rate of my Logitech G5 in SetPoint to 1000Hz makes it worse; setting it to 125Hz isn't too bad but it's still there. Note: I tried my mouse on my laptop too, but since I don't have SetPoint installed on it, it doesn't exhibit this behaviour. Should I be handling WM_INPUT separately to the rest of my app? I've got some basic code which shows this problem when you have a high-frequency mouse: [CODE] #include <windows.h> #include <gl/gl.h> #include <gl/glu.h> #include <stdio.h> #include "console.h" HWND hWnd; HDC hDC; HGLRC hRC; // Set up pixel format for graphics initialization void SetupPixelFormat() { PIXELFORMATDESCRIPTOR pfd, *ppfd; int pixelformat; pfd = &pfd; ppfd->nSize = sizeof(PIXELFORMATDESCRIPTOR); ppfd->nVersion = 1; ppfd->dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; ppfd->dwLayerMask = PFD_MAIN_PLANE; ppfd->iPixelType = PFD_TYPE_COLORINDEX; ppfd->cColorBits = 16; ppfd->cDepthBits = 16; ppfd->cAccumBits = 0; ppfd->cStencilBits = 0; pixelformat = ChoosePixelFormat(hDC, ppfd); SetPixelFormat(hDC, pixelformat, ppfd); } // Initialize OpenGL graphics void InitGraphics() { hDC = GetDC(hWnd); SetupPixelFormat(); hRC = wglCreateContext(hDC); wglMakeCurrent(hDC, hRC); glClearColor(0, 0, 0, 0.5); glClearDepth(1.0); glEnable(GL_DEPTH_TEST); } // Resize graphics to fit window void ResizeGraphics() { // Get new window size RECT rect; int width, height; GLfloat aspect; GetClientRect(hWnd, &rect); width = rect.right; height = rect.bottom; aspect = (GLfloat)width / height; // Adjust graphics to window size glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45.0, aspect, 1.0, 100.0); glMatrixMode(GL_MODELVIEW); } // Draw frame void DrawGraphics() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Set location in front of camera glLoadIdentity(); glTranslated(0, 0, -10); // Draw a square glBegin(GL_QUADS); glColor3d(1, 0, 0); glVertex3d(-2, 2, 0); glVertex3d(2, 2, 0); glVertex3d(2, -2, 0); glVertex3d(-2, -2, 0); glEnd(); // Show the new scene SwapBuffers(hDC); } // Handle window events and messages LONG WINAPI MainWndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_MOUSEMOVE: //printf("\nMouse Move message received\n"); return 0; break; case WM_INPUT: // printf("\nInput message received %d", rand()); return 0; break; case WM_SIZE: ResizeGraphics(); break; case WM_CLOSE: DestroyWindow(hWnd); break; case WM_DESTROY: PostQuitMessage(0); break; // Default event handler default: return DefWindowProc (hWnd, uMsg, wParam, lParam); break; } return 1; } int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { SetStdOutToNewConsole(); const LPCWSTR appname = TEXT("OpenGL Sample"); WNDCLASS wndclass; MSG msg; // Define the window class wndclass.style = 0; wndclass.lpfnWndProc = (WNDPROC)MainWndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = hInstance; wndclass.hIcon = LoadIcon(hInstance, appname); wndclass.hCursor = LoadCursor(NULL,IDC_ARROW); wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wndclass.lpszMenuName = appname; wndclass.lpszClassName = appname; // Register the window class if (!RegisterClass(&wndclass)) return FALSE; //Calculate x and y coords of where window should be int dwWidth = GetSystemMetrics(SM_CXSCREEN); int dwHeight = GetSystemMetrics(SM_CYSCREEN); dwWidth /= 2; dwWidth -= (800/2); dwHeight /= 2; dwHeight -= (600/2); // Create the window hWnd = CreateWindow( appname, appname, WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, dwWidth, dwHeight, 800, 600, NULL, NULL, hInstance, NULL); if (!hWnd) return FALSE; RAWINPUTDEVICE Rid[1]; Rid[0].usUsagePage = 0x01; Rid[0].usUsage = 0x02; Rid[0].dwFlags = RIDEV_INPUTSINK; Rid[0].hwndTarget = hWnd; RegisterRawInputDevices(Rid, 1, sizeof(Rid[0])); // Initialize OpenGL InitGraphics(); // Display the window ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); // Event loop while (1) { if (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE) == TRUE) { if (!GetMessage(&msg, NULL, 0, 0)) return TRUE; TranslateMessage(&msg); DispatchMessage(&msg); } DrawGraphics(); } wglDeleteContext(hRC); ReleaseDC(hWnd, hDC); } [/CODE]