| Author | Topics » Book an abo for this thread |  |
MegaManJuno Strong supporter
 

Status:Offline Date registered: 28.02.2006 Post:34 Send Message | Created on 28.02.2006 - 17:20 |  |
Hi guys,
I came across Maruke's excellent CComic shader in this forum a while back and wanted to take it in more of a cel-shaded direction than the washed out comic book look in the original.
Maruke, I will not post the code here unless I have your permission to do so, since it was based on your initial code.
This is my first attempt at any GLSL coding, and will probably be the only thing I ever work on for Pete's OpenGL2 plugin.
EDIT: Maruke has approved my release of the shader, built upon his CComic shader as a base. Here's the code you'll need for your SLV and SLF files (note as this is a WIP, it's subject to change from time to time as I test different games and try to balance out color adjustment problems):
SLV:
| Code: | | 1: | | 2: | | 3: | | 4: | | 5: | | 6: | | 7: | | 8: | | 9: | | 10: | | 11: | | 12: | | 13: | | 14: | | 15: | | 16: | | 17: | | 18: | | 19: | | 20: | | 21: | | 22: | | 23: | | | | // Special thanks go out to Maruke for his CComic shader,
| // and for allowing me to release this shader based upon his work.
| // -----------
| // MegaManJuno
|
| uniform vec4 OGL2InvSize;
|
| void main() {
| vec4 offset;
|
| gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
|
| gl_TexCoord[0] = gl_MultiTexCoord0.xyxy;
|
| offset.xy = -(offset.zw = vec2(0.0, OGL2InvSize.y));
| gl_TexCoord[1] = gl_TexCoord[0] + offset;
|
| offset.xy = -(offset.zw = vec2(OGL2InvSize.x, 0.0));
| gl_TexCoord[2] = gl_TexCoord[0] + offset;
|
| offset.xy = -(offset.zw = vec2(OGL2InvSize.x, OGL2InvSize.y));
| gl_TexCoord[3] = gl_TexCoord[1] + offset;
| | } | |
SLF:
| Code: | | 1: | | 2: | | 3: | | 4: | | 5: | | 6: | | 7: | | 8: | | 9: | | 10: | | 11: | | 12: | | 13: | | 14: | | 15: | | 16: | | 17: | | 18: | | 19: | | 20: | | 21: | | 22: | | 23: | | 24: | | 25: | | 26: | | 27: | | 28: | | 29: | | 30: | | 31: | | 32: | | 33: | | 34: | | 35: | | 36: | | 37: | | 38: | | 39: | | 40: | | 41: | | 42: | | 43: | | 44: | | 45: | | 46: | | 47: | | 48: | | 49: | | 50: | | 51: | | 52: | | 53: | | 54: | | 55: | | 56: | | 57: | | 58: | | 59: | | 60: | | 61: | | 62: | | 63: | | 64: | | 65: | | 66: | | 67: | | 68: | | 69: | | 70: | | 71: | | 72: | | 73: | | 74: | | 75: | | 76: | | 77: | | 78: | | 79: | | 80: | | 81: | | 82: | | 83: | | 84: | | 85: | | 86: | | 87: | | 88: | | 89: | | 90: | | 91: | | 92: | | 93: | | 94: | | 95: | | | | // Special thanks go out to Maruke for his CComic shader,
| // and for allowing me to release this shader based upon his work.
| // -----------
| // MegaManJuno
|
| uniform sampler2D OGL2Texture;
| uniform vec4 OGL2Param;
|
| vec3 colorAdjust(in vec3 cRGB) {
| float avg, m;
|
| //average RGB values
| avg = (max(cRGB[2], max(cRGB[0], cRGB[1])) + min(cRGB[2], min(cRGB[0], cRGB[1])) + ((cRGB[0] + cRGB[1] + cRGB[2]) / 3.0)) / 3.0;
|
| m = (OGL2Param.z + 1.0) / 4.0;
|
| if(avg >= 0.95) {
| return(cRGB);
| } else if(avg >= 0.8) {
| return(cRGB + vec3((0.95 - avg) * m));
|
| } else if(avg >= 0.75) {
| return(cRGB - vec3((avg - 0.75) * m));
| } else if(avg >= 0.6) {
| return(cRGB + vec3((0.75 - avg) * m));
|
| } else if(avg >= 0.5) {
| return(cRGB - vec3((avg - 0.5) * m));
| } else if(avg >= 0.4) {
| return(cRGB + vec3((0.5 - avg) * m));
|
| } else if(avg >= 0.25) {
| return(cRGB - vec3((avg - 0.25) * m));
| } else if(avg >= 0.2) {
| return(cRGB + vec3((0.25 - avg) * m));
|
| } else if(avg >= 0.05) {
| return(cRGB - vec3((avg - 0.05) * m));
| } else {
| return(cRGB);
| }
| }
|
| void main() {
| vec3 h, o, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9;
| vec3 cz, cz0, cz1, cz2, cz3, cz5, cz6, cz7, cz8;
| float i, k;
|
| //brightness adjust before applying colorAdjust function
| o = vec3(1.20); //20% brighter
|
| c0 = (texture2D(OGL2Texture, gl_TexCoord[3].xy).rgb * o);
| c1 = (texture2D(OGL2Texture, gl_TexCoord[2].xy).rgb * o);
| c2 = (texture2D(OGL2Texture, gl_TexCoord[3].zy).rgb * o);
| c3 = (texture2D(OGL2Texture, gl_TexCoord[1].xy).rgb * o);
| c4 = (texture2D(OGL2Texture, gl_TexCoord[0].xy).rgb * o);
| c5 = (texture2D(OGL2Texture, gl_TexCoord[1].zw).rgb * o);
| c6 = (texture2D(OGL2Texture, gl_TexCoord[3].xw).rgb * o);
| c7 = (texture2D(OGL2Texture, gl_TexCoord[2].zw).rgb * o);
| c8 = (texture2D(OGL2Texture, gl_TexCoord[3].zw).rgb * o);
|
| c9 = (c4 + ((c0 + c1 + c2 + c3 + c5 + c6 + c7 + c8) / 8.0)) / 2.0;
|
| o = vec3(1.0);
|
| h = vec3(0.003);
| k = 0.001;
|
| cz0 = (c0 + h) / (dot(o, c0) + k);
| cz1 = (c1 + h) / (dot(o, c1) + k);
| cz2 = (c2 + h) / (dot(o, c2) + k);
| cz3 = (c3 + h) / (dot(o, c3) + k);
| cz = (c9 + h) / (dot(o, c9) + k);
| cz5 = (c5 + h) / (dot(o, c5) + k);
| cz6 = (c6 + h) / (dot(o, c6) + k);
| cz7 = (c7 + h) / (dot(o, c7) + k);
| cz8 = (c8 + h) / (dot(o, c8) + k);
|
| k = 0.01;
|
| h = (cz - cz0); i = k / (dot(h, h) + k);
| h = (cz - cz1); i += k / (dot(h, h) + k);
| h = (cz - cz2); i += k / (dot(h, h) + k);
| h = (cz - cz3); i += k / (dot(h, h) + k);
| h = (cz - cz5); i += k / (dot(h, h) + k);
| h = (cz - cz6); i += k / (dot(h, h) + k);
| h = (cz - cz7); i += k / (dot(h, h) + k);
| h = (cz - cz8); i += k / (dot(h, h) + k);
|
| i /= 8.0;
|
| c9 = min(o, min(c9, c9 + dot(o, c9))) * i;
|
| gl_FragColor.rgb = (c9 + colorAdjust(c9)) / 2.0;
| | } | |
[Dieser Beitrag wurde am 17.04.2006 - 00:39 von MegaManJuno aktualisiert]
Signature |
|
|
rama  Strong supporter
 

Status:Offline Date registered: 18.11.2005 Post:43 Send Message | Created on 01.03.2006 - 20:23 |  |
That's a really nice enhancement.
I'd like to see that shader released ^^
|
MegaManJuno Strong supporter
 

Status:Offline Date registered: 28.02.2006 Post:34 Send Message | Created on 02.03.2006 - 02:00 |  |
Thanks.
I still have a few little things I'd like to try with it, but thought I'd post a little here about it and see if anyone else would be interested in it.
Does anyone (especially ShadX, since you seem to have worked with him on some shaders in the past) know if maruke still visits the forums at all? I'd just like to make sure he's OK with me releasing it into the wild, since it was his code I used as a base. (And it might help to bounce a few questions off of him if he'd be willing).
Signature |
ShadX  Real addict
  

Status:Offline Date registered: 20.01.2005 Post:267 Send Message | Created on 02.03.2006 - 11:00 |  |
You can visit the Chris's homepage and send a mail to him.
See the mail me line...
Bye:)
[Dieser Beitrag wurde am 02.03.2006 - 11:01 von ShadX aktualisiert]
|
MegaManJuno Strong supporter
 

Status:Offline Date registered: 28.02.2006 Post:34 Send Message | Created on 03.03.2006 - 07:15 |  |
Thanks, ShadX. I'll give his email a try.
Although I got to thinking, and since this part is my own code apart from maruke's shader, I'll go ahead and post this piece here. If anyone wants to use it in another shader, or wants to modify it in any way, you are welcome to do so.
vec3 colorAdjust(in vec3 colorRGB) {
float av;
float cutoffA, cutoffB, cutoffC;
cutoffA = 0.666; cutoffB = 0.495; cutoffC = 0.333;
//average the highest and lowest RGB values
av = (max(colorRGB[2], max(colorRGB[0], colorRGB[1])) + min(colorRGB[2], min(colorRGB[0], colorRGB[1]))) / 2.0;
if(av > cutoffA)
//lighten output color more as original color gets darker
colorRGB = colorRGB * (1.0 + pow(1.0 - av, 2.0));
else if(av > cutoffB)
//darken output color more as original color gets brighter
colorRGB = colorRGB * (1.0 - pow((cutoffA - av) / 2.0, 2.0));
else if(av > cutoffC)
//lighten output color more as original color gets darker
colorRGB = colorRGB * (1.0 + pow((cutoffB - av) * 2.0, 2.0));
else
//darken output color more as original color gets brighter
colorRGB = colorRGB * (1.0 - pow(cutoffB - av, 2.0));
return(colorRGB);
}
Currently, I'm using this right when setting the gl_FragColor at the end of the fragment shader, so it looks something like this:
gl_FragColor.rgb = colorAdjust(color_variable_you_want_to_modify.rgb);
This function was the initial piece I put together which led to other small modifications to try and tweak the output somewhat. Unfortunately, from what I've read and my understanding so far, I don't think I can currently do the remaining part I wanted to with this without multipass support. I'd like to be able to adjust the color, then do some blending (possibly edge-detected blurring would work?) on the result to help smooth out the edge lines where the color cutoffs take place.
Currently, it generally looks pretty good on games that make heavy use of gouraud shading (like the FF7 example shots above). In games with more textures (and 2D games), it sometimes leaves some harsh jagged edges I'd like to smooth out some, without losing the overall color cutoff effect.
If anyone has any suggestions, I'd be happy to listen, if it would even be possible in a single pass...?
Signature |
MegaManJuno Strong supporter
 

Status:Offline Date registered: 28.02.2006 Post:34 Send Message | Created on 05.03.2006 - 06:44 |  |
guest schrieb
>>gl_FragColor.rgb = colorAdjust(color_variable_you_want_to_modify.rgb);
gl_FragColor.rgb = colorAdjust(gl_FragColor.rgb);
can be added at the end of the shader.
PS: Saw some Dragon Quest VIII screenshots recently. Link. Think that's the "desired look" of a comic gfx...
|
Yes, by "color_variable_you_want_to_modify" I just meant any randomly named color variable you wanted to use, and did not mean that was the actual name of what I was using. I'm actually doing it the way you suggested.
As for the Dragon Quest 8 shots, I would consider that more of a "comic book" look myself, where I am shooting for more of an anime type of look (where the hard edged, 2-tone or 3-tone shading is more common).
I have no clue what style other people are looking for in a cel/comic/toon shader. Honestly, I'm doing this because it's what I want to see, regardless of what anyone else wants. I just thought I'd see if there was any interest in it being released when I'm finished tweaking it, by posting some info here and seeing what kind of feedback I got from it.
Without trying to sound like an ass by saying this, I don't really care what other people want to see in a shader. ...That being said, I'll gladly accept suggestions and ideas on how to improve it, but don't be upset if I don't agree and don't use them. If it gets released, then someone else can modify it for thier own personal wants and needs.
Oh, and just for the record, this part wasn't specifically directed at you guest. It was just a response in general.
For anyone who wants to see more shots, I've got a few others over on my putfile.com page (www.putfile.com/megamanjuno), and will be uploading some more in the next few days from some other games as well.
I've been swamped with a project from work the past week, so I haven't done anything with the shader in the past few days, and haven't gotten around to emailing maruke yet. Hopefully, next week I'll have more free time to work on it.
Signature |
MegaManJuno Strong supporter
 

Status:Offline Date registered: 28.02.2006 Post:34 Send Message | Created on 05.03.2006 - 11:19 |  |
guest schrieb
Ehe!
The desired look follows from the definition of Cartoon, Comic, Toon's graphics (if there aren't any, they should be made). Like for "sephia", "noir"...
Best way for doing this, IMHO, is by giving some good "representive samples" of such native game gfx. I think it's the most constructive way.
|
In a perfect world, it would be that simple. In reality though, many games handle it differently, much as 2 different people can draw the same thing by hand and end up with different results. There's too many different styles of hand-drawn anime, comic book, cartoon, etc. artwork (and various game styles that fall in the "cel-shaded" group) to try and do them all with an "all-in-one" shader. Personal preference plays a big part in it as well, so that leaves us with different shaders for different effects that share some similar qualities (color manipulation being the major one).
Go look up screenshots of XIII or Zelda: Wind Waker in google or something for just 2 different looks from how Dragon Quest 8 looks for a quick example.
Signature |
rama  Strong supporter
 

