Renormalization without pixel shaders or cubemap?
category: general [glöplog]
I'm trying to get per-pixel lighting to work (with more than just directional lights) on the iPhone, but it doesn't support cubemaps or fragment programs so I have no idea how to renormalize the interpolated tangent space light vector. Is there any other way to do this? Or maybe a reasonable approximization?
How can you do per-pixel lighting without fragment programs? :|
With the texture combiners. It does support DOT3.
as long as you're only doing diffuse, you may get away without doing any per-pixel normalization at all. you'll need pretty fine geometry for that to work though.
Well, in this particular case I was aiming for point lights close to pretty big polys, so the artifacts are probably unacceptable. Maybe it looks okay with heavy tesselation... I guess I'll just have to try.
well, it doesn't really have to be a cubemap, it's just that appearance of cubemaps coincided with appearance of dot3 on pc hardware and they're pretty suitable since they don't introduce extra distortion. but if no normalization really doesn't work, you can try an inbetween solution and use a spheremap or dual paraboloid map to normalize. both are subject to interpolation-related distortions, though.
just purely about that normalization, if you can set up the stages a bit like with gf2/gf3 reg combiners i think i remember there was a way to normalize when writing a stage result? you could waste a stage on that (renormalizing) if you have enough of 'em.
(something i vaguely remember from xbox 1, should go check out that iphone sometime)
(something i vaguely remember from xbox 1, should go check out that iphone sometime)
Slightly off topic, but what's should i be googling for if i want to calculate the normals for a mesh in the vertex shader? (or better yet, do lighting without normals, if such a thing is possible)
Well if it's a sphere you can just normalize the vector, but that's not what you're looking for right? :) I guess there's no way around accessing other neighbouring vertices for a generic 'always works' solotion. What type of lighting are you looking for, what kind of geometry is it? Special cases might have ways around it.
(a.k.a I'd also like to see someone point his finger in an interesting direction..)
(a.k.a I'd also like to see someone point his finger in an interesting direction..)
maybe you could do something with projected textures..
Doesn't look like that functionality is available in GLES1.1 or through extensions...
Does the iPhone driver not expose GL_OES_texture_cube_map or is there some other reason you wanted to avoid cube maps?
All of the dot3 examples in the POWERVR SDK do not use normalization, they do have relatively highly tessellated models though.
Does the iPhone driver not expose GL_OES_texture_cube_map or is there some other reason you wanted to avoid cube maps?
All of the dot3 examples in the POWERVR SDK do not use normalization, they do have relatively highly tessellated models though.
niels: there was a hack that effectively computed what was either one iteration of a newton-raphson reciprocal square root computation or a one-term taylor expansion centered around 1 - but that worked mainly because the GF3 happened to support just the right constants with their register combiners, not sure if it would work on powervr.
psonice: why not use gl_Normal or gl_NormalMatrix?
ryg, got a link for that hack?
I was trying to figure out if I could do Newton-Raphson in the combiners as I vaguely recall someone mentioning doing this (several years ago), but he could also have been talking about an early version of pixel shaders that did not support square roots... I don't really remember.
Using spheremaps is a good idea though, I'll give that a shot. Thanks!
Using spheremaps is a good idea though, I'll give that a shot. Thanks!
neils: the shape can be "anything", and changes every frame.. I've stuck to simple extruded plain/modified sphere stuff so far as that's easy to handle with 'special case' methods. What would be the best way to calculate the normal in the vertex shader then?
rare: the normals 'exist' there, but bare no relation to the actual geometry, so they're pretty much useless. It's those bits I'm trying to put back without killing performance somewhere :)
rare: the normals 'exist' there, but bare no relation to the actual geometry, so they're pretty much useless. It's those bits I'm trying to put back without killing performance somewhere :)
psonice: without additional information, you can't. A vertex position can be the same for many triangles with completely unrelated normals.
ok, i think it was the taylor expansion variant.
we need: v_norm = v*(1/sqrt(v.x² + v.y² + v.z²))
for f(x) = 1/sqrt(x), we get f(1) = 1 and f'(1) = -1/2, so the taylor expansion around 1 is f(1+h) = 1 - h/2 + O(h²). (in other words, it's just a cheap linear approximation). with that, you get
v_norm = v*(1/sqrt(v.x² + v.y² + v.z²)) =~ v * (1 - 1/2 (v.x² + v.y² + v.z² - 1)) = v * (3/2 - 1/2 (v.x² + v.y² + v.z²)) = v + v * 1/2 * (1 - v.x² - v.y² - v.z²)
in other words, one texture stage doing a dot product of the normal with itself (say into the alpha channel), the next does a multiply-accumulate of v+v*1/2*(1-dotStage.a). you had free invert on gf3 register combiners, you had input shift, not sure how you would do the 1/2 though, probably using one of the bias modes. i never used the combiners directly, so i don't have a clue. in any case, this should be possible (with some shuffling and probably an extra stage). and of course you end up needing an extra dot product after that, so we're already at 3 stages min, possibly 4.
we need: v_norm = v*(1/sqrt(v.x² + v.y² + v.z²))
for f(x) = 1/sqrt(x), we get f(1) = 1 and f'(1) = -1/2, so the taylor expansion around 1 is f(1+h) = 1 - h/2 + O(h²). (in other words, it's just a cheap linear approximation). with that, you get
v_norm = v*(1/sqrt(v.x² + v.y² + v.z²)) =~ v * (1 - 1/2 (v.x² + v.y² + v.z² - 1)) = v * (3/2 - 1/2 (v.x² + v.y² + v.z²)) = v + v * 1/2 * (1 - v.x² - v.y² - v.z²)
in other words, one texture stage doing a dot product of the normal with itself (say into the alpha channel), the next does a multiply-accumulate of v+v*1/2*(1-dotStage.a). you had free invert on gf3 register combiners, you had input shift, not sure how you would do the 1/2 though, probably using one of the bias modes. i never used the combiners directly, so i don't have a clue. in any case, this should be possible (with some shuffling and probably an extra stage). and of course you end up needing an extra dot product after that, so we're already at 3 stages min, possibly 4.
psonice, you might be able to use dFdx/dFdy to do what you want.
ryg, cheers, I might give that a go.
I think OpenGL ES 1.1 does not support multiply-accumulate, but it does support GL_INTERPOLATE so maybe you could set up the stages like this:
stage 1: dot3(v,v) -> alpha
stage 2: lerp(1,previous.a,3/2) -> alpha
stage 3: modulate(v,previous.a) -> rgb
stage 4: dot3(normalmap, previous.rgb) -> rgb
Unfortunately... ES 1.1 only supports two texture stages, and I'm not even sure you can set the third argument of lerp to values > 1. I don't see a way to spread the 4 stages over 2 passes, or maybe I'm missing something obvious?
I'm confident spheremaps will work out fine though. I don't think anyone will notice the small distortions caused by interpolation on such a tiny screen.
stage 1: dot3(v,v) -> alpha
stage 2: lerp(1,previous.a,3/2) -> alpha
stage 3: modulate(v,previous.a) -> rgb
stage 4: dot3(normalmap, previous.rgb) -> rgb
Unfortunately... ES 1.1 only supports two texture stages, and I'm not even sure you can set the third argument of lerp to values > 1. I don't see a way to spread the 4 stages over 2 passes, or maybe I'm missing something obvious?
I'm confident spheremaps will work out fine though. I don't think anyone will notice the small distortions caused by interpolation on such a tiny screen.
ryg: that's what i'm talking about -- and yeah that 1/2 was done using a bias operation.
was company code (and i'm no longer there) so i don't have any access to that 5 y/o stuff alas. not that anyone would benefit from gf3 register combiner structs here :)
was company code (and i'm no longer there) so i don't have any access to that 5 y/o stuff alas. not that anyone would benefit from gf3 register combiner structs here :)
HAVE YOU TRIED glEnabel(GL_NORMALISE)?!???????????
Mr. theMoose: the normals end up with no relation to the actual mesh, so it's not going to help..
Pete: interesting, I wasn't aware of the dFdx stuff. That might work somehow, or at least help. Then again, that tiny corner of my brain that deals with maths took a good look and decided to have a quick lie down :)
Pete: interesting, I wasn't aware of the dFdx stuff. That might work somehow, or at least help. Then again, that tiny corner of my brain that deals with maths took a good look and decided to have a quick lie down :)