normalmaps mipmaps mathematica playground

13
In[1]:= H* Load a normalmap, convert to floats and remap it to the -1, 1 range, resize to make it more manageable... *L normalMap = ImageApply@Normalize@- 0.5D &, Image@ImageResize@Import@"C:\\Users\\angelo.pesce\\Desktop\\4.jpg"D, 128D, "Real"D D Out[1]=

Upload: c0de517eblogspotcom

Post on 07-Oct-2014

821 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Normalmaps mipmaps Mathematica playground

In[1]:= H* Load a normalmap, convert to floats and remap it to the -1,

1 range, resize to make it more manageable... *LnormalMap = ImageApply@Normalize@ð - 0.5D &,

Image@ImageResize@Import@"C:\\Users\\angelo.pesce\\Desktop\\4.jpg"D, 128D, "Real"DD

Out[1]=

Page 2: Normalmaps mipmaps Mathematica playground

In[2]:= H* We'll need a mean to operate on sub-blocks of an image,

let's write a small helper function that does these operations in parallell *LblockImageMap@img_, fn_, size_D := Parallelize@Map@fn, ImagePartition@img, sizeD, 82<DD

H* Let's compute the average normal for the blocks,

we could have done it wiht another

ImageResize but it's also a test of blockImageMap... *LblockSize = 16;

averagedNormals = blockImageMap@normalMap,

Normalize@Apply@Plus, Flatten@ImageData@ðD, 1DDD &, blockSizeD;

Image@averagedNormalsDaveragedNormals = Flatten@averagedNormals, 1D;

Out[5]=

2 normalmapFit.nb

Page 3: Normalmaps mipmaps Mathematica playground

In[7]:=

H* We're not going to use a four-dimensional Phong BRDF,

we'll cheat reduce Phong to a simple lobe around the normal,

like a "powered" diffuse *LH* Let me motivate this a bit: let's say that we have a cone-

Phong which takes a cone of normals and a light direction. The light around

the normal reflection direction around the cone will be a cone whose

size is equal to the normal cone no matter where the light direction is,

thus this cone-Phong will have a constant lobe which just

rotates as the light direction changes,

so we can ignore the light direction and just construct a lobe

around the normalHsL instead, which we do here.*LcosFn@n_, exp_, a_, b_D := [email protected]@bD * Sin@aD, Sin@bD * Sin@aD, Cos@aD<, 0.D^exp

H* Let's see how that looks like when we start

averaging different lobes around a bunch of normals *LaggregateCosFn = Compile@88nlist, _Real, 2<, exp, a, b<,

Mean@Map@n Ì [email protected]@bD * Sin@aD, Sin@bD * Sin@aD, Cos@aD<, 0.D^exp, nlistDDD;

someTestNormals =

880., 0., 1.<, 80., 1., 0.<, 80., 0.7071067811865475, 0.7071067811865475<<;

someTestData = Flatten@Table@8a, b, aggregateCosFn@someTestNormals, 5., a, bD<,

8a, 0., Pi, 0.01<, 8b, -Pi � 2, Pi � 2, 0.01<D, 1D; �� AbsoluteTiming

testPlot = SphericalPlot3D@aggregateCosFn@someTestNormals, 5., a, bD,

8a, -Pi � 2., Pi � 2.<, 8b, 0., Pi<, PlotRange ® FullDOut[10]= 80.6400640, Null<

CompiledFunction::cfsa : Argument a at position 3 should be a machine-size real number. �

normalmapFit.nb 3

Page 4: Normalmaps mipmaps Mathematica playground

Out[11]=

4 normalmapFit.nb

Page 5: Normalmaps mipmaps Mathematica playground

In[12]:= H* Ok, now let's say that we are fine with a

normal that is the average of the normals in the budle,

we won't cosider that as a parameter... we want to fit a

single lobe that fits well around the ones in the bundle... *LtestNormal = Normalize@Plus �� someTestNormalsDH* cosFn=Compile@88n,_Real,1<,exp,a,b<,

[email protected]@bD*Sin@aD,Sin@bD*Sin@aD,Cos@aD<,0.D^expD *LtestFit = FindFit@someTestData, mul * cosFn@testNormal, N@expD, a, bD, 8mul, exp<, 8a, b<DtestFitPlot = SphericalPlot3D@Hmul * cosFn@testNormal, exp, a, bDL �. testFit,

