Archive: How can I refer to single pixels to change colors?


17th May 2006 09:23 UTC

How can I refer to single pixels to change colors?
Hi, I apologize if someone has answered this question previously. I'm making my first visualization, and having trouble. I want to have a simple spectrum analyzer, with about 8-10 vertical bars with gaps between them, rather than the entire spectrum. I want these bars to be composed of thin sections to make an interlaced effect. I am currently using Trans / Interleave to black out the portions of the screen that are between bars, and to black out horizontal lines to create the interlaced effect that I want.

The problem I have is that the Render / Simple spectrum analyzer in the background isn't divided into 8-10 neat vertical bars. Some of the wider bars that I am choosing to show are nearly filled with the spectrum analyzer, while some have two or three pixels extending far above the others. Here's a picture of what I have currently:

http://www.fileden.com/files/18968/p...20spectrum.bmp

I want to level these off so they don't have irregular tops. The way I think I could do this would be to take the first column in each of the 10 sections. For each pixel in this column, copy it to the 7 pixels to the right. This will make an eight pixel wide column that is one solid color, which is what I want. I don't know how to actually copy the pixels to the right though. A formula that I think could work would be something like this:



x%8=offset
red=(if(abs(equal(offset,0)-1),red(x-offset),red(x)));
blue=(if(abs(equal(offset,0)-1),blue(x-offset),blue(x)));
green=(if(abs(equal(offset,0)-1),green(x-offset),green(x)));


This will set the variable "offset" to the remainder of the x coordinate divided by 8. (Now that I think about it - where is the origin in rectangular coordinate mode? I may have to modify this to be abs(x%8)=offset.)

This will next check the value of abs(equal(offset,0)-1. If offset is nonzero (the X coordinate is one of the first columns in the large sections that I'm looking for,) this will return 1. If offset is 0(the X coordinate is to the right of one of the first columns,) this will return 0.

The rest of this code section will replace the color values of pixel x with those of x - offset. Here's my problem. I don't know the syntax for this. So can anyone help me by showing me exactly how I can copy the colors from one pixel to another?


Thanks,
Isaac

*edit* uploaded .avs file to here

17th May 2006 09:45 UTC

You can't read and write individual pixels in the framebuffer unfortunately, it is one of the few things AVS cannot do. However you can usually create the effect you want without needing to access pixels directly.

In your case the problem is that you are rendering basically what you want with simple components, then looking for a way to post-process that to make the effect you want. The right way to do it would be to drop the render/simple and use a render/superscope; that will give you much more control over how the spectrum is rendered in the first place.

You essentially need to render a seperate vertical bar for different parts of the spectrum, which you can do with one or many superscopes. I wont paste code for doing it here though, I'll just point you to the tutorials and programming guide


17th May 2006 10:01 UTC

Thanks, I'll read through these.


17th May 2006 11:38 UTC

Alright, after reading some of those guides, I've come up with this:

http://www.fileden.com/files/18968/I...ectrum%202.avs

I think it's much improved but I still have two problems. There are still single lines visible during the visualization playback - I'm sure this is due to rendering or something, not my code, because whenever I click the plus sign to add another effect it pauses the visualization view, and when paused the tops of each bar are always level. Also, at the high end of the spectrum, the bar occasionally peaks higher than the top of the visualization window. Rather than changing the code of the SuperScope, is there a simple way to black out everything in the top 10% of the screen?

*edit* For the first problem, I think that the screen's just tearing... how can I set it to a hard 30 fps?


17th May 2006 12:10 UTC

the hax are strong with this one

Thats not a bad first effort but let me steer you towards a nicer solution...

Rather than use 'i' to define the x of your bars, try using it to define the y since that is the primary direction. Since i has a value of 0-1 based on which point it is rendering (1-n) you can just multiply it by the sound data and you will have a variable that goes from 0 to <amplitude>. The x position you actually just want as a fixed value, you can give the bar width by simply changing the linesize variable. You also want the spectrum data to be based on the x postion, not y.

Here is an example bar:

n=2;
drawmode=1;
linesize=10;
x=-0.8;
y=-i*getspec(x*0.5+0.5,0.1,0);

[edit] There is an APE to limit frame rate, but you can enable wait for retrace in the display options[/edit]


17th May 2006 19:20 UTC

Excellent! Thanks, this is a much more elegant solution. It works perfectly now.


17th May 2006 21:33 UTC

Can a mod close this topic, I want this preserved forever;

Guy comes to the forums with a question, gets help

TEH PERFECT THREAD!!1


18th May 2006 00:36 UTC

Originally posted by PAK-9
You can't read and write individual pixels in the framebuffer unfortunately, it is one of the few things AVS cannot do.
Just for the record you can actually write to the framebuffer a pixel at a time by using a superscope to draw points, since each point is a pixel you can convert x and y into screen space 0..width and 0..height with a simple scaling. This doesnt help for reading though...

18th May 2006 13:16 UTC

Well, yes, technically speaking you could read & write pixels either by:

o - Using the ridiculously slow per pixel ape
o - Using the gmegabuf/megabuf as a framebuffer and 'rendering' it with a superscope; which would give you pixel read/write capability assuming you made your whole preset using the (g)megabuf