#
root/OpenSceneGraph/trunk/src/osgUtil/PerlinNoise.cpp
@
13041

Revision 13041, 8.3 kB (checked in by robert, 3 years ago) |
---|

Line | |
---|---|

1 | /* OpenSceneGraph example, osgshaders. |

2 | * |

3 | * Permission is hereby granted, free of charge, to any person obtaining a copy |

4 | * of this software and associated documentation files (the "Software"), to deal |

5 | * in the Software without restriction, including without limitation the rights |

6 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |

7 | * copies of the Software, and to permit persons to whom the Software is |

8 | * furnished to do so, subject to the following conditions: |

9 | * |

10 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |

11 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |

12 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |

13 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |

14 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |

15 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |

16 | * THE SOFTWARE. |

17 | */ |

18 | |

19 | /************************************************************************ |

20 | * * |

21 | * Copyright (C) 2002 3Dlabs Inc. Ltd. * |

22 | * * |

23 | ************************************************************************/ |

24 | |

25 | /* Adapted from osgshaders example by Robert Osfield for use as part of osgUtil.*/ |

26 | |

27 | #include <math.h> |

28 | #include <stdlib.h> |

29 | |

30 | #include <osgUtil/PerlinNoise> |

31 | |

32 | using namespace osgUtil; |

33 | |

34 | /* Coherent noise function over 1, 2 or 3 dimensions */ |

35 | /* (copyright Ken Perlin) */ |

36 | |

37 | #define N 0x1000 |

38 | #define NP 12 /* 2^N */ |

39 | #define NM 0xfff |

40 | |

41 | #define s_curve(t) ( t * t * (3. - 2. * t) ) |

42 | #define lerp(t, a, b) ( a + t * (b - a) ) |

43 | #define setup(i,b0,b1,r0,r1)\ |

44 | t = vec[i] + N;\ |

45 | b0 = ((int)t) & BM;\ |

46 | b1 = (b0+1) & BM;\ |

47 | r0 = t - (int)t;\ |

48 | r1 = r0 - 1.; |

49 | #define at2(rx,ry) ( rx * q[0] + ry * q[1] ) |

50 | #define at3(rx,ry,rz) ( rx * q[0] + ry * q[1] + rz * q[2] ) |

51 | |

52 | |

53 | PerlinNoise::PerlinNoise() |

54 | { |

55 | SetNoiseFrequency(1); |

56 | } |

57 | |

58 | void PerlinNoise::SetNoiseFrequency(int frequency) |

59 | { |

60 | start = 1; |

61 | B = frequency; |

62 | BM = B-1; |

63 | } |

64 | |

65 | double PerlinNoise::noise1(double arg) |

66 | { |

67 | int bx0, bx1; |

68 | double rx0, rx1, sx, t, u, v, vec[1]; |

69 | |

70 | vec[0] = arg; |

71 | if (start) { |

72 | start = 0; |

73 | initNoise(); |

74 | } |

75 | |

76 | setup(0,bx0,bx1,rx0,rx1); |

77 | |

78 | sx = s_curve(rx0); |

79 | u = rx0 * g1[ p[ bx0 ] ]; |

80 | v = rx1 * g1[ p[ bx1 ] ]; |

81 | |

82 | return(lerp(sx, u, v)); |

83 | } |

84 | |

85 | double PerlinNoise::noise2(double vec[2]) |

86 | { |

87 | int bx0, bx1, by0, by1, b00, b10, b01, b11; |

88 | double rx0, rx1, ry0, ry1, *q, sx, sy, a, b, t, u, v; |

89 | int i, j; |

90 | |

91 | if (start) { |

92 | start = 0; |

93 | initNoise(); |

94 | } |

95 | |

96 | setup(0, bx0,bx1, rx0,rx1); |

97 | setup(1, by0,by1, ry0,ry1); |

98 | |

99 | i = p[ bx0 ]; |

100 | j = p[ bx1 ]; |

101 | |

102 | b00 = p[ i + by0 ]; |

103 | b10 = p[ j + by0 ]; |

104 | b01 = p[ i + by1 ]; |

105 | b11 = p[ j + by1 ]; |

106 | |

107 | sx = s_curve(rx0); |

108 | sy = s_curve(ry0); |

109 | |

110 | q = g2[ b00 ] ; u = at2(rx0,ry0); |

111 | q = g2[ b10 ] ; v = at2(rx1,ry0); |

112 | a = lerp(sx, u, v); |

113 | |

114 | q = g2[ b01 ] ; u = at2(rx0,ry1); |

115 | q = g2[ b11 ] ; v = at2(rx1,ry1); |

116 | b = lerp(sx, u, v); |

117 | |

118 | return lerp(sy, a, b); |

119 | } |

120 | |

121 | double PerlinNoise::noise3(double vec[3]) |

122 | { |

123 | int bx0, bx1, by0, by1, bz0, bz1, b00, b10, b01, b11; |

124 | double rx0, rx1, ry0, ry1, rz0, rz1, *q, sy, sz, a, b, c, d, t, u, v; |

125 | int i, j; |

126 | |

127 | if (start) { |

128 | start = 0; |

129 | initNoise(); |

130 | } |

131 | |

132 | setup(0, bx0,bx1, rx0,rx1); |

133 | setup(1, by0,by1, ry0,ry1); |

134 | setup(2, bz0,bz1, rz0,rz1); |

135 | |

136 | i = p[ bx0 ]; |

137 | j = p[ bx1 ]; |

138 | |

139 | b00 = p[ i + by0 ]; |

140 | b10 = p[ j + by0 ]; |

141 | b01 = p[ i + by1 ]; |

142 | b11 = p[ j + by1 ]; |

143 | |

144 | t = s_curve(rx0); |

145 | sy = s_curve(ry0); |

146 | sz = s_curve(rz0); |

147 | |

148 | q = g3[ b00 + bz0 ] ; u = at3(rx0,ry0,rz0); |

149 | q = g3[ b10 + bz0 ] ; v = at3(rx1,ry0,rz0); |

150 | a = lerp(t, u, v); |

151 | |

152 | q = g3[ b01 + bz0 ] ; u = at3(rx0,ry1,rz0); |

153 | q = g3[ b11 + bz0 ] ; v = at3(rx1,ry1,rz0); |

154 | b = lerp(t, u, v); |

155 | |

156 | c = lerp(sy, a, b); |

157 | |

158 | q = g3[ b00 + bz1 ] ; u = at3(rx0,ry0,rz1); |

159 | q = g3[ b10 + bz1 ] ; v = at3(rx1,ry0,rz1); |

160 | a = lerp(t, u, v); |

161 | |

162 | q = g3[ b01 + bz1 ] ; u = at3(rx0,ry1,rz1); |

163 | q = g3[ b11 + bz1 ] ; v = at3(rx1,ry1,rz1); |

164 | b = lerp(t, u, v); |

165 | |

166 | d = lerp(sy, a, b); |

167 | |

168 | //fprintf(stderr, "%f\n", lerp(sz, c, d)); |

169 | |

170 | return lerp(sz, c, d); |

171 | } |

172 | |

173 | void PerlinNoise::normalize2(double v[2]) |

174 | { |

175 | double s; |

176 | |

177 | s = sqrt(v[0] * v[0] + v[1] * v[1]); |

178 | v[0] = v[0] / s; |

179 | v[1] = v[1] / s; |

180 | } |

181 | |

182 | void PerlinNoise::normalize3(double v[3]) |

183 | { |

184 | double s; |

185 | |

186 | s = sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); |

187 | v[0] = v[0] / s; |

188 | v[1] = v[1] / s; |

189 | v[2] = v[2] / s; |

190 | } |

191 | |

192 | void PerlinNoise::initNoise(void) |

193 | { |

194 | int i, j, k; |

195 | |

196 | srand(30757); |

197 | for (i = 0 ; i < B ; i++) { |

198 | p[i] = i; |

199 | g1[i] = (double)((rand() % (B + B)) - B) / B; |

200 | |

201 | for (j = 0 ; j < 2 ; j++) |

202 | g2[i][j] = (double)((rand() % (B + B)) - B) / B; |

203 | normalize2(g2[i]); |

204 | |

205 | for (j = 0 ; j < 3 ; j++) |

206 | g3[i][j] = (double)((rand() % (B + B)) - B) / B; |

207 | normalize3(g3[i]); |

208 | } |

209 | |

210 | while (--i) { |

211 | k = p[i]; |

212 | p[i] = p[j = rand() % B]; |

213 | p[j] = k; |

214 | } |

215 | |

216 | for (i = 0 ; i < B + 2 ; i++) { |

217 | p[B + i] = p[i]; |

218 | g1[B + i] = g1[i]; |

219 | for (j = 0 ; j < 2 ; j++) |

220 | g2[B + i][j] = g2[i][j]; |

221 | for (j = 0 ; j < 3 ; j++) |

222 | g3[B + i][j] = g3[i][j]; |

223 | } |

224 | } |

225 | |

226 | /* --- My harmonic summing functions - PDB --------------------------*/ |

227 | |

228 | /* |

229 | In what follows "alpha" is the weight when the sum is formed. |

230 | Typically it is 2, As this approaches 1 the function is noisier. |

231 | "beta" is the harmonic scaling/spacing, typically 2. |

232 | */ |

