Archived

This topic is now archived and is closed to further replies.

Grayscale rendering using Jim's Tile engine from P_RPG_W/DX8.0 (modified)

This topic is 5500 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Well, I have submitted a relative question some time ago, but I thought I''d come clean w/ all of you and ask again clearly, since I''d much rather ask again in a different manner than bump away :D In any case, here''s the chant, berks (Planescape anybody?): I''m using a heavily modified edition of Jim Adams'' tile map engine from Programming Role Playing Games With DirectX 8.0 - for those not having read the book, Jim uses a direct blit operation on the texture itself in order to draw part of it as a tile, no polygons et al involved. The point is, I want to be able to render to grayscale (or tinted grayscale, for that instance ), so as to emulate the effect used on old SNES FF games (flashback, memories returning, etc.). Sadly, since the map is blitted directly, without the intervention of polygons, I can''t use any texture states to get my job done, any of course creating grayscale versions of the tilesets is out of the question for obvious, I believe, reasons. S1CA and others who had replied to my first post had mentioned (thanks again Simon and fellas, for what it''s worth ) I could somehow render the frame normally somewhere and then render THAT rendering on-screen in B&W (phew). So, here are the questions: How can I achieve the grayscale effect in the method described above? (detailed answers please, I''m not much of a guru, I''d probably bump again for details, so spare me the swelling on the forehead:D) Is there any other way to do it, and if so, which one? Jim, Simon... anyone?Hello? -----------<<>>----------- Ga1adaN, Primus ante Adein flareman@freemail.gr -----------<<>>------------

Share this post


Link to post
Share on other sites
I've been following this discussion and I am also very intrested in how to render a grayscale image.

I saw someone write about renderstates and someone else was suggesting a PixelShader. I did not get any of the methods to work.

So, if someone have or know where to find an actual example (code) on how to do this (how to turn the whole backbuffer or just textures to b/w), please reply. Two versions of the textures is not an option for me ether.

Thanks!



[edited by - lexor on November 18, 2002 5:43:12 PM]

Share this post


Link to post
Share on other sites
well, here's somebody thinking my way
I tried pixel shading myself, but, alas, it won't work, because it functions w/ polygons as well (besides, pixel shading in h/w isn't supported by my lowly GeForce2MX400... ah, well)

Render states don't seem to give an immediate solution (perhaps there is one that we just can't see - enlightening, anyone?)

The best thing to do, in my opinion, would be to lock the rendered backbuffer, then perform a grayscale-conversion operation on EACH pixel, along w/ any tinting we needed - just tell me how to do it and I'm off nuts! (although I have that hunch about it not being the optimal way to do it - well, I'm not even sure whether it CAN be done in the first place!)

But I'm getting carried off. Suggestions?

-----------<<>>-----------
Ga1adaN, Primus ante Adein
flareman@freemail.gr
-----------<<>>------------

[edited by - Flareman on November 18, 2002 6:40:37 PM]

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
all i can say is, you gotta go grayscale before you tint, otherwise the result will be kinda kinky

hope this helps
Buzzah

Share this post


Link to post
Share on other sites
Yeah, I thought so myself, but the intitial question remains: HOW can I achieve grayscale rendering when the frame is already in the buffer? Can I modify the already rendered pixels, and if so, how? Or should I use another technique?

Fellas, help me out here;it''s getting sort of lonely in here...

-----------<<>>-----------
Flareman (a.k.a Ga1adaN)
Primus ante Adein
flareman@freemail.gr
-----------<<>>------------

Share this post


Link to post
Share on other sites
Instead of blitting/drawing to the frame buffer, just draw to a texture. The code shouldn''t change fundamentally (use the surface of the texture instead of the surface for the frame buffer) that way, and with that you can basically do all kinds of funky effects by just rendering two triangles to the screen.

- JQ
Full Speed Games. Are back.

Share this post


Link to post
Share on other sites
Well, that''s an option;however, I fear there could arise difficulties:

First of all, resolutions such as 640x480, 800x600 etc. aren''t completely powers of two, as the textures should be (perfect squares, that is), so it''s a bit more complicated (not to mention inefficient) to create a 1024x1024 texture in order to fin a 640x480 frame in it. Of course, if there is a workaround, I''d love to hear it.

In any case, I''d appreciate seeing some code, here;like I said, I roughly can go beyond the basics, so I haven''t the foggiest about rendering to another render target, or switching back to the back buffer (the SDK notes aren''t much of a help, either)

