Jump to content
  • Advertisement

corysama

Member
  • Content Count

    86
  • Joined

  • Last visited

  • Days Won

    2

corysama last won the day on September 3

corysama had the most liked content!

Community Reputation

359 Neutral

About corysama

  • Rank
    Member

Personal Information

  • Role
    Programmer
  • Interests
    Programming
  1. You can use Win32 to create a window, then use OGL or D3D to create a texture, update it with the contents of your software rendered framebuffer and draw it that texture to the screen. That's gonna be about as fast as you can get an image from main RAM to the screen. I'd recommend using https://www.libsdl.org/ to do the window handling and blit. Under the hood it does what I described, but has code paths for many OS's and graphics APIs already widely battle-tested. Here's a complete program demonstrating how to blit CPU->screen using SDL2. #include <SDL.h> inline uint32_t argb(uint8_t a, uint8_t r, uint8_t g, uint8_t b) { return (a<<24) | (r << 16) | (g << 8) | (b << 0); } int main(int argc, char *argv[]) { SDL_Init(SDL_INIT_VIDEO); SDL_Rect screenRect = { 0,0,1024,1024 }; SDL_Window *window = SDL_CreateWindow("SDL", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, screenRect.w, screenRect.h, SDL_WINDOW_SHOWN); SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED); SDL_Texture *texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, screenRect.w, screenRect.h); for (int frame = 0; ; ++frame) { SDL_Event event; while (SDL_PollEvent(&event) != 0) if (event.type == SDL_QUIT) return 0; int pitch; uint32_t *pixels; SDL_LockTexture(texture, &screenRect, (void**)&pixels, &pitch); uint32_t startTicks = SDL_GetTicks(); for (int y = 0; y < screenRect.h; y++) { for (int x = 0; x < screenRect.w; x++) { pixels[y*screenRect.w + x] = argb(255, frame>>3, y+frame, x+frame); } } uint32_t endTicks = SDL_GetTicks(); SDL_UnlockTexture(texture); SDL_SetRenderDrawColor(renderer, 0xFF, 0xFF, 0xFF, 0xFF); SDL_RenderClear(renderer); // Don't skip the clear! Drivers look for it when managing framebuffer queueing and reuse. SDL_RenderCopy(renderer, texture, &screenRect, &screenRect); SDL_RenderPresent(renderer); char title[32]; SDL_SetWindowTitle(window, SDL_itoa(endTicks - startTicks, title, 10)); } }
  2. I worked on the crowd rendering for NBA Inside Drive 2004 for the Xbox OG. Here's what we did: Made about 10 3D models of various low-rez, animated audience members. Divided up the stadium into seating sections. Made a tool to automate placing camera-facing sprites for each seat in every section. bonus: The sprites were ordered inside the mesh from front row to back so that the front sprites would z-occlude back seats within a single draw call Every frame we'd pick one on-camera seating section and render about 20 sprites using the 10 models. All sprites were rendered as if the person was positioned in the center of the section relative to the current camera. Those 20ish sprite would be used to populate the whole section until the section was next updated. So, the perspective wasn't perfect for any of them. But, it was good enough to look good. And, the sprites would be reused for a few frames, but the update rate vs. performance was easy to tune. bonus: The audience all wore grey shirts with 50% gray alpha. They were rendered into the sprite sheet with alpha blend disabled and the background cleared to (0,0,0,0). So, the background had alpha=0, the shirt texels had alpha=127 and the skin/pants had alpha=255. The shader was set to colorize texels with alpha = 127 and we used alpha blend disabled and alpha test (discard) enabled for alpha < 64. The Xbox had a pixel shader instruction "multiply, multiply, select" that let us colorize the shirts differently per audience member in a single shader cycle.
  3. Best advice I can give you is to start out by developing your code on multiple platforms simultaneously. When you do that, you will discover tons of tiny surprises along the way that you need to adjust to keep the code clean on all platforms. Fixing issues as they appear is quick and easy. But, putting off discovery until after lots of code has been written, you are signing yourself up for lots of unpleasant surprises (and rewrites).
  4. corysama

    Gamma correction confusion

    Yep. You understand it now. When sampling a framebuffer, it's just another texture. Having sRGB framebuffers and textures is not just a convenience. Blending and texture filtering need to be done in linear space to work properly (linearly). So, under the hood, the blendop has to do newSrgbPixelColor = toSRGB(blend(linearShaderOutputColor, toLinear(currentSrgbPixelColor))) You can't do that in a pixel shader without "programmable blending" extensions. Similarly, the texture sampler has to convert all samples to linear before performing filtering. In theory you could do a bunch of point samples and convert+filter yourself in a pixel shader. But, you really do not want to. Especially not for complicated sampling like anisotropic.
  5. corysama

    Gamma correction confusion

    In your postprocessing you'll need to set the framebuffer as an sRGB source texture to convert it back to linear when you sample it. It's the same as your loaded textures. The 8-bit render target is being used as intermediate storage between fp32 calculations. The linear->sRGB->linear round-trip is designed to minimize loss during that 8-bit intermediate step. So, it goes: load 8-bit sRGB texture file, sample 8-bit sRGB texture converting it to a linear fp32 color, do lighting math in fp32, convert to sRGB to store in an 8-bit framebuffer, set the frambuffer as an sRGB8888 source texture, sample the 8-bit texture converting from sRGB to linear fp32, do post-processing math, store to another 8-bit sRGB framebuffer. You can avoid the linear->sRGB->linear process if you can afford a higher-precision intermediate format.
  6. corysama

    Gamma correction confusion

    There are 2 purposes to using sRGB as an image/framebuffer format: 1) It's what monitors expect. So, it can be pumped straight to be monitor without extra work. 2) 8 bits is not enough precision to avoid banding artifacts in dark regions when the color is stored linearly. If you use a higher bitrate framebuffer then you can get away with storing linear space colors. And, sRGB888 is OK as an intermediate format. But, RGB888 filled with linear-space colors will result in a lot of banding.
  7. Are you making a math library for games or for "serious" applications --stuff where rare bugs have serious physical/financial consequences? In general, the theme for bug handling in games is to have lots of testing up front. During production, error as early as possible to make it easy to identify the hopefully recent change that caused the bug. When you ship, remove all error checks because you are confident in your testing, right? So, yeah. Assert. If a non-invertible matrix goes through the invert function in a game, something went irrecoverably wrong. There is no exception/error-handling to be done. There's a bug and it needs to be fixed quickly.
  8. corysama

    Marching Tetrahedra algorithm normals

    Hey, Thomas. What is the run time source of your 3D scalar field? The easiest way to generate vertex normals for marching cubes/tets is to do central differencing (take the gradient) on the scalar field. This should also be much more accurate than trying to reconstruct the field normal from the generated triangles. You can see an implementation of this technique in the vGetNormal function of my ancient example code: http://paulbourke.net/geometry/polygonise/marchingsource.cpp It's pretty easy to implement. But, can be slow for complicated procedural fields. If you need that to be faster, you can dig into analytic differentiation. But, be prepared to break out your math textbooks.
  9. corysama

    Relative to Camera rendering.

    r_Grid * vec4(r_Vertex, 1.0) is what's giving you grief. In order to avoid fp32 precision errors you can never allow an fp32 calculation to contain an excessively large value. r_ModelViewProjection * vec4(V, 1.0); Is taking an already stairsteppy V and transforming it to projection space. What you need is a GridModelViewProjection matrix that is calculated as doubles before being converted to floats. How to pull off the normalize trick after that is a good question... Bikeshedding bonus: Personally, I prefer to name my mats in the style of ProjectionFromGrid rather than GridModelViewProjection. That way it connects nicely when I write out "projectionPosition = ProjectionFromGrid * gridPosition"
  10. corysama

    Packing uniforms into matrix

    Don't stop at packing some of them into a matrix. Pack all of them into an array of vec4s and alias them with "#define shininess array[3].y"
  11. So, sounds like what you are doing is: reGamma(Ambient(deGamma(texture)) + reGamma(Light(deGamma(texture)) This doesn't work because reGamma is a non-linear operator. So, you can't expect a linear operator like + to make sense with it's results. Instead what you have to do is: reGamma(Ambient(deGamma(texture) + Light(deGamma(texture)) That means removing the gamma operation from the end of your shader, accumulating linear values into your framebuffer, then switching back to gamma as a post past on the final value. To make that work, you are going to need to switch to an fp16 format for your framebuffer because the whole point of the gamma curve is that rgb888 isn't enough bits to store linear colors without banding.
  12. corysama

    Frustum Culling

    This is a very nice article.   The bit at the at the end of the OBB function __m128i outside_res_i = _mm_cvtps_epi32(outside); ALIGN_SSE int obj_culling_res[4]; _mm_store_si128((__m128i *)&obj_culling_res[0], outside_res_i); culling_res[i] = (obj_culling_res[0] != 0 || obj_culling_res[1] != 0 ||  obj_culling_res[2] != 0) ? 1 : 0; Is unnecessary memory traffic.  The store, loads, all of those compares and the branch can be replaced by a single instruction that keeps everything in registers. culling_res[i] = _mm_movemask_ps(outside);   With SSE, RAM is the enemy.  Registers are your only friend.
  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!