Status:Offline Date registered: 18.11.2005 Post:43 Send Message | Created on 05.03.2006 - 16:32 |  |
..but the shader looks good already ^^
If there could only be some magically applied HQ3X in it :D
|
ShadX  Real addict
  

Status:Offline Date registered: 20.01.2005 Post:267 Send Message | Created on 07.03.2006 - 17:22 |  |
If someone could test this shader...
gpuPeteOGL2.slv:
void main()
{
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
gl_TexCoord[0] = gl_MultiTexCoord0;
}
gpuPeteOGL2.slf:
const mat3 YIQ = mat3(0.299, 0.596, 0.212,
0.587,-0.275,-0.523,
0.114,-0.321, 0.311);
const mat3 invYIQ = mat3( 1.0, 1.0, 1.0,
0.9557,-0.2716,-1.1082,
0.6199,-0.6469, 1.7051);
uniform sampler2D OGL2Texture;
uniform vec4 OGL2InvSize;
uniform vec4 OGL2Size;
uniform vec4 OGL2Param;
void main ()
{
float GrayLevels = OGL2Param.z + 4.0;
vec4 coord = (OGL2Size * gl_TexCoord[0]) - 0.5;
vec4 weight = fract(coord);
coord = OGL2InvSize * floor(coord);
vec3 sample = mix(mix(texture2D( OGL2Texture, coord.xy ),
texture2D( OGL2Texture, coord.xy + OGL2InvSize.xy * vec2( 1.0, 0.0)),
weight.x),
mix(texture2D( OGL2Texture, coord.xy + OGL2InvSize.xy * vec2( 0.0, 1.0)),
texture2D( OGL2Texture, coord.xy + OGL2InvSize.xy ),
weight.x),
weight.y).rgb;
sample = YIQ * sample;
sample.x = floor(sample.x * GrayLevels + 0.5);
sample.x /= GrayLevels;
sample = invYIQ * sample;
gl_FragColor = vec4( sample, 0.0);
}
Bye
[Dieser Beitrag wurde am 08.03.2006 - 09:35 von ShadX aktualisiert]
|
rama  Strong supporter
 

Status:Offline Date registered: 18.11.2005 Post:43 Send Message | Created on 07.03.2006 - 19:17 |  |
Hmm, am I doing something wrong here?
I'm getting an error "cannot call nonexisting function"
in line 18.
|