One more thing: ''don''t pretty much know why, but I stigg got that feeling that there MUST be a more efficient way to do this... all o''ya guys, you sure I can''t justlay my hands on the buffer itself somehow?

Answers...answers... (well, at least I didn''t have to bump

-----------<<>>-----------
Flareman (a.k.a Ga1adaN)
Primus ante Adain
flareman@freemail.gr
-----------<<>>------------

Share this post


Link to post
Share on other sites
Flaaaareman! Every time I check the forums and see a new post in the grayscale-thred I get excited to see if someone made a good post about solving the problem. But every time its just you and your bumps. Ahhh!

Share this post


Link to post
Share on other sites
OK, in order to be more constructive:
I haven''t read Jim''s book, so I know only what you have said in this thread about the methods you are currently using.
I think to be able to help more you''d have to tell us how the sprites (I assume?) are currently stored, and how you actually blit to the frame buffer - is it done using a custom blitter? (you said it''s DirectX8 right?) If not, how exactly are you blitting?

- JQ
Full Speed Games. Are back.

Share this post


Link to post
Share on other sites
Here goes:

lexor: hey, somebody 's gotta bump, just in case Jim shows up
Pardon the p/o'ing, but since I started the thread... it's only fair I should bump (and have the responsibility for it, too) (besides, I only bumped once! thereare some guys that bump AAAAAAL the time; THEY are the ones that ought to be banned )

pipo: nah, I tried that one already; gamma ramping actually modifies the color content for all pixels simultaneously on a percentage base; that is, suppose I use a gamma ramp that is 100% red, 100% green and 40% blue - all pixels will have their blue values dropped by 60%. Now, grayscaling encompasses the following MAJOR p/o (spasimo as we say in greece): all three chromatic values must be EQUAL, so that the result is a pure gray color. The (common) value assigned is calculated so as to take under consideration all trhee color components, using a different weighting factor. So, red color contributes by 21,25%, green by 71,54% (easily the biggest percentage - that is why the green component is essentially the most definitive when converting from RGB to grayscale) and blue by 7,21% (meager). The conclusion is that gamma ramping can't and will simply NOT assign the same (correct) value to all 3 color components (BUT, after the frame is grayscale, it definitively *can* be used to tint the color to say, yellow (or what have you))

On to the good part:
JQ: Yeah, you're probably right, my mistake entirely for not mentioning... not all have Jim's book; allow me to elaborate :

When I'm talking of this particular tile engine, I'm referring to the actual map drawn on screen using a specific tileset (however, sprites, objects, etc will probably use the same technique, so read on). The tileset is a .bmp file, square, of set dimensions (e.g. 256x256), containing (optimally) square tiles (currently, 64x64 - the size doesn't matter). The tileset is loaded on a IDirect3DTexture8 interface (using the d3dx function LoadTextureFromFileEx, obviously - please note that the engine structure is more complex, with encapsulation and stuff, I just don't mention all the classes and so on in order to keep things clear). When I want to draw a tile, I have a ID3DXSprite interface, which I couple with the texture and use the Draw (or DrawTransform, that's irrelevant) function of the sprite interface.

Now, the important fact is this: the Draw function blits the pixels of the texture directly to the back buffer - DIRECTLY. That's my problem. The blitting procedure skips ENTIRELY the T&L procedure, as well as any texturing (or texture-state) based attemps to grayscale-render. After the frame is done and already in the back buffer, the only thing I could possibly do is to lock the bb and then manually process each pixel to "do" it grayscale.

BTW, I'm using the old quad-above-the-frame technique for fades and such, as well as for color-adding (hase while snowing, etc.) AND for achieving the letterbox effect for cut-scenes. All of theses are polygons, BUT, once again, not textured, which means that the grayscale problem occurs still.

I hope that I have explained my technique sufficiently enough for any other who want to help - if not, post and ask away

Anything guys, just help me w/ this nightmare

-----------<<>>-----------
Flareman (a.k.a Ga1adaN)
Primus ante Adain
flareman@freemail.gr
-----------<<>>------------

[edited by - flareman on November 22, 2002 4:25:43 AM]

Share this post


Link to post
Share on other sites
Why not bypass the middleman that is D3DX and write your own sprite class that uses polys? That''s what I''m doing, I hate using the D3DX Sprite functions since your bound to using their Draw method.

Share this post


Link to post
Share on other sites
Can''t you just create a second texture for each tile set that has grayscale versions of each of the tiles in the image? Then when you want to render grayscale you just need to change which texture you''re using.

Share this post


Link to post
Share on other sites
maymer: creating a whole new set of tiles isn''t actually my idea of efficiency; buying a new PC just because the old one''s RAM went ZAP isn''t really a solution - one''s more likely to replace the burnt circuits (thanks for taking the time to respond, though; it''s just that I want to be flexible with my code, creating data-dependent code is sort of a nemesis to me)

qdot: well, that''s a solution, for sure, but the problem is that there are also other objects on-screen that are NOT polygons, or that ARE polygons, but carry no texture (for example, raindrop particles are simple lines colored using a light teal/blue/gray mixture). Such items can''t be rendered grayscale even using D3DTOP_DOTPRODUCT3 - which won''t always work. What I''d really need is the way to convert the entire back buffer, pixel by pixel if need there be, to grayscale.

Grayscaling presents a great scenario potential (at least to me) - I''d really like to get this feature implemented in my engine, and that''s the reason that I am so intent on working out a viable solution. So, suggestions?

ps: some of you might have seen a similar grayscale effect in use in the latest edition of zsnes for windows (which DOES use DX8) - anyone out there know the dark of how THAT is done?
(surely there must be some way other than dot product)

-----------<<>>-----------
Flareman (a.k.a Ga1adaN)
Primus ante Adain
flareman@freemail.gr
-----------<<>>------------

Share this post


Link to post
Share on other sites
Rendering the scene to texture then to polygon is rather effective I think for not only can you make a greyscale renderer but you can also play around with all kinds of shaders. In Real Time Rendering: Tricks and Techniques in DirectX, there is good exanmple code for this and also for things like edge detection and blurring.

Share this post


Link to post
Share on other sites
I''ll have that in mind; next time I''m in the bookstore I''ll seek the book out. Till then, some solid code please? Or, at least some general guidelines, just to get me started (not just the "render to a new surface" kind of instructions that the sdk docs include; I can''t make much out of them - some practicalities if you please)

as always, I''m open to suggestions

-----------<<>>-----------
Flareman (a.k.a Ga1adaN)
Primus ante Adain
flareman@freemail.gr
-----------<<>>------------

Share this post


Link to post
Share on other sites
quote:
First of all, resolutions such as 640x480, 800x600 etc. aren''t completely powers of two, as the textures should be (perfect squares, that is), so it''s a bit more complicated (not to mention inefficient) to create a 1024x1024 texture in order to fin a 640x480 frame in it. Of course, if there is a workaround, I''d love to hear it.[/QUOTE]

Well what I was getting at is that you don''t have to have textures of perfect squares. You can have any texture that is a multiple of 2.

Share this post


Link to post
Share on other sites
A surface won''t do, it would have to be a texture you create because you need to be able to set it as a texture when you want to render it to the screen. Basic process for using renderable textures is:

1) CreateTexture() specifying D3DUSAGE_RENDERTARGET.

1a) If you want to use depth buffering call CreateDepthStencilSurface() to make a depth buffer the same dimensions as your texture.

