mirror of
https://gitea.wildfiregames.com/0ad/0ad
synced 2026-06-16 05:13:58 -07:00
Added Perlin noise class, which will be useful for water.
This was SVN commit r3871.
This commit is contained in:
parent
4879b98fc7
commit
18eb72a25a
10 changed files with 334 additions and 1 deletions
160
source/maths/Noise.cpp
Normal file
160
source/maths/Noise.cpp
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
#include "precompiled.h"
|
||||
#include "Noise.h"
|
||||
#include <cmath>
|
||||
#include <boost/random.hpp>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace
|
||||
{
|
||||
/// Random number generator (Boost Mersenne Twister)
|
||||
boost::mt19937 rng;
|
||||
|
||||
/// Utility function for random numbers
|
||||
float randFloat() {
|
||||
return ((float)rng()) / 4294967296.0f;
|
||||
}
|
||||
|
||||
/// Utility function used in both noises as an ease curve
|
||||
float easeCurve(float t)
|
||||
{
|
||||
return t*t*t*(t*(t*6-15)+10);
|
||||
}
|
||||
}
|
||||
|
||||
Noise2D::Noise2D(int f)
|
||||
{
|
||||
freq = f;
|
||||
grads = new CVector2D*[freq];
|
||||
for(int i=0; i<freq; i++)
|
||||
{
|
||||
grads[i] = new CVector2D[freq];
|
||||
for(int j=0; j<freq; j++)
|
||||
{
|
||||
float a = randFloat() * 2 * M_PI;
|
||||
grads[i][j] = CVector2D(cos(a), sin(a));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Noise2D::~ Noise2D()
|
||||
{
|
||||
for(int i=0; i<freq; i++)
|
||||
{
|
||||
delete[] grads[i];
|
||||
}
|
||||
delete[] grads;
|
||||
}
|
||||
|
||||
float Noise2D::operator()(float x, float y)
|
||||
{
|
||||
x *= freq;
|
||||
y *= freq;
|
||||
|
||||
int ix = floor(x);
|
||||
int iy = floor(y);
|
||||
|
||||
float fx = x - ix;
|
||||
float fy = y - iy;
|
||||
|
||||
ix %= freq; if(ix<0) ix += freq;
|
||||
iy %= freq; if(iy<0) iy += freq;
|
||||
|
||||
int ix1 = (ix+1) % freq;
|
||||
int iy1 = (iy+1) % freq;
|
||||
|
||||
float s = grads[ix][iy].Dot(CVector2D(fx, fy));
|
||||
float t = grads[ix1][iy].Dot(CVector2D(fx-1, fy));
|
||||
float u = grads[ix][iy1].Dot(CVector2D(fx, fy-1));
|
||||
float v = grads[ix1][iy1].Dot(CVector2D(fx-1, fy-1));
|
||||
|
||||
float ex = easeCurve(fx);
|
||||
float ey = easeCurve(fy);
|
||||
float a = s + ex*(t-s);
|
||||
float b = u + ex*(v-u);
|
||||
return (a + ey*(b-a)) * .5 + .5;
|
||||
}
|
||||
|
||||
Noise3D::Noise3D(int f, int v) : freq(f), vfreq(v)
|
||||
{
|
||||
grads = new CVector3D**[freq];
|
||||
for(int i=0; i<freq; i++)
|
||||
{
|
||||
grads[i] = new CVector3D*[freq];
|
||||
for(int j=0; j<freq; j++)
|
||||
{
|
||||
grads[i][j] = new CVector3D[vfreq];
|
||||
for(int k=0; k<vfreq; k++)
|
||||
{
|
||||
CVector3D v;
|
||||
do {
|
||||
v = CVector3D(2*randFloat()-1, 2*randFloat()-1, 2*randFloat()-1);
|
||||
}
|
||||
while(v.LengthSquared() > 1 || v.LengthSquared() < 0.1);
|
||||
v.Normalize();
|
||||
grads[i][j][k] = CVector3D(v.X, v.Y, v.Z);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Noise3D::~ Noise3D()
|
||||
{
|
||||
for(int i=0; i<freq; i++)
|
||||
{
|
||||
for(int j=0; j<freq; j++)
|
||||
{
|
||||
delete[] grads[i][j];
|
||||
}
|
||||
delete[] grads[i];
|
||||
}
|
||||
delete[] grads;
|
||||
}
|
||||
|
||||
float Noise3D::operator()(float x, float y, float z)
|
||||
{
|
||||
x *= freq;
|
||||
y *= freq;
|
||||
z *= vfreq;
|
||||
|
||||
int ix = floor(x);
|
||||
int iy = floor(y);
|
||||
int iz = floor(z);
|
||||
|
||||
float fx = x - ix;
|
||||
float fy = y - iy;
|
||||
float fz = z - iz;
|
||||
|
||||
ix %= freq; if(ix<0) ix += freq;
|
||||
iy %= freq; if(iy<0) iy += freq;
|
||||
iz %= vfreq; if(iz<0) iz += vfreq;
|
||||
|
||||
int ix1 = (ix+1) % freq;
|
||||
int iy1 = (iy+1) % freq;
|
||||
int iz1 = (iz+1) % vfreq;
|
||||
|
||||
float s0 = grads[ix][iy][iz].Dot(CVector3D(fx, fy, fz));
|
||||
float t0 = grads[ix1][iy][iz].Dot(CVector3D(fx-1, fy, fz));
|
||||
float u0 = grads[ix][iy1][iz].Dot(CVector3D(fx, fy-1, fz));
|
||||
float v0 = grads[ix1][iy1][iz].Dot(CVector3D(fx-1, fy-1, fz));
|
||||
|
||||
float s1 = grads[ix][iy][iz1].Dot(CVector3D(fx, fy, fz-1));
|
||||
float t1 = grads[ix1][iy][iz1].Dot(CVector3D(fx-1, fy, fz-1));
|
||||
float u1 = grads[ix][iy1][iz1].Dot(CVector3D(fx, fy-1, fz-1));
|
||||
float v1 = grads[ix1][iy1][iz1].Dot(CVector3D(fx-1, fy-1, fz-1));
|
||||
|
||||
float ex = easeCurve(fx);
|
||||
float ey = easeCurve(fy);
|
||||
float ez = easeCurve(fz);
|
||||
|
||||
float a0 = s0 + ex*(t0-s0);
|
||||
float b0 = u0 + ex*(v0-u0);
|
||||
float c0 = a0 + ey*(b0-a0);
|
||||
|
||||
float a1 = s1 + ex*(t1-s1);
|
||||
float b1 = u1 + ex*(v1-u1);
|
||||
float c1 = a1 + ey*(b1-a1);
|
||||
|
||||
return (c0 + ez*(c1-c0)) * .5 + .5;
|
||||
}
|
||||
|
||||
54
source/maths/Noise.h
Normal file
54
source/maths/Noise.h
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Name: Noise.h
|
||||
// Author: Matei Zaharia
|
||||
// Contact: matei@wildfiregames.com
|
||||
//
|
||||
// Description: 2D and 3D seamless Perlin noise classes. Not optimized for speed yet.
|
||||
//
|
||||
// Based on http://www.cs.cmu.edu/~mzucker/code/perlin-noise-math-faq.html
|
||||
// and http://mrl.nyu.edu/~perlin/paper445.pdf.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef NOISE_H
|
||||
#define NOISE_H
|
||||
|
||||
#include "Vector2D.h"
|
||||
#include "Vector3D.h"
|
||||
#include "MathUtil.h"
|
||||
|
||||
class Noise2D
|
||||
{
|
||||
/// Frequency in X and Y
|
||||
int freq;
|
||||
|
||||
/// freq*freq random gradient vectors in the unit cube
|
||||
CVector2D** grads;
|
||||
public:
|
||||
Noise2D(int freq);
|
||||
~Noise2D();
|
||||
|
||||
/// Evaluate the noise function at a given point
|
||||
float operator() (float x, float y);
|
||||
};
|
||||
|
||||
class Noise3D
|
||||
{
|
||||
/// Frequency in X and Y
|
||||
int freq;
|
||||
|
||||
/// Frequency in Z (vertical frequency)
|
||||
int vfreq;
|
||||
|
||||
/// freq*freq*vfreq random gradient vectors in the unit cube
|
||||
CVector3D*** grads;
|
||||
public:
|
||||
Noise3D(int freq, int vfreq);
|
||||
~Noise3D();
|
||||
|
||||
/// Evaluate the noise function at a given point
|
||||
float operator() (float x, float y, float z);
|
||||
};
|
||||
|
||||
#endif
|
||||
99
source/maths/Vector2D.h
Normal file
99
source/maths/Vector2D.h
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
//***********************************************************
|
||||
//
|
||||
// Name: CVector2D.h
|
||||
// Author: Matei Zaharia
|
||||
//
|
||||
// Description: Provides an interface for a vector in R4 and
|
||||
// allows vector and scalar operations on it
|
||||
//
|
||||
//***********************************************************
|
||||
|
||||
#ifndef VECTOR2D_H
|
||||
#define VECTOR2D_H
|
||||
|
||||
|
||||
#include <math.h>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// CVector2D:
|
||||
class CVector2D
|
||||
{
|
||||
public:
|
||||
CVector2D() {}
|
||||
CVector2D(float x,float y) { X=x; Y=y; }
|
||||
CVector2D(const CVector2D& p) { X=p.X; Y=p.Y; }
|
||||
|
||||
operator float*() {
|
||||
return &X;
|
||||
}
|
||||
|
||||
operator const float*() const {
|
||||
return &X;
|
||||
}
|
||||
|
||||
CVector2D operator-() const {
|
||||
return CVector2D(-X, -Y);
|
||||
}
|
||||
|
||||
CVector2D operator+(const CVector2D& t) const {
|
||||
return CVector2D(X+t.X, Y+t.Y);
|
||||
}
|
||||
|
||||
CVector2D operator-(const CVector2D& t) const {
|
||||
return CVector2D(X-t.X, Y-t.Y);
|
||||
}
|
||||
|
||||
CVector2D operator*(float f) const {
|
||||
return CVector2D(X*f, Y*f);
|
||||
}
|
||||
|
||||
CVector2D operator/(float f) const {
|
||||
float inv=1.0f/f;
|
||||
return CVector2D(X*inv, Y*inv);
|
||||
}
|
||||
|
||||
CVector2D& operator+=(const CVector2D& t) {
|
||||
X+=t.X; Y+=t.Y;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CVector2D& operator-=(const CVector2D& t) {
|
||||
X-=t.X; Y-=t.Y;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CVector2D& operator*=(float f) {
|
||||
X*=f; Y*=f;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CVector2D& operator/=(float f) {
|
||||
float invf=1.0f/f;
|
||||
X*=invf; Y*=invf;
|
||||
return *this;
|
||||
}
|
||||
|
||||
float Dot(const CVector2D& a) const {
|
||||
return X*a.X + Y*a.Y;
|
||||
}
|
||||
|
||||
float LengthSquared() const {
|
||||
return Dot(*this);
|
||||
}
|
||||
|
||||
float Length() const {
|
||||
return (float) sqrt(LengthSquared());
|
||||
}
|
||||
|
||||
void Normalize() {
|
||||
float mag=Length();
|
||||
X/=mag; Y/=mag;
|
||||
}
|
||||
|
||||
public:
|
||||
float X, Y;
|
||||
};
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -117,9 +117,15 @@ CVector3D CVector3D::Cross (const CVector3D &vector) const
|
|||
return Temp;
|
||||
}
|
||||
|
||||
|
||||
float CVector3D::LengthSquared () const
|
||||
{
|
||||
return ( SQR(X) + SQR(Y) + SQR(Z) );
|
||||
}
|
||||
|
||||
float CVector3D::GetLength () const
|
||||
{
|
||||
return sqrtf ( SQR(X) + SQR(Y) + SQR(Z) );
|
||||
return sqrtf ( LengthSquared() );
|
||||
}
|
||||
|
||||
void CVector3D::Normalize ()
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ class CVector3D
|
|||
|
||||
//Returns length of the vector
|
||||
float GetLength () const;
|
||||
float LengthSquared () const;
|
||||
void Normalize ();
|
||||
|
||||
// Returns 3 element array of floats, e.g. for glVertex3fv
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ bool g_NoGLVBO=false;
|
|||
bool g_NoGLFramebufferObject = false;
|
||||
// flag to switch on shadows
|
||||
bool g_Shadows=false;
|
||||
// flag to switch on reflective/refractive water
|
||||
bool g_FancyWater=false;
|
||||
// flag to switch on fixed frame timing (RC: I'm using this for profiling purposes)
|
||||
bool g_FixedFrameTiming=false;
|
||||
bool g_VSync = false;
|
||||
|
|
@ -72,6 +74,7 @@ static void LoadGlobals()
|
|||
CFG_GET_USER_VAL("novbo", Bool, g_NoGLVBO);
|
||||
CFG_GET_USER_VAL("noframebufferobject", Bool, g_NoGLFramebufferObject);
|
||||
CFG_GET_USER_VAL("shadows", Bool, g_Shadows);
|
||||
CFG_GET_USER_VAL("fancywater", Bool, g_FancyWater);
|
||||
CFG_GET_USER_VAL("renderpath", String, g_RenderPath);
|
||||
|
||||
CFG_GET_USER_VAL("lodbias", Float, g_LodBias);
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ extern bool g_NoGLVBO;
|
|||
extern bool g_NoGLFramebufferObject;
|
||||
// flag to switch on shadows
|
||||
extern bool g_Shadows;
|
||||
// flag to switch on reflective/refractive water
|
||||
extern bool g_FancyWater;
|
||||
// flag to switch on fixed frame timing (RC: I'm using this for profiling purposes)
|
||||
extern bool g_FixedFrameTiming;
|
||||
extern bool g_VSync;
|
||||
|
|
|
|||
|
|
@ -667,6 +667,7 @@ static void InitRenderer()
|
|||
g_Renderer.SetOptionBool(CRenderer::OPT_NOVBO,g_NoGLVBO);
|
||||
g_Renderer.SetOptionBool(CRenderer::OPT_NOFRAMEBUFFEROBJECT,g_NoGLFramebufferObject);
|
||||
g_Renderer.SetOptionBool(CRenderer::OPT_SHADOWS,g_Shadows);
|
||||
g_Renderer.SetOptionBool(CRenderer::OPT_FANCYWATER,g_FancyWater);
|
||||
g_Renderer.SetRenderPath(CRenderer::GetRenderPathByName(g_RenderPath));
|
||||
g_Renderer.SetOptionFloat(CRenderer::OPT_LODBIAS, g_LodBias);
|
||||
|
||||
|
|
|
|||
|
|
@ -552,6 +552,9 @@ void CRenderer::SetOptionBool(enum Option opt,bool value)
|
|||
case OPT_SHADOWS:
|
||||
m_Options.m_Shadows=value;
|
||||
break;
|
||||
case OPT_FANCYWATER:
|
||||
m_Options.m_FancyWater=value;
|
||||
break;
|
||||
default:
|
||||
debug_warn("CRenderer::SetOptionBool: unknown option");
|
||||
break;
|
||||
|
|
@ -569,6 +572,8 @@ bool CRenderer::GetOptionBool(enum Option opt) const
|
|||
return m_Options.m_NoFramebufferObject;
|
||||
case OPT_SHADOWS:
|
||||
return m_Options.m_Shadows;
|
||||
case OPT_FANCYWATER:
|
||||
return m_Options.m_FancyWater;
|
||||
default:
|
||||
debug_warn("CRenderer::GetOptionBool: unknown option");
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -91,6 +91,7 @@ public:
|
|||
OPT_NOVBO,
|
||||
OPT_NOFRAMEBUFFEROBJECT,
|
||||
OPT_SHADOWS,
|
||||
OPT_FANCYWATER,
|
||||
OPT_LODBIAS
|
||||
};
|
||||
|
||||
|
|
@ -136,6 +137,7 @@ public:
|
|||
bool m_NoVBO;
|
||||
bool m_NoFramebufferObject;
|
||||
bool m_Shadows;
|
||||
bool m_FancyWater;
|
||||
float m_LodBias;
|
||||
RenderPath m_RenderPath;
|
||||
} m_Options;
|
||||
|
|
|
|||
Loading…
Reference in a new issue