8a, -Pi � 2., Pi � 2.<, 8b, 0., Pi<, PlotRange ® FullD;

Show@testPlot, testFitPlotDOut[12]= 80., 0.707107, 0.707107<

Out[13]= 8mul ® 0.437587, exp ® 1.3201<

Out[15]=

In[16]:= H* Same as before,

but let's visualize the actual aggregated lobes for all the blocks in our image. *LbaseExponent = 15. ; H* We assume that the "original" Phong exponent is a constant,

no gloss map. That also motivates the fact that we

don't fit the normals but just use the average later on *LH* All these graphs take quite some time to compute... *LaggregateGraphs = blockImageMap@normalMap,

SphericalPlot3D@aggregateCosFn@Flatten@ImageData@ðD, 1D, baseExponent, a, bD,

8a, -Pi � 2., Pi � 2.<, 8b, 0., Pi<, PlotRange ® FullD &

, blockSizeD;

aggregateGraphs �� Grid

Out[17]=

normalmapFit.nb 5

Page 6: Normalmaps mipmaps Mathematica playground

Out[17]=

6 normalmapFit.nb

Page 7: Normalmaps mipmaps Mathematica playground

Out[17]=

normalmapFit.nb 7

Page 8: Normalmaps mipmaps Mathematica playground

Out[17]=

In[18]:= H* Now let's do it "for real" and not only on our test case... This

will sample the aggretageCosFn for all the blocks in the image *LbigTableStep = 0.1;

bigTable = Flatten@blockImageMap@normalMap,

Flatten@Table@8a, b, aggregateCosFn@Flatten@ImageData@ðD, 1D, baseExponent, a, bD<,

8a, 0., Pi, bigTableStep<, 8b, -Pi � 2, Pi � 2, bigTableStep<D, 1D &

, blockSizeD, 1D;

8 normalmapFit.nb

Page 9: Normalmaps mipmaps Mathematica playground

In[20]:= On@AssertDAssert@Length@averagedNormalsD == Length@bigTableDDH* And this will do all the fits... *LmulExpFit = Parallelize@

MapIndexed@FindFit@ð1, mul * cosFn@averagedNormals@@First@ð2DDD, N@expD, a, bD,

8mul, exp<, 8a, b<D &, bigTableDDOut[22]= 88mul ® 0.618805, exp ® 8.89502<, 8mul ® 0.598644, exp ® 8.51412<,

8mul ® 0.532327, exp ® 7.89826<, 8mul ® 0.477471, exp ® 6.5503<,

8mul ® 0.340919, exp ® 4.43919<, 8mul ® 0.276318, exp ® 3.27376<,

8mul ® 0.239627, exp ® 2.56283<, 8mul ® 0.203344, exp ® 2.24956<,

8mul ® 0.641131, exp ® 9.08297<, 8mul ® 0.654242, exp ® 9.53887<,

8mul ® 0.551036, exp ® 7.94867<, 8mul ® 0.507081, exp ® 6.8086<,

8mul ® 0.244188, exp ® 2.90802<, 8mul ® 0.303832, exp ® 4.30447<,

8mul ® 0.221055, exp ® 2.5569<, 8mul ® 0.213842, exp ® 2.6156<,

8mul ® 0.52463, exp ® 8.39447<, 8mul ® 0.566446, exp ® 8.5677<,

8mul ® 0.432999, exp ® 6.17545<, 8mul ® 0.635317, exp ® 9.14319<,

8mul ® 0.275543, exp ® 3.27375<, 8mul ® 0.37205, exp ® 5.46512<,

8mul ® 0.222615, exp ® 2.83855<, 8mul ® 0.205707, exp ® 2.32635<,

8mul ® 0.297381, exp ® 3.65126<, 8mul ® 0.453345, exp ® 6.01124<,

8mul ® 0.380706, exp ® 5.5091<, 8mul ® 0.474217, exp ® 8.23652<,

8mul ® 0.294879, exp ® 3.78966<, 8mul ® 0.269861, exp ® 3.16145<,

