// Aqsis // Copyright © 1997 - 2001, Paul C. Gregory // // Contact: pgregory@aqsis.com // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public // License as published by the Free Software Foundation; either // version 2 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // General Public License for more details. // // You should have received a copy of the GNU General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /** \file \brief Implements the CqNoise wrapper class to Noise1234 for producing Perlin noise. \author Paul C. Gregory (pgregory@aqsis.com) \author Stefan Gustavson (stegu76@liu.se) */ #include "aqsis.h" #include "noise.h" #include "noise1234.h" START_NAMESPACE( Aqsis ) // This macro is slightly differently implemented as // FLOOR() in "aqsis_types.h". I could have used that version // instead, but the FLOOR/CEIL/ROUND in "aqsis_types.h" all // seem unnecessarily complicated to me. // This is faster because of fewer conditionals, and rounding // to the nearest integer by using FASTFLOOR(x+0.5) is a lot // faster than using the ROUND() in "aqsis_types.h". #define FASTFLOOR(x) ( ((x)>0) ? ((int)x) : ((int)x-1 ) ) // Carefully chosen but somewhat arbitrary x, y, z, t offsets // for repeated evaluation for vector return types. #define O1x 19.34 #define O1y 7.66 #define O1z 3.23 #define O1t 2.77 #define O2x 5.47 #define O2y 17.85 #define O2z 11.04 #define O2t 13.19 // These are actually never used, because SL has no 4D return types #define O3x 23.54 #define O3y 29.11 #define O3z 31.91 #define O3t 37.48 //--------------------------------------------------------------------- /** 1D float Perlin noise, SL "noise()" */ TqFloat CqNoise::FGNoise1( TqFloat x ) { return ( 0.5f * (1.0f + Noise1234::noise( x ) ) ); } //--------------------------------------------------------------------- /** 1D float Perlin periodic noise, SL "pnoise()" */ TqFloat CqNoise::FGPNoise1( TqFloat x, TqFloat pfx ) { TqInt px; pfx = pfx + 0.5f; px = FASTFLOOR( pfx ); return ( 0.5f * ( 1.0f + Noise1234::pnoise( x, px ) ) ); } //--------------------------------------------------------------------- /** 2D float Perlin noise. */ TqFloat CqNoise::FGNoise2( TqFloat x, TqFloat y ) { return ( 0.5f * ( 1.0f + Noise1234::noise( x, y ) ) ); } //--------------------------------------------------------------------- /** 2D float Perlin periodic noise. */ TqFloat CqNoise::FGPNoise2( TqFloat x, TqFloat y, TqFloat pfx, TqFloat pfy ) { TqInt px, py; pfx = pfx + 0.5; pfy = pfy + 0.5; px = FASTFLOOR( pfx ); py = FASTFLOOR( pfy ); return ( 0.5f * ( 1.0f + Noise1234::pnoise( x, y, px, py ) ) ); } //--------------------------------------------------------------------- /** 3D float Perlin noise. */ TqFloat CqNoise::FGNoise3( const CqVector3D& v ) { TqFloat x, y, z; x = v.x(); y = v.y(); z = v.z(); return ( 0.5f * ( 1.0f + Noise1234::noise( x, y, z ) ) ); } //--------------------------------------------------------------------- /** 3D float Perlin periodic noise. */ TqFloat CqNoise::FGPNoise3( const CqVector3D& v, const CqVector3D& pv ) { TqFloat x, y, z; TqFloat pfx, pfy, pfz; TqInt px, py, pz; x = v.x(); y = v.y(); z = v.z(); pfx = pv.x() + 0.5f; // Temp variables to avoid having the FASTFLOOR() macro pfy = pv.y() + 0.5f; // expand to something that is difficult to optimise. pfz = pv.z() + 0.5f; // (An inline function fastfloor() would be nicer.) px = FASTFLOOR( pfx ); py = FASTFLOOR( pfy ); pz = FASTFLOOR( pfz ); return ( 0.5f * ( 1.0f + Noise1234::pnoise( x, y, z, px, py, pz ) ) ); } //--------------------------------------------------------------------- /** 4D float Perlin noise. */ TqFloat CqNoise::FGNoise4( const CqVector3D& v, TqFloat t ) { TqFloat x, y, z; x = v.x(); y = v.y(); z = v.z(); return ( 0.5f * ( 1.0f + Noise1234::noise( x, y, z, t ) ) ); } //--------------------------------------------------------------------- /** 4D float Perlin periodic noise. */ TqFloat CqNoise::FGPNoise4( const CqVector3D& v, TqFloat t, const CqVector3D& pv, TqFloat pft ) { TqFloat x, y, z; TqFloat pfx, pfy, pfz; TqInt px, py, pz, pt; x = v.x(); y = v.y(); z = v.z(); pfx = pv.x() + 0.5f; // Temp variables to avoid having the FASTFLOOR() macro pfy = pv.y() + 0.5f; // expand to something that is difficult to optimise. pfz = pv.z() + 0.5f; pft = pft + 0.5f; px = FASTFLOOR( pfx ); py = FASTFLOOR( pfy ); pz = FASTFLOOR( pfz ); pt = FASTFLOOR( pft ); return ( 0.5f * ( 1.0f + Noise1234::pnoise( x, y, z, t, px, py, pz, pt ) ) ); } //--------------------------------------------------------------------- /** Vector-valued 1D Perlin noise. */ CqVector3D CqNoise::PGNoise1( TqFloat x ) { TqFloat a, b, c; a = 0.5f * ( 1.0f + Noise1234::noise( x ) ); b = 0.5f * ( 1.0f + Noise1234::noise( x + O1x ) ); c = 0.5f * ( 1.0f + Noise1234::noise( x + O2x ) ); return ( CqVector3D( a, b, c ) ); } //--------------------------------------------------------------------- /** Vector-valued 1D Perlin periodic noise. */ CqVector3D CqNoise::PGPNoise1( TqFloat x, TqFloat pfx ) { TqFloat a, b, c; TqInt px; pfx = pfx + 0.5f; px = FASTFLOOR( pfx ); a = 0.5f * ( 1.0f + Noise1234::pnoise( x, px ) ); b = 0.5f * ( 1.0f + Noise1234::pnoise( x + O1x, px ) ); c = 0.5f * ( 1.0f + Noise1234::pnoise( x + O2x, px ) ); return ( CqVector3D( a, b, c ) ); } //--------------------------------------------------------------------- /** Vector-valued 2D Perlin noise. */ CqVector3D CqNoise::PGNoise2( TqFloat x, TqFloat y ) { TqFloat a, b, c; a = 0.5f * ( 1.0f + Noise1234::noise( x, y ) ); b = 0.5f * ( 1.0f + Noise1234::noise( x + O1x, y + O1y ) ); c = 0.5f * ( 1.0f + Noise1234::noise( x + O2x, y + O2y ) ); return ( CqVector3D( a, b, c ) ); } //--------------------------------------------------------------------- /** Vector-valued 2D Perlin periodic noise. */ CqVector3D CqNoise::PGPNoise2( TqFloat x, TqFloat y, TqFloat pfx, TqFloat pfy ) { TqInt px, py; TqFloat a, b, c; pfx = pfx + 0.5; pfy = pfy + 0.5; px = FASTFLOOR( pfx ); py = FASTFLOOR( pfy ); a = 0.5f * ( 1.0f + Noise1234::pnoise( x, y, px, py ) ); b = 0.5f * ( 1.0f + Noise1234::pnoise( x + O1x, y + O1y, px, py ) ); c = 0.5f * ( 1.0f + Noise1234::pnoise( x + O2x, y + O2y, px, py ) ); return ( CqVector3D( a, b, c ) ); } //--------------------------------------------------------------------- /** Vector-valued 3D Perlin noise. */ CqVector3D CqNoise::PGNoise3( const CqVector3D& v ) { TqFloat x, y, z; TqFloat a, b, c; x = v.x(); y = v.y(); z = v.z(); a = 0.5f * ( 1.0f + Noise1234::noise( x, y, z ) ); b = 0.5f * ( 1.0f + Noise1234::noise( x + O1x, y + O1y, z + O1z ) ); c = 0.5f * ( 1.0f + Noise1234::noise( x + O2x, y + O2y, z + O2z ) ); return ( CqVector3D( a, b, c ) ); } //--------------------------------------------------------------------- /** Vector-valued 3D Perlin periodic noise. */ CqVector3D CqNoise::PGPNoise3( const CqVector3D& v, const CqVector3D& pv ) { TqFloat x, y, z; TqFloat a, b, c; TqFloat pfx, pfy, pfz; TqInt px, py, pz; x = v.x(); y = v.y(); z = v.z(); pfx = pv.x() + 0.5f; // Temp variables to avoid having the FASTFLOOR() macro pfy = pv.y() + 0.5f; // expand to something that is difficult to optimise. pfz = pv.z() + 0.5f; // This might seem stupid, but it *is* actually faster. px = FASTFLOOR(pfx); py = FASTFLOOR(pfy); pz = FASTFLOOR(pfz); a = 0.5f * ( 1.0f + Noise1234::pnoise( x, y, z, px, py, pz ) ); b = 0.5f * ( 1.0f + Noise1234::pnoise( x + O1x, y + O1y, z + O1z, px, py, pz ) ); c = 0.5f * ( 1.0f + Noise1234::pnoise( x + O2x, y + O2y, z + O2z, px, py, pz ) ); return ( CqVector3D ( a, b, c ) ); } //--------------------------------------------------------------------- /** Vector-valued 4D Perlin noise. */ CqVector3D CqNoise::PGNoise4( const CqVector3D& v, TqFloat t ) { TqFloat x, y, z; TqFloat a, b, c; x = v.x(); y = v.y(); z = v.z(); a = 0.5f * ( 1.0f + Noise1234::noise( x, y, z, t ) ); b = 0.5f * ( 1.0f + Noise1234::noise( x + O1x, y + O1y, z + O1z, t + O1t ) ); c = 0.5f * ( 1.0f + Noise1234::noise( x + O2x, y + O2y, z + O2z, t + O2t ) ); return ( CqVector3D( a, b, c ) ); } //--------------------------------------------------------------------- /** Vector-valued 4D Perlin periodic noise. */ CqVector3D CqNoise::PGPNoise4( const CqVector3D& v, TqFloat t, const CqVector3D& pv, TqFloat pft ) { TqFloat x, y, z; TqFloat a, b, c; TqFloat pfx, pfy, pfz; TqInt px, py, pz, pt; x = v.x(); y = v.y(); z = v.z(); pfx = pv.x() + 0.5f; // Temp variables to avoid having the FASTFLOOR() macro pfy = pv.y() + 0.5f; // expand to something that is difficult to optimise. pfz = pv.z() + 0.5f; pft = pft + 0.5f; px = FASTFLOOR( pfx ); py = FASTFLOOR( pfy ); pz = FASTFLOOR( pfz ); pt = FASTFLOOR( pft ); a = 0.5f * ( 1.0f + Noise1234::pnoise( x, y, z, t, px, py, pz, pt ) ); b = 0.5f * ( 1.0f + Noise1234::pnoise( x + O1x, y + O1y, z + O1z, t + O1t, px, py, pz, pt ) ); c = 0.5f * ( 1.0f + Noise1234::pnoise( x + O2x, y + O2y, z + O2z, t + O2t, px, py, pz, pt ) ); return ( CqVector3D( a, b, c ) ); } // The Color noise versions below are all simple conversions from Point noise. // This assumes that Color is always a 3-vector, which is indeed the case now, // but the Ri spec formally allows for an arbitrary number of color components. // A change from RGB to a more general Color class would require changes here. // Hyperspectral renderings are still uncommon, so this is a minor problem. //--------------------------------------------------------------------- /** Color-valued 1D Perlin noise. */ CqColor CqNoise::CGNoise1( TqFloat x ) { return ( CqColor( PGNoise1( x ) ) ); } //--------------------------------------------------------------------- /** Color-valued 1D Perlin periodic noise. */ CqColor CqNoise::CGPNoise1( TqFloat x, TqFloat px ) { return ( CqColor( PGPNoise1( x, px ) ) ); } //--------------------------------------------------------------------- /** Color-valued 2D Perlin noise. */ CqColor CqNoise::CGNoise2( TqFloat x, TqFloat y ) { return ( CqColor( PGNoise2( x, y ) ) ); } //--------------------------------------------------------------------- /** Color-valued 2D Perlin periodic noise. */ CqColor CqNoise::CGPNoise2( TqFloat x, TqFloat y, TqFloat px, TqFloat py ) { return CqColor( PGPNoise2( x, y, px, py ) ); } //--------------------------------------------------------------------- /** Color-valued 3D Perlin noise. */ CqColor CqNoise::CGNoise3( const CqVector3D& v ) { return CqColor( PGNoise3( v ) ); } //--------------------------------------------------------------------- /** Color-valued 3D Perlin periodic noise. */ CqColor CqNoise::CGPNoise3( const CqVector3D& v, const CqVector3D& pv ) { return CqColor( PGPNoise3( v, pv ) ); } //--------------------------------------------------------------------- /** Color-valued 4D Perlin noise. */ CqColor CqNoise::CGNoise4( const CqVector3D& v, TqFloat t ) { return CqColor( PGNoise4( v, t ) ); } //--------------------------------------------------------------------- /** Color-valued 4D Perlin periodic noise. */ CqColor CqNoise::CGPNoise4( const CqVector3D& v, TqFloat t, const CqVector3D& pv, TqFloat pt ) { return CqColor( PGPNoise4( v, t, pv, pt ) ); } END_NAMESPACE( Aqsis ) //---------------------------------------------------------------------