2) Call GetSurfaceLevel() to obtain an IDirect3DSurface8 for the texture.

3) Call IDirect3DDevice8::SetRenderTarget() giving it the surface from #2 (and depth buffer from 1a), now any rendering you do goes into the texture.

4) Call SetRenderTarget() again with the back buffer surface (and your original depth buffer) to render to back buffer again and draw a quad over the screen using your texture.

This method of course assumes that the hardware you''re targetting will support renderable textures, but it sounds like you want to support a pretty wide variety of systems so you might not be able to rely on this method. I can''t think of any other ways that haven''t already been suggested though, but maybe somebody else will.

Well, good luck.

Share this post


Link to post
Share on other sites
I''l see what I can do; one detail, though: when I set the render target back to the back buffer, how do I do it? I mean, should I have acquired the back buffer somehow in advance in order to set it again once the initial pass is done?

-----------<<>>-----------
Flareman (a.k.a Ga1adaN)
Primus ante Adain
flareman@freemail.gr
-----------<<>>------------

Share this post


Link to post
Share on other sites
Yes after you create your device you can use the GetRenderTarget() method to get a pointer to the original back buffer so you can restore it later. Ditto for the depth buffer only the function is called GetDepthStencilSurface().

FYI: Calling these functions will raise the reference count of those surfaces so you''ll want to make sure to do a Release() on them when your rendering code shuts down.

Share this post


Link to post
Share on other sites