[HLSL] librairie simplex

Cette section est destinée aux scripts partagés par la communauté. Chaque post est destiné à un script. Suivez bien les recommandations.
Avatar de l’utilisateur
Titan
Messages : 582
Inscription : 12 Sep 2011 13:54
Contact :

[HLSL] librairie simplex

Message par Titan » 13 Juil 2013 19:22

-NOM: librairie simplex

-AUTEUR(S): Titan, (inspiration: https://github.com/kev009/craftd/blob/m ... oise1234.c, viewtopic.php?f=8&t=2679&p=15346&hilit=simplex#p15346)

-DESCRIPTION :
une librairie HLSL qui permet de générer du bruit:
http://www.youtube.com/watch?v=01AcTdGmA7E
et les dérivés correspondante:
http://www.youtube.com/watch?v=CREd_BMQfLs
Version: 1D 2D 3D avec et sans dérivé.
note: je n'ai pas fait de version 4D ni de version loop,
si vous en avez besoin demandez moi.

la différence avec les autres implémentation que l'ont peut trouver sur google:
- calcul la dérivé.
- utilise une seed au lieu d'une lookup texture.
- ça marche.

-UTILISATION :
il faut copier le code dans un fichier, et le mettre dans le même répertoire que le shader qui va l'utiliser
ensuite le shader #include "simplex.hlsl"

pour l'utiliser il y faut setter la seed simplexSeed et ensuite utiliser la fonction simplexNoise()

les prototypes peuvent être:

Code : Tout sélectionner

float simplexNoise(float coord);
float simplexNoise(float2 coord);
float simplexNoise(float3 coord);
float simplexNoise(float coord, float derivative);
float simplexNoise(float2 coord, float2 derivative);
float simplexNoise(float3 coord, float3 derivative);
-en théorie rien n’empêche ce code de fonctionner n'importe où. en pratique, si vous utilisez Unity^^, shaderlab n'est pas compatible HLSL à ma connaissance donc sont usage va se limiter au computeShader.

-pour bind la seed vous devez mettre dans le code C#:

Code : Tout sélectionner

myComputeShader.SetFloat("simplexSeed", 148948);
un exemple de code qui l'utilise (2eme video):

Code : Tout sélectionner

#pragma kernel main
#include "simplex.compute"

RWTexture2D<float4> Result;

float time;

[numthreads(8,8,1)]
void main (uint3 id : SV_DispatchThreadID)
{
	float3 d;
	float n = simplexNoise(float3((float)(id.x) / 128, (float)(id.y) / 128, time), d) * 0.5 + 0.5;
	d = d * 0.25 + 0.5;
    Result[id.xy] = float4(d, 1);
}

Code : Tout sélectionner

using UnityEngine;
using System.Collections;

public class TestSimplex : MonoBehaviour 
{
	RenderTexture rd;
	public ComputeShader cs;
	
	void Start () 
	{
		rd = new RenderTexture(1024, 1024, 1, RenderTextureFormat.Default, RenderTextureReadWrite.sRGB);
		rd.enableRandomWrite = true;
		rd.Create();
		cs.SetTexture(0, "Result", rd);
	}
	
	void OnGUI()
	{
		if(Event.current.type.Equals(EventType.Repaint))
		{
			cs.SetFloat("time", Time.time);
			cs.SetFloat("simplexSeed", 148948);
			cs.Dispatch(0, 128, 128, 1);

			Graphics.DrawTexture (new Rect(0, 0, Screen.height, Screen.height), rd);
		}
	}
}
-SCRIPT :

Code : Tout sélectionner

int simplexSeed;

int hash(int a)
{
    a = (a ^ 61) ^ (a >> 16);
    a = a + (a << 3);
    a = a ^ (a >> 4);
    a = a * simplexSeed;
    a = a ^ (a >> 15);
    return a;
}

/*
** 1D
*/

void grad1( int hash,  out float gx ) 
{
    int h = hash & 15;
    gx = 1.0f + (h & 7);
    if (h&8) gx = -gx;
}

float noise( float x )
{
  int i0 = floor(x);
  int i1 = i0 + 1;
  float x0 = x - i0;
  float x1 = x0 - 1.0f;

  float gx0, gx1;
  float n0, n1;
  float t20, t40, t21, t41;
  
  float x20 = x0 * x0;
  float t0 = 1.0f - x20;
  t20 = t0 * t0;
  t40 = t20 * t20;
  grad1(hash(i0 & 0xff), gx0);
  n0 = t40 * gx0 * x0;

  float x21 = x1*x1;
  float t1 = 1.0f - x21;
  t21 = t1 * t1;
  t41 = t21 * t21;
  grad1(hash(i1 & 0xff), gx1);
  n1 = t41 * gx1 * x1;
  
  return 0.25f * (n0 + n1);
}

float noise (float x, out float dnoise_dx)
{
  int i0 = floor(x);
  int i1 = i0 + 1;
  float x0 = x - i0;
  float x1 = x0 - 1.0f;

  float gx0, gx1;
  float n0, n1;
  float t20, t40, t21, t41;
  
  float x20 = x0 * x0;
  float t0 = 1.0f - x20;
  t20 = t0 * t0;
  t40 = t20 * t20;
  grad1(hash(i0 & 0xff), gx0);
  n0 = t40 * gx0 * x0;

  float x21 = x1*x1;
  float t1 = 1.0f - x21;
  t21 = t1 * t1;
  t41 = t21 * t21;
  grad1(hash(i1 & 0xff), gx1);
  n1 = t41 * gx1 * x1;

  dnoise_dx = t20 * t0 * gx0 * x20;
  dnoise_dx += t21 * t1 * gx1 * x21;
  dnoise_dx *= -8.0f;
  dnoise_dx += t40 * gx0 + t41 * gx1;
  dnoise_dx *= 0.1;
  return 0.25f * (n0 + n1);
}

/*
** 2D
*/

static 	float2 grad2lut[8] = 
	{
	  { -1.0f, -1.0f }, { 1.0f, 0.0f } , { -1.0f, 0.0f } , { 1.0f, 1.0f } ,
	  { -1.0f, 1.0f } , { 0.0f, -1.0f } , { 0.0f, 1.0f } , { 1.0f, -1.0f }
	};

float2 grad2( int hash)
{
    return grad2lut[hash & 7];
}

float noise( float2 input)
  {
    float n0, n1, n2;
    float2 g0, g1, g2;

    float s = ( input.x + input.y ) * 0.366025403f;
    float2 a = input + s;
    int2 ij = floor( a );

    float t = ( float ) ( ij.x + ij.y ) * 0.211324865f;
    float2 b = ij - t;
    float2 c = input - b;

    int2 ij1 = c.x > c.y ? float2(1,0) : float2(0,1);

	float2 c1 = c - ij1 + 0.211324865f;
	float2 c2 = c - 1.0f + 2.0f * 0.211324865f;

    int ii = ij.x & 0xff;
    int jj = ij.y & 0xff;

    float t0 = 0.5f - c.x * c.x - c.y * c.y;
    float t20, t40;
    if( t0 < 0.0f ) t40 = t20 = t0 = n0 = g0.x = g0.y = 0.0f;
    else 
    {
      g0 = grad2( hash(ii + hash(jj)));
      t20 = t0 * t0;
      t40 = t20 * t20;
      n0 = t40 * ( g0.x * c.x + g0.y * c.y );
    }

    float t1 = 0.5f - c1.x * c1.x - c1.y * c1.y;
    float t21, t41;
    if( t1 < 0.0f ) t21 = t41 = t1 = n1 = g1.x = g1.y = 0.0f;
    else 
    {
      g1 = grad2( hash(ii + ij1.x + hash(jj + ij1.y)));
      t21 = t1 * t1;
      t41 = t21 * t21;
      n1 = t41 * ( g1.x * c1.x + g1.y * c1.y );
    }

    float t2 = 0.5f - c2.x * c2.x - c2.y * c2.y;
    float t22, t42;
    if( t2 < 0.0f ) t42 = t22 = t2 = n2 = g2.x = g2.y = 0.0f;
    else 
    {
      g2 = grad2( hash(ii + 1 + hash(jj + 1)));
      t22 = t2 * t2;
      t42 = t22 * t22;
      n2 = t42 * ( g2.x * c2.x + g2.y * c2.y );
    }

    float noise = 40.0f * ( n0 + n1 + n2 );
    return noise;
  }

float noise( float2 input, out float2 derivative)
  {
    float n0, n1, n2;
    float2 g0, g1, g2;

    float s = ( input.x + input.y ) * 0.366025403f;
    float2 a = input + s;
    int2 ij = floor( a );

    float t = ( float ) ( ij.x + ij.y ) * 0.211324865f;
    float2 b = ij - t;
    float2 c = input - b;

    int2 ij1 = c.x > c.y ? float2(1,0) : float2(0,1);

	float2 c1 = c - ij1 + 0.211324865f;
	float2 c2 = c - 1.0f + 2.0f * 0.211324865f;

    int ii = ij.x & 0xff;
    int jj = ij.y & 0xff;

    float t0 = 0.5f - c.x * c.x - c.y * c.y;
    float t20, t40;
    if( t0 < 0.0f ) t40 = t20 = t0 = n0 = g0.x = g0.y = 0.0f;
    else 
    {
      g0 = grad2( hash(ii + hash(jj)));
      t20 = t0 * t0;
      t40 = t20 * t20;
      n0 = t40 * ( g0.x * c.x + g0.y * c.y );
    }

    float t1 = 0.5f - c1.x * c1.x - c1.y * c1.y;
    float t21, t41;
    if( t1 < 0.0f ) t21 = t41 = t1 = n1 = g1.x = g1.y = 0.0f;
    else 
    {
      g1 = grad2( hash(ii + ij1.x + hash(jj + ij1.y)));
      t21 = t1 * t1;
      t41 = t21 * t21;
      n1 = t41 * ( g1.x * c1.x + g1.y * c1.y );
    }

    float t2 = 0.5f - c2.x * c2.x - c2.y * c2.y;
    float t22, t42;
    if( t2 < 0.0f ) t42 = t22 = t2 = n2 = g2.x = g2.y = 0.0f;
    else 
    {
      g2 = grad2( hash(ii + 1 + hash(jj + 1)));
      t22 = t2 * t2;
      t42 = t22 * t22;
      n2 = t42 * ( g2.x * c2.x + g2.y * c2.y );
    }

    float noise = 40.0f * ( n0 + n1 + n2 );

    float temp0 = t20 * t0 * ( g0.x * c.x + g0.y * c.y );
    float temp1 = t21 * t1 * ( g1.x * c1.x + g1.y * c1.y );
    float temp2 = t22 * t2 * ( g2.x * c2.x + g2.y * c2.y );
    derivative = ((temp0 * c + temp1 * c1 + temp2 * c2) * -8 + (t40 * g0 + t41 * g1 + t42 * g2)) * 40;
      
    return noise;
  }
  
  /*
  ** 3D
  */                    

	static float3 grad3lut[16] = 
	{
	  { 1.0f, 0.0f, 1.0f }, { 0.0f, 1.0f, 1.0f },
	  { -1.0f, 0.0f, 1.0f }, { 0.0f, -1.0f, 1.0f },
	  { 1.0f, 0.0f, -1.0f }, { 0.0f, 1.0f, -1.0f },
	  { -1.0f, 0.0f, -1.0f }, { 0.0f, -1.0f, -1.0f },
	  { 1.0f, -1.0f, 0.0f }, { 1.0f, 1.0f, 0.0f },
	  { -1.0f, 1.0f, 0.0f }, { -1.0f, -1.0f, 0.0f },
	  { 1.0f, 0.0f, 1.0f }, { -1.0f, 0.0f, 1.0f }, 
	  { 0.0f, 1.0f, -1.0f }, { 0.0f, -1.0f, -1.0f }
	};
  
	float3 grad3(int hash) 
	{
		return grad3lut[hash & 15];
	}
     
  float simplexNoise(float3 input)
  {
    float n0, n1, n2, n3;
    float noise;
    float3 g0, g1, g2, g3;

    float s = (input.x + input.y + input.z) * 0.333333333;
    float3 a = input + s;
    int3 ijk = floor(a);

    float t = (float)(ijk.x + ijk.y + ijk.z) * 0.166666667;
    float3 b = ijk - t;
	float3 c = input - b;

	int3 ijk1;
	int3 ijk2;
	
    if(c.x >= c.y) {
      if(c.y >= c.z)
        { ijk1 = int3(1, 0, 0); ijk2 = int3(1,1,0); }
        else if(c.x >= c.z) { ijk1 = int3(1, 0, 0); ijk2 = int3(1,0,1); }
        else { ijk1 = int3(0, 0, 1); ijk2 = int3(1,0,1); }
      }
    else {
      if(c.y < c.z) { ijk1 = int3(0, 0, 1); ijk2 = int3(0,1,1); }
      else if(c.x < c.z) { ijk1 = int3(0, 1, 0); ijk2 = int3(0,1,1); }
      else { ijk1 = int3(0, 1, 0); ijk2 = int3(1,1,0); }
    }

    float3 c1 = c - ijk1 + 0.166666667;
	float3 c2 = c - ijk2 + 2.0f * 0.166666667;
	float3 c3 = c - 1.0f + 3.0f * 0.166666667;

    int ii = ijk.x & 0xff;
    int jj = ijk.y & 0xff;
    int kk = ijk.z & 0xff;

    float t0 = 0.6f - c.x * c.x - c.y * c.y - c.z * c.z;
    float t20, t40;
    if(t0 < 0.0f) n0 = t0 = t20 = t40 = g0.x = g0.y = g0.z = 0.0f;
    else {
      g0 = grad3( hash(ii + hash(jj + hash(kk))));
      t20 = t0 * t0;
      t40 = t20 * t20;
      n0 = t40 * ( g0.x * c.x + g0.y * c.y + g0.z * c.z );
    }

    float t1 = 0.6f - c1.x * c1.x -  c1.y * c1.y - c1.z * c1.z;
    float t21, t41;
    if(t1 < 0.0f) n1 = t1 = t21 = t41 = g1.x = g1.y = g1.z = 0.0f;
    else {
      g1 = grad3( hash(ii + ijk1.x + hash(jj + ijk1.y + hash(kk + ijk1.z))));
      t21 = t1 * t1;
      t41 = t21 * t21;
      n1 = t41 * ( g1.x * c1.x + g1.y * c1.y + g1.z * c1.z );
    }

    float t2 = 0.6f - c2.x * c2.x - c2.y * c2.y - c2.z * c2.z;
    float t22, t42;
    if(t2 < 0.0f) n2 = t2 = t22 = t42 = g2.x = g2.y = g2.z = 0.0f;
    else {
      g2 = grad3( hash(ii + ijk2.x + hash(jj + ijk2.y + hash(kk + ijk2.z))));
      t22 = t2 * t2;
      t42 = t22 * t22;
      n2 = t42 * ( g2.x * c2.x + g2.y * c2.y + g2.z * c2.z );
    }

    float t3 = 0.6f - c3.x * c3.x - c3.y * c3.y - c3.z * c3.z;
    float t23, t43;
    if(t3 < 0.0f) n3 = t3 = t23 = t43 = g3.x = g3.y = g3.z = 0.0f;
    else {
      g3 = grad3( hash(ii + 1 + hash(jj + 1 + hash(kk + 1))));
      t23 = t3 * t3;
      t43 = t23 * t23;
      n3 = t43 * ( g3.x * c3.x + g3.y * c3.y + g3.z * c3.z );
    }

    noise = 20.0f * (n0 + n1 + n2 + n3);
    return noise;
}
    
  float simplexNoise( float3 input, out float3 derivative)
  {
    float n0, n1, n2, n3;
    float noise;
    float3 g0, g1, g2, g3;

    float s = (input.x + input.y + input.z) * 0.333333333;
    float3 a = input + s;
    int3 ijk = floor(a);

    float t = (float)(ijk.x + ijk.y + ijk.z) * 0.166666667;
    float3 b = ijk - t;
	float3 c = input - b;

	int3 ijk1;
	int3 ijk2;
	
    if(c.x >= c.y) {
      if(c.y >= c.z)
        { ijk1 = int3(1, 0, 0); ijk2 = int3(1,1,0); }
        else if(c.x >= c.z) { ijk1 = int3(1, 0, 0); ijk2 = int3(1,0,1); }
        else { ijk1 = int3(0, 0, 1); ijk2 = int3(1,0,1); }
      }
    else {
      if(c.y < c.z) { ijk1 = int3(0, 0, 1); ijk2 = int3(0,1,1); }
      else if(c.x < c.z) { ijk1 = int3(0, 1, 0); ijk2 = int3(0,1,1); }
      else { ijk1 = int3(0, 1, 0); ijk2 = int3(1,1,0); }
    }

    float3 c1 = c - ijk1 + 0.166666667;
	float3 c2 = c - ijk2 + 2.0f * 0.166666667;
	float3 c3 = c - 1.0f + 3.0f * 0.166666667;

    int ii = ijk.x & 0xff;
    int jj = ijk.y & 0xff;
    int kk = ijk.z & 0xff;

    float t0 = 0.6f - c.x * c.x - c.y * c.y - c.z * c.z;
    float t20, t40;
    if(t0 < 0.0f) n0 = t0 = t20 = t40 = g0.x = g0.y = g0.z = 0.0f;
    else {
      g0 = grad3( hash(ii + hash(jj + hash(kk))));
      t20 = t0 * t0;
      t40 = t20 * t20;
      n0 = t40 * ( g0.x * c.x + g0.y * c.y + g0.z * c.z );
    }

    float t1 = 0.6f - c1.x * c1.x -  c1.y * c1.y - c1.z * c1.z;
    float t21, t41;
    if(t1 < 0.0f) n1 = t1 = t21 = t41 = g1.x = g1.y = g1.z = 0.0f;
    else {
      g1 = grad3( hash(ii + ijk1.x + hash(jj + ijk1.y + hash(kk + ijk1.z))));
      t21 = t1 * t1;
      t41 = t21 * t21;
      n1 = t41 * ( g1.x * c1.x + g1.y * c1.y + g1.z * c1.z );
    }

    float t2 = 0.6f - c2.x * c2.x - c2.y * c2.y - c2.z * c2.z;
    float t22, t42;
    if(t2 < 0.0f) n2 = t2 = t22 = t42 = g2.x = g2.y = g2.z = 0.0f;
    else {
      g2 = grad3( hash(ii + ijk2.x + hash(jj + ijk2.y + hash(kk + ijk2.z))));
      t22 = t2 * t2;
      t42 = t22 * t22;
      n2 = t42 * ( g2.x * c2.x + g2.y * c2.y + g2.z * c2.z );
    }

    float t3 = 0.6f - c3.x * c3.x - c3.y * c3.y - c3.z * c3.z;
    float t23, t43;
    if(t3 < 0.0f) n3 = t3 = t23 = t43 = g3.x = g3.y = g3.z = 0.0f;
    else {
      g3 = grad3( hash(ii + 1 + hash(jj + 1 + hash(kk + 1))));
      t23 = t3 * t3;
      t43 = t23 * t23;
      n3 = t43 * ( g3.x * c3.x + g3.y * c3.y + g3.z * c3.z );
    }

    noise = 20.0f * (n0 + n1 + n2 + n3);

    float temp0 = t20 * t0 * ( g0.x * c.x + g0.y * c.y + g0.z * c.z );
    derivative = temp0 * c;
    float temp1 = t21 * t1 * ( g1.x * c1.x + g1.y * c1.y + g1.z * c1.z );
    derivative += temp1 * c1;
    float temp2 = t22 * t2 * ( g2.x * c2.x + g2.y * c2.y + g2.z * c2.z );
    derivative += temp2 * c2;
    float temp3 = t23 * t3 * ( g3.x * c3.x + g3.y * c3.y + g3.z * c3.z );
    derivative += temp3 * c3;
    derivative *= -8.0f;
    derivative += t40 * g0 + t41 * g1 + t42 * g2 + t43 * g3;
    derivative *= 28.0f;

    return noise;
}
____________________________________________
Hop Boy

Avatar de l’utilisateur
Max
Messages : 8773
Inscription : 30 Juil 2011 13:57
Contact :

Re: [HLSL] librairie simplex

Message par Max » 13 Juil 2013 20:22

interessant tout ça, cela me rappel un sujet aussi fort interessant traité sur ce forum par ce grand théoricien qu'est Gabriel : viewtopic.php?f=8&t=2679&hilit=noise
Image
Pas d'aide par MP, le forum est là pour ça.
En cas de doute sur les bonnes pratiques à adopter sur le forum, consulter la Charte et sa FAQ

Avatar de l’utilisateur
artemisart
Messages : 1893
Inscription : 21 Juin 2011 19:51
Localisation : Centre
Contact :

Re: [HLSL] librairie simplex

Message par artemisart » 13 Juil 2013 23:23

Très intéressant ! Par contre peut-on l'utiliser sans passer par les RenderTexture ?

Avatar de l’utilisateur
Titan
Messages : 582
Inscription : 12 Sep 2011 13:54
Contact :

Re: [HLSL] librairie simplex

Message par Titan » 14 Juil 2013 02:26

Je vais m'en servir pour générer de la géométrie.
Tu peut le voir comme n'importe quelle fonction mathématique finalement, c'est comme demander si on peut utiliser une fonction cosinus en dehors d'un RenderTexture.

Si la question était vis à vis du computeShader, il y a 2 moyens de récupérer des données après traitement:
- le RenderTexture, que tu peut ensuite attacher à n'importe quel shader.
- le computeBuffer qui permet de récupérer un tableau de taille fixe. Le tableau peut contenir le type d'élément que tu veux, j'ai fait un package de démonstration dans ce thread viewtopic.php?f=12&t=628, ou mon computeBuffer contient un tableau de structure contenant la position et la vélocité de particules, par contre je récupère à aucun moment le contenu, je l'envoi directement au shader sans repasser par le CPU dans cet exemple, mais il suffit de faire ComputeBuffer.GetData(System.Array data) ou data est un tableau de type et de taille compatible pour importer le résultat (si ton tableau est pas bon Unity crash directe).
Dernière édition par Titan le 14 Juil 2013 02:27, édité 2 fois.
____________________________________________
Hop Boy

Avatar de l’utilisateur
Titan
Messages : 582
Inscription : 12 Sep 2011 13:54
Contact :

Re: [HLSL] librairie simplex

Message par Titan » 14 Juil 2013 02:27

double post, y'avais longtemps.
____________________________________________
Hop Boy

Répondre

Revenir vers « Scripts »