233 | |

234 | double PerlinNoise::PerlinNoise1D(double x,double alpha,double beta,int n) |

235 | { |

236 | int i; |

237 | double val,sum = 0; |

238 | double p,scale = 1; |

239 | |

240 | p = x; |

241 | for (i=0;i<n;i++) { |

242 | val = noise1(p); |

243 | sum += val / scale; |

244 | scale *= alpha; |

245 | p *= beta; |

246 | } |

247 | return(sum); |

248 | } |

249 | |

250 | double PerlinNoise::PerlinNoise2D(double x,double y,double alpha,double beta,int n) |

251 | { |

252 | int i; |

253 | double val,sum = 0; |

254 | double p[2],scale = 1; |

255 | |

256 | p[0] = x; |

257 | p[1] = y; |

258 | for (i=0;i<n;i++) { |

259 | val = noise2(p); |

260 | sum += val / scale; |

261 | scale *= alpha; |

262 | p[0] *= beta; |

263 | p[1] *= beta; |

264 | } |

265 | return(sum); |

266 | } |

267 | |

268 | double PerlinNoise::PerlinNoise3D(double x,double y,double z,double alpha,double beta,int n) |

269 | { |

270 | int i; |

271 | double val,sum = 0; |

272 | double p[3],scale = 1; |

273 | |

274 | p[0] = x; |

275 | p[1] = y; |

276 | p[2] = z; |

277 | for (i=0;i<n;i++) { |

278 | val = noise3(p); |

279 | sum += val / scale; |

280 | scale *= alpha; |

281 | p[0] *= beta; |

282 | p[1] *= beta; |

283 | p[2] *= beta; |

284 | } |

285 | return(sum); |

286 | } |

287 | |

288 | osg::Image* PerlinNoise::create3DNoiseImage(int texSize) |

289 | { |

290 | osg::Image* image = new osg::Image; |

291 | image->setImage(texSize, texSize, texSize, |

292 | 4, GL_RGBA, GL_UNSIGNED_BYTE, |

293 | new unsigned char[4 * texSize * texSize * texSize], |

294 | osg::Image::USE_NEW_DELETE); |

295 | |

296 | const int startFrequency = 4; |

297 | const int numOctaves = 4; |

298 | |

299 | int f, i, j, k, inc; |

300 | double ni[3]; |

301 | double inci, incj, inck; |

302 | int frequency = startFrequency; |

303 | GLubyte *ptr; |

304 | double amp = 0.5; |

305 | |

306 | osg::notify(osg::INFO) << "creating 3D noise texture... "; |

307 | |

308 | for (f = 0, inc = 0; f < numOctaves; ++f, frequency *= 2, ++inc, amp *= 0.5) |

309 | { |

310 | SetNoiseFrequency(frequency); |

311 | ptr = image->data(); |

312 | ni[0] = ni[1] = ni[2] = 0; |

313 | |

314 | inci = 1.0 / (texSize / frequency); |

315 | for (i = 0; i < texSize; ++i, ni[0] += inci) |

316 | { |

317 | incj = 1.0 / (texSize / frequency); |

318 | for (j = 0; j < texSize; ++j, ni[1] += incj) |

319 | { |

320 | inck = 1.0 / (texSize / frequency); |

321 | for (k = 0; k < texSize; ++k, ni[2] += inck, ptr += 4) |

322 | { |

323 | *(ptr+inc) = (GLubyte) (((noise3(ni) + 1.0) * amp) * 128.0); |

324 | } |

325 | } |

326 | } |

327 | } |

328 | |

329 | osg::notify(osg::INFO) << "DONE" << std::endl; |

330 | return image; |

331 | } |

332 | |

333 | osg::Texture3D* PerlinNoise::create3DNoiseTexture(int texSize ) |

334 | { |

335 | osg::Texture3D* noiseTexture = new osg::Texture3D; |

336 | noiseTexture->setFilter(osg::Texture3D::MIN_FILTER, osg::Texture3D::LINEAR); |

337 | noiseTexture->setFilter(osg::Texture3D::MAG_FILTER, osg::Texture3D::LINEAR); |

338 | noiseTexture->setWrap(osg::Texture3D::WRAP_S, osg::Texture3D::REPEAT); |

339 | noiseTexture->setWrap(osg::Texture3D::WRAP_T, osg::Texture3D::REPEAT); |

340 | noiseTexture->setWrap(osg::Texture3D::WRAP_R, osg::Texture3D::REPEAT); |

341 | noiseTexture->setImage( create3DNoiseImage(texSize) ); |

342 | return noiseTexture; |

343 | } |

**Note:**See TracBrowser for help on using the browser.