8mul ® 0.213934, exp ® 2.2836<, 8mul ® 0.236978, exp ® 2.93404<,

8mul ® 0.577994, exp ® 8.49755<, 8mul ® 0.336856, exp ® 4.13611<,

8mul ® 0.367468, exp ® 4.02667<, 8mul ® 0.33009, exp ® 3.96973<,

8mul ® 0.383339, exp ® 4.77278<, 8mul ® 0.407135, exp ® 5.56801<,

8mul ® 0.428866, exp ® 6.55542<, 8mul ® 0.430458, exp ® 5.99862<,

8mul ® 0.805292, exp ® 12.181<, 8mul ® 0.773268, exp ® 11.6552<,

8mul ® 0.837642, exp ® 12.5788<, 8mul ® 0.864366, exp ® 13.018<,

8mul ® 0.857893, exp ® 12.9482<, 8mul ® 0.818741, exp ® 12.3182<,

8mul ® 0.752328, exp ® 11.1784<, 8mul ® 0.819131, exp ® 12.5493<,

8mul ® 0.792982, exp ® 11.9456<, 8mul ® 0.802381, exp ® 12.0445<,

8mul ® 0.788424, exp ® 11.5308<, 8mul ® 0.808138, exp ® 11.5349<,

8mul ® 0.807078, exp ® 11.8358<, 8mul ® 0.799556, exp ® 11.4176<,

8mul ® 0.821676, exp ® 11.8566<, 8mul ® 0.813524, exp ® 12.0381<,

8mul ® 0.907429, exp ® 13.9459<, 8mul ® 0.879497, exp ® 13.5577<,

8mul ® 0.880625, exp ® 13.787<, 8mul ® 0.872389, exp ® 13.6939<,

8mul ® 0.880505, exp ® 13.8098<, 8mul ® 0.834215, exp ® 13.3251<,

8mul ® 0.867259, exp ® 13.9305<, 8mul ® 0.895466, exp ® 14.0431<<In[23]:= fitGraphs = Parallelize@MapIndexed@

SphericalPlot3D@Hmul * cosFn@averagedNormals@@First@ð2DDD, exp, a, bDL �. ð1, 8a,

-Pi � 2., Pi � 2.<, 8b, 0., Pi<, PlotRange ® Full, MeshStyle ® NoneD &, mulExpFitDD;

H* Let's still display graphs as a grid, but as fitGraphs is a list

we have to convert it to a table first... *LWith@8sideLength = Sqrt@Length@fitGraphsDD<,

Table@Show@fitGraphs@@j + i * sideLengthDD, aggregateGraphs@@i + 1, jDDD, 8i, 0, sideLength - 1<, 8j, sideLength<D

D �� Grid

Out[24]=

normalmapFit.nb 9

Page 10: Normalmaps mipmaps Mathematica playground

Out[24]=

10 normalmapFit.nb

Page 11: Normalmaps mipmaps Mathematica playground

Out[24]=

normalmapFit.nb 11

Page 12: Normalmaps mipmaps Mathematica playground

Out[24]=

In[37]:= normalLengths = blockImageMap@normalMap,

Norm@Apply@Plus, Flatten@ImageData@ðD, 1DD � blockSize^2D &, blockSizeD;

Image@normalLengthsDnormalLengths = Flatten@normalLengths, 1D;

Out[38]=

12 normalmapFit.nb

Page 13: Normalmaps mipmaps Mathematica playground

H* Let's follow some of the ideas here http:��developer.nvidia.com�content�mipmapping-normal-maps -

is there a relation between averaged vector lengths and the phong exponent? *LH* We interleave the elements of normalLengths with the exponents from the

fit solutions, then group everything two elements at a time, then plot... *LlengthAndExponent =

Partition@Riffle@normalLengths, Map@sol Ì baseExponent � Hexp �. solL, mulExpFitDD, 2D;

ListPlot@lengthAndExponentD

Out[53]=

0.86 0.88 0.90 0.92 0.94 0.96 0.98

1

2

3

4

5

6

In[54]:= linearLengthExponentFit = Fit@lengthAndExponent, 81, x<, xD

Out[54]= 34.3097 - 33.9931 x

normalmapFit.nb 13