gpt4 book ai didi

.net - Perlin 噪声插值

转载 作者:行者123 更新时间:2023-12-02 04:59:40 26 4
gpt4 key购买 nike

我一直在使用 this 在 F# 中编写 Perlin 噪声生成器和 this ,并且一直成功直到算法的插值部分。这是到目前为止的工作代码(您可能不需要阅读接下来的 2 个代码块,因为它们只是为了上下文,所以不要害怕):

// PerlinNoiseProvider3D.fs
open System
open System.Collections.Generic
open Axiom.Math
open Ops

// Instances return a pseudorandom noise value between -1 and 1. scale defines how far apart the grid points are spaced.
type PerlinNoiseProvider3D(scale) =
let randGen = new Random()
// Each point in the grid has a random gradient
let grid = new Dictionary<Vector3, Vector3>()

// I stole this handy algorithm from this SE question:
// http://math.stackexchange.com/questions/44689/how-to-find-a-random-axis-or-unit-vector-in-3d
let randomAngle() =
// Random value between 0 and 2π
let θ = randGen.NextDouble() * Math.PI * 2.0
// Random value between -1 and 1
let z = randGen.NextDouble() * 2.0 - 1.0
// Compute the resulting point
(sqrt(1.0 - (z**2.0)) * cos(θ)) @@ (sqrt(1.0 - (z**2.0)) * sin(θ)) @@ z

// Returns the gradient (just a vector pointing in a particular direction) at the given GRID point (not world coordinates)
let getGradientAt v =
try
grid.[v]
with
| :? KeyNotFoundException -> grid.[v] <- randomAngle(); grid.[v]

// Calculates the influence of the gradient g at gp on p, which is the dot product of gp and a vector facing from gp to p. Note that gp is _not_ in grid coordinates!!
let influence (p: Vector3) (gp: Vector3) (g: Vector3) =
// Find the vector going from the gp to p
let f = p - gp
// Dot product on the grandient and the vector facing p from gp
float <| (g.x * f.x) + (g.y * f.y) + (g.z * f.y)

member this.GetValue (point: Vector3) =
let v: Vector3 = point / scale
// There's gotta be a shorter way to do this...
let extract (i: Vector3) (min: Vector3) (max: Vector3) =
let x =
match int i.x with
| 0 -> min.x
| 1 -> max.x
| _ -> failwith "Bad x index (shouldn't happen!)"
let y =
match int i.y with
| 0 -> min.y
| 1 -> max.y
| _ -> failwith "Bad y index (shouldn't happen!)"
let z =
match int i.z with
| 0 -> min.z
| 1 -> max.z
| _ -> failwith "Bad z index (shouldn't happen!)"
x @@ y @@ z
let min = (floor <| float v.x) @@ (floor <| float v.y) @@ (floor <| float v.z)
let max = (ceil <| float v.x) @@ (ceil <| float v.y) @@ (ceil <| float v.z)
// Relative 3D array of neighboring points (fst in tuple) and data (snd in tuples)
let neighbors = Array3D.init 2 2 2 (fun xi yi zi -> extract (xi @@ yi @@ zi) min max, 0 @@ 0 @@ 0)
let pInfluence = influence v
let influences = neighbors |> Array3D.map (fun (p, g) -> pInfluence p (getGradientAt p))



// Ops.fs
module Ops
let average (numbers: float list) =
let rec average' (numbers': float list) =
if numbers'.Length > 1 then
average' [
for i in 0..2..(numbers'.Length - 1) ->
let a = numbers'.[i]
try
(a + numbers'.[i + 1]) / 2.0
with
| :? System.ArgumentException -> a
]
else
numbers'
(average' numbers).[0]

// Temporary 3D array average
let average3D numbers =
// Simply flatten the list and use the average function defined earlier
average [
for x in 0..(Array3D.length1 numbers - 1) do
for y in 0..(Array3D.length2 numbers - 1) do
for z in 0..(Array3D.length3 numbers - 1) ->
numbers.[x, y, z]
]

我知道有很多东西需要考虑,但是上面给出的代码都没有被破坏;它按预期工作会产生这样的不完整图像(只是缺少一些): 500x500 almost Perlin noise image (scale 20)

这就是我想出的插值(只是其他代码+这个,结果删除了average3D调用):
// PerlinNoiseProvider3D.fs
// ...
let interp((a: float, b), axis) = a + (axis * (b - a))
let Sx, Sy, Sz = S <| float v.x, S <| float v.y, S <| float v.z
let zE1, zE2, zE3, zE4 =
(influences.[0, 0, 0], influences.[0, 0, 1]),
(influences.[0, 1, 0], influences.[0, 1, 1]),
(influences.[1, 0, 0], influences.[1, 0, 1]),
(influences.[1, 1, 0], influences.[1, 1, 1])
// Interpolate the points along the z-axis
let xE1, xE2 =
(interp(zE1, Sz), interp(zE2, Sz)),
(interp(zE3, Sz), interp(zE4, Sz))
// Interpolate the edges along the x-axis
let yE = (interp(xE1, Sx), interp(xE2, Sx))
// And finally, interpolate the y edge to yield our final value
interp(yE, Sy)


// Ops.fs
// ..
// Ease curve
let ease p = (3.0 * (p ** 2.0)) - (2.0 * (p ** 3.0))
let S x = ease (x - (floor x))

这给出了这个结果,看起来更糟:

Really bad Perlin noise algorithm that should work

我认为你基本上应该对每个轴进行插值——在 3D 的情况下,所有 4 个 z 轴,然后是生成的 2 个 x 轴,最后是生成的 y 轴以获得最终结果值(value)。它似乎不起作用。我一定在这里误解了一些东西;它只是行不通!也许我的插值函数是错误的。也许我的应用是错误的。任何帮助表示赞赏。甚至是对您应该如何执行此操作的确切解释——最后一步的大多数其他来源都说,“然后将这些点积插值在一起以获得最终值。”

PS:我正在使用游戏库 Axiom(Ogre 的 C# 端口)中的结构,主要是 Vector3,所以我定义了 @@在整个代码中使用的运算符,用于轻松创建 Vector3,如下所示: 1 @@ 2 @@ 3

最佳答案

来自 here .

11.1.3 Normal vector interpolation This technique uses a similar interpolation method, except that the quantity interpolated across the polygon is the surface normal vector, instead of the computed intensity itself. (This method is also known as Phong interpolation.) The vertex normals are computed just as in the intensity interpolation method. Referring to Figure 11.2 again, and representing the normal vector at a point P as NP , we have

NQ =  u*NB+(1-u)NA,  where  u=  AQ/AB 
NR = w*NB+(1-w)NC, where w= CR/CB
NP = v*NR+(1-v)NQ, where v= QP/QR

The normal vector can also be determined incrementally.

The result is much more realistic than the intensity interpolation method, especially when specular reflection is considered - the highlights are rendered more faithfully, and Mach banding is greatly reduced (but spheres and cylinders are still prone to Mach band effects).

The drawback of this method is that it requires more computations to process each interpolated point in a polygon; at each point the complete shading calculation must be performed using the interpolated normal at that point.

11.1.4 Dot-product interpolation This method is a compromise between intensity interpolation and normal vector interpolation. Here, the quantities interpolated from one end of the scan line to the other are the dot products N· L and (R· V)n . This method is sometimes called 'cheap Phong' interpolation.



您可能必须阅读整篇文章才能获得足够的上下文来理解方程式。

关于.net - Perlin 噪声插值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17820330/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com