"Fossies" - the Fresh Open Source Software Archive

Member "aqsis-1.8.2/prototypes/newcore/shader.cpp" (24 Aug 2012, 18729 Bytes) of package /linux/privat/aqsis-1.8.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 // Aqsis
    2 // Copyright (C) 2001, Paul C. Gregory and the other authors and contributors
    3 // All rights reserved.
    4 //
    5 // Redistribution and use in source and binary forms, with or without
    6 // modification, are permitted provided that the following conditions are met:
    7 //
    8 // * Redistributions of source code must retain the above copyright notice,
    9 //   this list of conditions and the following disclaimer.
   10 // * Redistributions in binary form must reproduce the above copyright notice,
   11 //   this list of conditions and the following disclaimer in the documentation
   12 //   and/or other materials provided with the distribution.
   13 // * Neither the name of the software's owners nor the names of its
   14 //   contributors may be used to endorse or promote products derived from this
   15 //   software without specific prior written permission.
   16 //
   17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   18 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   19 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   20 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   21 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   22 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   23 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   24 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   25 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   26 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   27 // POSSIBILITY OF SUCH DAMAGE.
   28 //
   29 // (This is the New BSD license)
   30 
   31 #include "shader.h"
   32 
   33 #include <string>
   34 
   35 #include <boost/range/end.hpp>
   36 
   37 #include <aqsis/math/noise.h>
   38 #include <aqsis/math/cellnoise.h>
   39 
   40 #include "grid.h"
   41 #include "gridstorage.h"
   42 #include "util.h"
   43 #include "varspec.h"
   44 
   45 namespace Aqsis {
   46 
   47 //------------------------------------------------------------------------------
   48 /// Pattern functions
   49 inline float triangleWave(float x, float w)
   50 {
   51     return std::abs(x - w*(std::floor(x/w)+0.5));
   52 }
   53 
   54 inline float sawWave(float x, float w)
   55 {
   56     return x - w*std::floor(x/w);
   57 }
   58 
   59 inline V3f reflect(V3f N, V3f I)
   60 {
   61     return I - 2*(N^I) * N;
   62 }
   63 
   64 static CqNoise g_noise;
   65 static CqCellNoise g_cellnoise;
   66 
   67 inline float f_noise(const V3f& p)
   68 {
   69     return g_noise.FGNoise3(CqVector3D(p.x, p.y, p.z));
   70 }
   71 
   72 inline V3f v_noise(const V3f& p)
   73 {
   74     CqVector3D v = g_noise.PGNoise3(CqVector3D(p.x, p.y, p.z));
   75     return V3f(v.x(), v.y(), v.z());
   76 }
   77 
   78 inline float f_cellnoise(const V3f& p)
   79 {
   80     return g_cellnoise.FCellNoise3(CqVector3D(p.x, p.y, p.z));
   81 }
   82 
   83 inline V3f v_cellnoise(const V3f& p)
   84 {
   85     CqVector3D n = g_cellnoise.PCellNoise3(CqVector3D(p.x, p.y, p.z));
   86     return V3f(n.x(), n.y(), n.z());
   87 }
   88 
   89 inline float smoothstep(float min, float max, float x)
   90 {
   91     if(x < min)
   92         return 0;
   93     if(x > max)
   94         return 1;
   95     x = (x - min)/(max - min);
   96     return x*x*(3 - 2*x);
   97 }
   98 
   99 float turbulence(V3f pos, int octaves, float lambda, float omega)
  100 {
  101     float value = 0;
  102     float l = 1;
  103     float o = 1;
  104     for(int i=0; i < octaves; i+=1)
  105     {
  106         value += o*(2*f_noise(pos*l)-1);
  107         l *= lambda;
  108         o *= omega;
  109     }
  110     return value;
  111 }
  112 
  113 float crater(V3f p, float jitter, float overlap, float sharpness)
  114 {
  115     V3f centre(floor(p.x + 0.5), floor(p.y + 0.5), floor(p.z + 0.5));
  116     float amp = 0;
  117     for(int i = -1; i <= 1; i += 1)
  118     for(int j = -1; j <= 1; j += 1)
  119     for(int k = -1; k <= 1; k += 1)
  120     {
  121         V3f cellCentreIjk = centre + V3f(i,j,k);
  122         cellCentreIjk += jitter * v_cellnoise(cellCentreIjk) - V3f(0.5);
  123         float rad = 0.5*overlap*f_cellnoise(cellCentreIjk);
  124         float d = (p - cellCentreIjk).length();
  125         amp = std::min(amp, smoothstep(sharpness*rad, rad, d) - 1);
  126     }
  127     return amp;
  128 }
  129 
  130 inline float specular(V3f N, V3f V, V3f L, float roughness)
  131 {
  132     V3f H = (L + V).normalized();
  133     return std::pow(std::max(0.0f, N^H), 8.0f/roughness);
  134 }
  135 
  136 inline V3f faceforward(V3f N, V3f I)
  137 {
  138     if((I^N) < 0)  // Should use Ng here
  139         return -N;
  140     else
  141         return N;
  142 }
  143 
  144 //------------------------------------------------------------------------------
  145 // Helper mixin class to hold shader input/output variables.
  146 class IOVarHolder : public Shader
  147 {
  148     private:
  149         VarSet m_inputVars;
  150         VarSet m_outputVars;
  151 
  152     protected:
  153         IOVarHolder() : m_inputVars(), m_outputVars() {}
  154 
  155         template<typename T, size_t n>
  156         void setInputVars(const T (&inVars)[n]) { m_inputVars.assign(inVars, inVars+n); }
  157 
  158         template<typename T, size_t n>
  159         void setOutputVars(const T (&outVars)[n]) { m_outputVars.assign(outVars, outVars+n); }
  160 
  161     public:
  162         virtual const VarSet& inputVars() const { return m_inputVars; }
  163         virtual const VarSet& outputVars() const { return m_outputVars; }
  164 };
  165 
  166 
  167 //------------------------------------------------------------------------------
  168 // More or less the usual default surface shader, but without opacity.
  169 class DefaultSurface : public IOVarHolder
  170 {
  171     private:
  172         float m_Kd;
  173         float m_Ka;
  174 
  175     public:
  176         DefaultSurface(const Ri::ParamList& pList)
  177             : m_Kd(0.7),
  178             m_Ka(0.2)
  179         {
  180             if(Ri::FloatArray Kd = pList.findFloat("Kd"))
  181                 m_Kd = Kd[0];
  182             if(Ri::FloatArray Ka = pList.findFloat("Ka"))
  183                 m_Ka = Ka[0];
  184             VarSpec inVars[] = {
  185                 Stdvar::N,
  186                 Stdvar::I,
  187                 Stdvar::Cs
  188             };
  189             setInputVars(inVars);
  190             VarSpec outVars[] = {
  191                 Stdvar::Ci
  192             };
  193             setOutputVars(outVars);
  194         }
  195 
  196         virtual void shade(ShadingContext& ctx, Grid& grid)
  197         {
  198             GridStorage& stor = grid.storage();
  199 
  200             DataView<V3f> N = stor.get(StdIndices::N);
  201             ConstDataView<V3f> I = stor.get(StdIndices::I);
  202             ConstDataView<C3f> Cs = stor.get(StdIndices::Cs);
  203             DataView<C3f> Ci = stor.get(StdIndices::Ci);
  204 
  205             int nshad = stor.nverts();
  206 
  207             for(int i = 0; i < nshad; ++i)
  208             {
  209                 float d = dot(I[i].normalized(), N[i].normalized());
  210                 Ci[i] = Cs[i] * (m_Ka + m_Kd*d*d);
  211             }
  212         }
  213 };
  214 
  215 
  216 //------------------------------------------------------------------------------
  217 /// Displace along normal with a set of sinusoids.
  218 class LumpySin : public IOVarHolder
  219 {
  220     public:
  221         LumpySin(const Ri::ParamList& pList)
  222             : m_useCameraCoords(false),
  223             m_amplitude(0.15),
  224             m_frequency(1)
  225         {
  226             Ri::IntArray useCam = pList.findInt("use_cam_coords");
  227             m_useCameraCoords = useCam && useCam[0] != 0;
  228             if(Ri::FloatArray a = pList.findFloat("amplitude"))
  229                 m_amplitude = a[0];
  230             if(Ri::FloatArray f = pList.findFloat("frequency"))
  231                 m_frequency = f[0];
  232             VarSpec inVars[] = {
  233                 Stdvar::P,
  234                 Stdvar::N,
  235             };
  236             setInputVars(inVars);
  237             VarSpec outVars[] = {
  238                 Stdvar::P,
  239                 Stdvar::N
  240             };
  241             setOutputVars(outVars);
  242         }
  243 
  244         virtual void shade(ShadingContext& ctx, Grid& grid)
  245         {
  246             GridStorage& stor = grid.storage();
  247 
  248             int nshad = stor.nverts();
  249 
  250             // Bind variables to the storage.  Most of these are guarenteed to
  251             // be present on the grid.
  252             DataView<V3f> N = stor.get(StdIndices::N);
  253             DataView<V3f> P = stor.P();
  254 
  255             M44f shaderCoords = ctx.getTransform("world")
  256                             * M44f().setAxisAngle(V3f(1,0,0), deg2rad(45))
  257                             * M44f().setAxisAngle(V3f(0,0,1), deg2rad(10))
  258                             * M44f().setAxisAngle(V3f(0,1,0), deg2rad(45));
  259 
  260             for(int i = 0; i < nshad; ++i)
  261             {
  262                 V3f p = P[i];
  263                 if(!m_useCameraCoords)
  264                     p = p*shaderCoords;
  265                 float amp = m_amplitude/3 *
  266                     (std::sin(m_frequency*10*p.x) +
  267                      std::sin(m_frequency*30*p.y) +
  268                      std::sin(m_frequency*20*p.z));
  269 //                    0.1*(triangleWave(1*p.x, 1) +
  270 //                         triangleWave(3*p.y, 1) +
  271 //                         triangleWave(2*p.z, 1));
  272 //                    0.005*(std::sin(100*p.x) +
  273 //                           std::sin(300*p.y) +
  274 //                           std::sin(200*p.z));
  275                 P[i] += amp*N[i].normalized();
  276             }
  277             grid.calculateNormals(N, P);
  278         }
  279 
  280     private:
  281         bool m_useCameraCoords;
  282         float m_amplitude;
  283         float m_frequency;
  284 };
  285 
  286 
  287 //------------------------------------------------------------------------------
  288 // Spirals in the y-direction with given amplitude and frequency.
  289 class Helix : public IOVarHolder
  290 {
  291     public:
  292         Helix(const Ri::ParamList& pList)
  293             : m_frequency(10),
  294             m_amplitude(0.02)
  295         {
  296             if(Ri::FloatArray f = pList.findFloat("frequency"))
  297                 m_frequency = f[0];
  298             if(Ri::FloatArray a = pList.findFloat("amplitude"))
  299                 m_amplitude = a[0];
  300             VarSpec inVars[] = {
  301                 Stdvar::P,
  302                 Stdvar::N,
  303             };
  304             setInputVars(inVars);
  305             VarSpec outVars[] = {
  306                 Stdvar::P,
  307                 Stdvar::N
  308             };
  309             setOutputVars(outVars);
  310         }
  311 
  312         virtual void shade(ShadingContext& ctx, Grid& grid)
  313         {
  314             GridStorage& stor = grid.storage();
  315 
  316             int nshad = stor.nverts();
  317 
  318             // Bind variables to the storage.  Most of these are guarenteed to
  319             // be present on the grid.
  320             DataView<V3f> N = stor.get(StdIndices::N);
  321             DataView<V3f> P = stor.P();
  322 
  323             M44f shaderCoords = ctx.getTransform("world");
  324             M44f scinv = shaderCoords.inverse();
  325 
  326             for(int i = 0; i < nshad; ++i)
  327             {
  328                 V3f p = P[i]*shaderCoords;
  329                 p += m_amplitude*V3f(std::cos(m_frequency*p.y + p.x), 0,
  330                                       std::sin(m_frequency*p.y + p.x));
  331                 P[i] = p*scinv;
  332             }
  333             grid.calculateNormals(N, P);
  334         }
  335 
  336     private:
  337         float m_frequency;
  338         float m_amplitude;
  339 };
  340 
  341 
  342 //------------------------------------------------------------------------------
  343 /// A lumpy displacement shader with phong lighting.
  344 class Plastic : public IOVarHolder
  345 {
  346     private:
  347         float m_Ka;
  348         float m_Kd;
  349         float m_Ks;
  350         float m_roughness;
  351         C3f m_lightColor;
  352 
  353     public:
  354         Plastic(const Ri::ParamList& pList)
  355             : m_Ka(0.2),
  356             m_Kd(0.5),
  357             m_Ks(0.5),
  358             m_roughness(0.1),
  359             m_lightColor(V3f(1))
  360         {
  361             if(Ri::FloatArray Kd = pList.findFloat("Kd"))
  362                 m_Kd = Kd[0];
  363             if(Ri::FloatArray Ka = pList.findFloat("Ka"))
  364                 m_Ka = Ka[0];
  365             if(Ri::FloatArray Ks = pList.findFloat("Ks"))
  366                 m_Ks = Ks[0];
  367             if(Ri::FloatArray r = pList.findFloat("roughness"))
  368                 m_roughness = r[0];
  369             if(Ri::FloatArray col = pList.findColor("lightcolor"))
  370                 m_lightColor = C3f(col[0], col[1], col[2]);
  371             VarSpec inVars[] = {
  372                 Stdvar::P,
  373                 Stdvar::N,
  374                 Stdvar::I,
  375                 Stdvar::Cs
  376             };
  377             setInputVars(inVars);
  378             VarSpec outVars[] = {
  379                 Stdvar::Ci,
  380                 Stdvar::P,
  381                 Stdvar::N
  382             };
  383             setOutputVars(outVars);
  384         }
  385 
  386         virtual void shade(ShadingContext& ctx, Grid& grid)
  387         {
  388             GridStorage& stor = grid.storage();
  389 
  390             int nshad = stor.nverts();
  391 
  392             //V3f lightPos = V3f(2,2,2) * ctx.getTransform("world").inverse();
  393 
  394             // Bind variables to the storage.  Most of these are guarenteed to
  395             // be present on the grid.
  396             DataView<V3f> N = stor.get(StdIndices::N);
  397             ConstDataView<V3f> I = stor.get(StdIndices::I);
  398             ConstDataView<C3f> Cs = stor.get(StdIndices::Cs);
  399             DataView<C3f> Ci = stor.get(StdIndices::Ci);
  400             if(!Ci)
  401                 return;
  402             DataView<V3f> P = stor.P();
  403 
  404             for(int i = 0; i < nshad; ++i)
  405             {
  406                 V3f nI = I[i].normalized();
  407                 V3f nN = faceforward(N[i].normalized(), I[i]);
  408                 //V3f nL = (P[i] - lightPos).normalized();
  409                 V3f R = reflect(nN, nI);
  410                 Ci[i] = Cs[i] * (m_Ka // ambient
  411                                  + m_Kd*std::abs(nI^nN)) // diffuse
  412                         + m_lightColor*m_Ks*specular(nN, nI, nI, m_roughness); // specular
  413             }
  414         }
  415 };
  416 
  417 
  418 //------------------------------------------------------------------------------
  419 /// Shader to show grids.
  420 class ShowGrids : public IOVarHolder
  421 {
  422     public:
  423         ShowGrids(const Ri::ParamList& pList)
  424         {
  425             VarSpec inVars[] = {
  426                 Stdvar::P,
  427                 Stdvar::N,
  428                 Stdvar::I,
  429             };
  430             setInputVars(inVars);
  431             VarSpec outVars[] = {
  432                 Stdvar::Ci
  433             };
  434             setOutputVars(outVars);
  435         }
  436         virtual void shade(ShadingContext& ctx, Grid& grid)
  437         {
  438             GridStorage& stor = grid.storage();
  439 
  440             DataView<V3f> N = stor.get(StdIndices::N);
  441             ConstDataView<V3f> I = stor.get(StdIndices::I);
  442             DataView<C3f> Ci = stor.get(StdIndices::Ci);
  443 
  444             C3f Cs(ctx.rand(), ctx.rand(), ctx.rand());
  445 
  446             float Kd = 0.8;
  447             float Ka = 0.2;
  448             int nshad = stor.nverts();
  449 
  450             int nu = 1;
  451             int nv = 1;
  452             if(grid.type() == GridType_Quad)
  453             {
  454                 // Ugh!  Would be nice if there was a better way to extract
  455                 // nu & nv generically...
  456                 nu = static_cast<QuadGrid&>(grid).nu();
  457                 nv = static_cast<QuadGrid&>(grid).nv();
  458             }
  459 
  460             for(int i = 0; i < nshad; ++i)
  461             {
  462                 float d = dot(I[i].normalized(), N[i].normalized());
  463                 bool isBoundary = i%nu == 0 || i%nu == nu-1
  464                                   || i/nu == 0 || i/nu == nv-1;
  465                 Ci[i] = Cs*(0.5f*isBoundary + 0.5)  * (Ka + Kd*d*d);
  466             }
  467         }
  468 };
  469 
  470 
  471 //------------------------------------------------------------------------------
  472 /// Shader to show micro polygons
  473 class ShowPolys : public IOVarHolder
  474 {
  475     public:
  476         ShowPolys(const Ri::ParamList& pList)
  477         {
  478             VarSpec inVars[] = {
  479                 Stdvar::P,
  480                 Stdvar::N,
  481                 Stdvar::I,
  482             };
  483             setInputVars(inVars);
  484             VarSpec outVars[] = {
  485                 Stdvar::Ci
  486             };
  487             setOutputVars(outVars);
  488         }
  489         virtual void shade(ShadingContext& ctx, Grid& grid)
  490         {
  491             GridStorage& stor = grid.storage();
  492 
  493             DataView<V3f> N = stor.get(StdIndices::N);
  494             ConstDataView<V3f> I = stor.get(StdIndices::I);
  495             DataView<C3f> Ci = stor.get(StdIndices::Ci);
  496 
  497             float Kd = 0.8;
  498             float Ka = 0.2;
  499             int nshad = stor.nverts();
  500 
  501             for(int i = 0; i < nshad; ++i)
  502             {
  503                 C3f Cs(ctx.rand(), ctx.rand(), ctx.rand());
  504                 float d = dot(I[i].normalized(), N[i].normalized());
  505                 Ci[i] = Cs * (Ka + Kd*d*d);
  506             }
  507         }
  508 };
  509 
  510 
  511 //------------------------------------------------------------------------------
  512 /// Asteroid shader example.
  513 class Asteroid : public IOVarHolder
  514 {
  515     public:
  516         Asteroid(const Ri::ParamList& pList)
  517         {
  518             VarSpec inVars[] = {
  519                 Stdvar::P,
  520                 Stdvar::N,
  521             };
  522             setInputVars(inVars);
  523             VarSpec outVars[] = {
  524                 Stdvar::P,
  525                 Stdvar::N
  526             };
  527             setOutputVars(outVars);
  528         }
  529 
  530         virtual void shade(ShadingContext& ctx, Grid& grid)
  531         {
  532             GridStorage& stor = grid.storage();
  533 
  534             int nshad = stor.nverts();
  535 
  536             M44f currentToWorld = ctx.getTransform("world");
  537 
  538             // Bind variables to the storage.  Most of these are guarenteed to
  539             // be present on the grid.
  540             DataView<V3f> N = stor.get(StdIndices::N);
  541             DataView<V3f> P = stor.P();
  542 
  543             // Displacement
  544             for(int i = 0; i < nshad; ++i)
  545             {
  546                 V3f Pobj = P[i]*currentToWorld;
  547                 float amp = 0.2*(
  548                     0.3*crater(2.0f*Pobj + 0.1f*v_noise(4.0f*Pobj), 0.5, 1, 0.5)
  549                     + 0.1*crater(5.0f*Pobj + 0.2f*v_noise(7.0f*Pobj), 1, 1, 0.6)
  550                     + 0.015*crater(20.0f*Pobj, 1, 1, 0.8)
  551                     ) + 0.1*turbulence(0.5f*Pobj, 8, 2, 0.4);
  552                 P[i] += amp*N[i].normalized();
  553             }
  554             grid.calculateNormals(N, P);
  555         }
  556 };
  557 
  558 
  559 //------------------------------------------------------------------------------
  560 ShaderPtr createShader(const char* name, const Ri::ParamList& pList)
  561 {
  562     if(name == std::string("lumpy_sin"))
  563         return ShaderPtr(new LumpySin(pList));
  564     if(name == std::string("helix"))
  565         return ShaderPtr(new Helix(pList));
  566     else if(name == std::string("plastic"))
  567         return ShaderPtr(new Plastic(pList));
  568     else if(name == std::string("asteroid"))
  569         return ShaderPtr(new Asteroid(pList));
  570     else if(name == std::string("showgrids"))
  571         return ShaderPtr(new ShowGrids(pList));
  572     else if(name == std::string("showpolys"))
  573         return ShaderPtr(new ShowPolys(pList));
  574     else if(name == std::string("default"))
  575         return ShaderPtr(new DefaultSurface(pList));
  576     else
  577         return ShaderPtr();
  578 }
  579 
  580 
  581 //------------------------------------------------------------------------------
  582 // ShadingContext implementation.
  583 ShadingContext::ShadingContext(const M44f& camToWorld)
  584     : m_camToWorld(camToWorld)
  585 {
  586     m_randScale = 1.0f/(m_rand.max() - m_rand.min());
  587 }
  588 
  589 M44f ShadingContext::getTransform(const char* toSpace)
  590 {
  591     if(strcmp(toSpace, "world") == 0)
  592     {
  593         return m_camToWorld;
  594     }
  595     else
  596     {
  597         // TODO
  598         assert(0);
  599         return M44f();
  600     }
  601 }
  602 
  603 float ShadingContext::rand()
  604 {
  605     return m_randScale*(m_rand() - m_rand.min());
  606 }
  607 
  608 } // namespace Aqsis