Skip to content

Does not take into account non integer divisors #3

@philipdavis82

Description

@philipdavis82

I got this error when generating noise

Traceback (most recent call last):
  File "c:/Software/Test Software/PerlinNoise.py", line 93, in <module>
    noise = terrain.generate_fractal_noise_2d((100,100),(10,10),3)
  File "c:/Software/Test Software/PerlinNoise.py", line 85, in generate_fractal_noise_2d
    noise += amplitude * self.generate_perlin_noise_2d(shape, (int(frequency*res[0]), int(frequency*res[1])))
  File "c:/Software/Test Software/PerlinNoise.py", line 69, in generate_perlin_noise_2d
    n00 = np.sum(grid * g00, 2)
ValueError: operands could not be broadcast together with shapes (100,100,2) (80,80,2)

I realized it was due to this line

        delta = (res[0] / shape[0], res[1] / shape[1])
        d = (shape[0] // res[0], shape[1] // res[1])
        grid = np.mgrid[0:res[0]:delta[0],0:res[1]:delta[1]].transpose(1, 2, 0) % 1
        # Gradients
        angles = 2*np.pi*self.random.rand(res[0]+1, res[1]+1)
        gradients = np.dstack((np.cos(angles), np.sin(angles)))
        g00 = gradients[0:-1,0:-1].repeat(d[0], 0).repeat(d[1], 1)
        g10 = gradients[1:,0:-1].repeat(d[0], 0).repeat(d[1], 1)
        g01 = gradients[0:-1,1:].repeat(d[0], 0).repeat(d[1], 1)
        g11 = gradients[1:,1:].repeat(d[0], 0).repeat(d[1], 1)

Grid must be a integer multiple of the gradiant size when repeating the gradient or else the sizes will not line up.

for the above example the shape of the grid was (100, 100, 2)
and the shape of g00 was (80, 80, 2). so they were not able to be broadcast by the np.sum function.

This was my fix

    def generate_perlin_noise_2d(self,shape, res):
        def f(t):
            return 6*t**5 - 15*t**4 + 10*t**3

        delta = (res[0] / shape[0], res[1] / shape[1])
        d = (shape[0] // res[0], shape[1] // res[1])
        grid = np.mgrid[0:res[0]:delta[0],0:res[1]:delta[1]].transpose(1, 2, 0) % 1
        # Gradients
        angles = 2*np.pi*self.random.rand(res[0]+1, res[1]+1)
        gradients = np.dstack((np.cos(angles), np.sin(angles)))
        if d[0]*delta[0] != 1:
            d = (d[0] + 1,d[1])
        if d[1]*delta[1] != 1:
            d = (d[0],d[1] + 1)
        g00 = gradients[0:-1,0:-1].repeat(d[0], 0).repeat(d[1], 1)
        g10 = gradients[1:,0:-1].repeat(d[0], 0).repeat(d[1], 1)
        g01 = gradients[0:-1,1:].repeat(d[0], 0).repeat(d[1], 1)
        g11 = gradients[1:,1:].repeat(d[0], 0).repeat(d[1], 1)
        # Ramps
        n00 = np.sum(grid * g00[:len(grid),:len(grid[0])], 2)
        n10 = np.sum(np.dstack((grid[:,:,0]-1, grid[:,:,1])) * g10[:len(grid),:len(grid[0])], 2)
        n01 = np.sum(np.dstack((grid[:,:,0], grid[:,:,1]-1)) * g01[:len(grid),:len(grid[0])], 2)
        n11 = np.sum(np.dstack((grid[:,:,0]-1, grid[:,:,1]-1)) * g11[:len(grid),:len(grid[0])], 2)
        # Interpolation
        t = f(grid)
        n0 = n00*(1-t[:,:,0]) + t[:,:,0]*n10
        n1 = n01*(1-t[:,:,0]) + t[:,:,0]*n11

        return np.sqrt(2)*((1-t[:,:,1])*n0 + t[:,:,1]*n1)

The idea was just to repeat one more time then slice the matrix for the sum.
This way any number should be able to be entered and there are still no loops.

I don't know if this is even an issue for most people, I just wanted to put it here.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions