Forums Développement Multimédia

Aller au contenu

- - - - -

AS3 Shaders : quelques exemples

CODE Actionscript

19 réponses à ce sujet

#1 Jean-Marc Le Roux

    Ceinture Noire

  • Minko
  • PipPipPipPipPipPipPip
  • 210 messages

Posté 19 November 2011 - 19:17 PM

L'écriture de vertex/fragment shaders est une partie extrêmement importante de toute technologie 3D, et à fortiori avec Flash 11 et Stage3D où tout le rendu à l'écran ne se fait que par des shaders.
Avec Minko il n'y besoin ni d'assembleur AGAL ni de PB3D.
Avec Minko, les shaders sont écrits en AS3.

Minko a un compilateur JIT qui, au runtime, compile vos shaders AS3 directement vers du bytecode AGAL uploadé sur la carte graphique. Vous pouvez donc écrire tous vos shaders dans votre projet Flash. De plus ce compilateur effectue beaucoup d'optimisations à votre place, et fait toute l'allocation mémoire, la mise en place des buffers, des textures... tout est automatisé.

Exemples de shaders AS3
Voilà des exemples très simples pour vous aider à commencer le temps que la doc. arrive :

Red

public class SimpleShader extends ActionScriptShader
{
  // retourne la position du vertex en clipspace (repère écran normalisé [-1 .. 1])
  override protected function getOutputPosition() : SValue
  {
    return vertexClipspacePosition;
  }

  // retourne du rouge pour la couleur du pixel
  override protected function getOutputColor() : SValue
  {
    return float4(1., 0., 0., 1.);
  }
}
 

Utilisation simple de la texture BasicStyle.DIFFUSE

public class SimpleTextureShader extends ActionScriptShader
{
  // retourne la position du vertex en clipspace (repère écran normalisé [-1 .. 1])
  override protected function getOutputPosition() : SValue
  {
    return vertexClipspacePosition;
  }

  // retourne du rouge pour la couleur du pixel
  override protected function getOutputColor() : SValue
  {
    // on doit utiliser "interpolate" car la valeur viens du vertex shader
    var uv : SValue = interpolate(vertexUV);

    return sampleTexture(BasicStyle.DIFFUSE, uv);
  }
}
 

Color transform

public class SimpleTextureShader extends ActionScriptShader
{
  private var _offset : Vector4 = null;
  private var _multiplier : Vector4 = null;

  public function ColorTransformShader(offset : Vector4, multiplier : Vector4)
  {
    _offset = offset;
    _multiplier = multiplier;
  }

  // retourne la position du vertex en clipspace (repère écran normalisé [-1 .. 1])
  override protected function getOutputPosition() : SValue
  {
    return vertexClipspacePosition;
  }

  // retourne du rouge pour la couleur du pixel
  override protected function getOutputColor() : SValue
  {
    // on doit utiliser "interpolate" car la valeur viens du vertex shader
    var uv : SValue = interpolate(vertexUV);
    var diffuse : SValue = sampleTexture(BasicStyle.DIFFUSE, uv);

    // applique les coefficient multiplicateurs
    diffuse = multiply(diffuse, multiplier);
    // applique l'offset
    diffuse = add(diffuse, _offset);

    return diffuse;
  }
}
 

LightCubeShader (extrait de la démo Gravity, nécessite minko-lighting)
Image IPB

public class LightCubeShader extends ActionScriptShader
{
        override protected function getOutputColor() : SValue
        {
                var pointLights         : WorldDataList = getWorldDataList(LightData);
                var numLights           : int                   = pointLights.length;
                var illumination        : SValue                = float3(0., 0., 0.);

                for (var lightIndex : int = 0; lightIndex < numLights; ++lightIndex)
                {
                        var lightPosition       : SValue        = getWorldParameter(3, LightData, LightData.LOCAL_POSITION, lightIndex);
                        var lightDiffuse        : SValue        = getWorldParameter(3, LightData, LightData.PREMULTIPLIED_DIFFUSE_COLOR, lightIndex);
                        var squareLocalDist     : SValue        = getWorldParameter(1, LightData, LightData.SQUARE_LOCAL_DISTANCE, lightIndex);

                        var lightToPoint        : SValue        = subtract(interpolate(vertexPosition), lightPosition);                        
                        var lightDirection      : SValue        = normalize(lightToPoint);
                        var lambertFactor       : SValue        = saturate(interpolate(vertexNormal).dotProduct3(lightDirection));

                        // hacky hacky...
                        var attenuation         : SValue        = saturate(multiply(squareLocalDist,
                                                                                                                   reciprocal(dotProduct3(lightToPoint, lightToPoint))));

                        // here goes the hack again...
                        lightDiffuse.scaleBy(attenuation)
                                                .scaleBy(.8);
                        illumination.incrementBy(lightDiffuse);
                }

                var uv          : SValue        = interpolate(vertexUV);
                var diffuse     : SValue        = sampleTexture(BasicStyle.DIFFUSE, uv);

                illumination = power(illumination, 1.2);

                return float4(multiply(diffuse.rgb, illumination), diffuse.a);
        }

        override protected function getOutputPosition() : SValue
        {
                return vertexClipspacePosition;
        }

        override public function getDataHash(styleData          : StyleData,
                                                 transformData  : TransformData,
                                                 worldData              : Dictionary) : String
        {
                return (worldData[LightData] as WorldDataList).length.toString(16);
        }
}
 

Simple Directional Lighting

public class SimpleDirectionalLightingShader
{
  private const LIGHT_DIRECTION : SValue = float3(1., -1., 0.);

  private var _vertexIllumination : SValue = null;

  override protected function getOutoutPosition()
  {
    var lightDirection : SValue = normalize(LIGHT_DIRECTION);
    var normal : SValue = normalize(vertexNormal);

    _vertexIllumination = dotProduct3(normal, lightDirection);
    _vertexIllumination = negate(_vertexIllumination);

    return vertexClipspacePosition();
  }

  override protected function getOutputColor()
  {
    var uv : SValue = interpolate(vertexUV);
    var diffuse : SValue = sampleTexture(BasicStyle.DIFFUSE, uv);
    var illumination : SValue = interpolate(_vertexIllumination);

    diffuse = float4(
      multiply(diffuse.rgb, illumination),
      diffuse.a
    );

    return diffuse;
  }
}
 

Utilisation des shaders sur la scène
Voilà comment utiliser de tels shaders sur la scène :


viewport.defaultEffect = new SinglePassRenderingEffect(new MyCoolShader());
 

Voilà comment utiliser de tels shaders sur une sous-scène en particulier :


var es : EffectGroup = new EffectGroup(new SinglePassRenderingEffect(new MyCoolShader()));

es.addChild(... // ajoutez tout ce que vous voulez rendre avec cet effet/shader

_scene.addChild(es);
 

Si vous voulez voir le code AGAL généré par le compilateur, vous pouvez activer l'option de debug suivante:


Minko.debugLevel = DebugLevel.SHADER_AGAL;
 

Vous pouvez faire des fonctions, des classes, des boucles, des if... tout ce que vous faites habituellement en AS3.
Il faut juste bien comprendre comment marche :
- l'évaluation de ces shaders : qu'est ce qui se passe côté GPU et CPU
- la compilation de ces shaders : comment ça fonctionne derrière et comment rendre les shaders dynamiques/paramétriques
- comment marche un vertex et un fragment shader : ça, on ne peut pas y couper

La doc expliquera tout ça en détail, c'est pour ça que c'est un peu long à écrire.
Pour faciliter encore plus la création et le debug des shaders, nous travaillons actuellement sur un outil : le shader lab.
Mais en gros, oubliez l'AGAL :)

Si vous avez des questions ou que vous voulez poster des exemples, n'hésitez pas.

#2 Logic

  • Honoris
  • PipPipPipPipPipPipPipPip
  • 2733 messages

Posté 19 November 2011 - 19:26 PM

Chez moi ça ne marche pas.

Quand je fais:

_sceneEffect = new EffectGroup(  new SinglePassEffect( new TestShader() ) );

A la compil ça me dit:

Citation

1067: Implicit coercion of a value of type aerys.minko.render.effect:SinglePassEffect to an unrelated type aerys.minko.render.effect:IRenderingEffect.

J'ai pourtant récupéré le dernier SWC depuis le GIT.

#3 Logic

  • Honoris
  • PipPipPipPipPipPipPipPip
  • 2733 messages

Posté 19 November 2011 - 19:56 PM

J'ai récupéré les dernières sources sur le GIT.

Je joint ma source.

Fichier(s) joint(s)



#4 Jean-Marc Le Roux

    Ceinture Noire

  • Minko
  • PipPipPipPipPipPipPip
  • 210 messages

Posté 19 November 2011 - 21:14 PM

Voir le messageLogic, le 19 November 2011 - 19:26 PM, dit :

_sceneEffect = new EffectGroup(  new SinglePassEffect( new TestShader() ) );

Il faut utiliser la classe SinglePassRenderingEffect et non SinglePassEffect.
La seconde représente un effet avec une seule passe, sans préciser s'il s'agit d'un effet de rendu ou de post-process (on différencie les deux pour éviter que les gens utilisent un effet de post-process pour du rendu et inversement).
La première représente un effet avec une seule passe, mais qui en plus est effectivement un effet de rendu (ce que l'on veut ici).

La classe SinglePassRenderingEffect n'est donc rien de plus qu'un raccourci, et nous l'avons ajouté récemment justement pour pouvoir travailler facilement avec des shaders AS3 sans avoir à créer une classe par effet. Cette classe est disponible sur le dépôt Git mais pas encore dans le SWC.

Quand vous avez ce genre d'erreurs, vérifiez bien que vous utilisez le dépôt GIT au cas ou.
Le SWC est nécessairement moins à jour, et c'est tout l'intérêt d'avoir un dépôt GIT public.

Citation

Je joint ma source.

Je vous conseille fortement de faire une classe par shader :)

a+

#5 Logic

  • Honoris
  • PipPipPipPipPipPipPipPip
  • 2733 messages

Posté 19 November 2011 - 22:26 PM

Maintenant ça compile mais aucune différence avec/sans shader.


package
{
        import aerys.minko.Minko;
        import aerys.minko.render.Viewport;
        import aerys.minko.render.effect.SinglePassRenderingEffect;
        import aerys.minko.render.effect.lighting.LightingEffect;
        import aerys.minko.render.effect.lighting.LightingStyle;
        import aerys.minko.scene.node.camera.ArcBallCamera;
        import aerys.minko.scene.node.group.EffectGroup;
        import aerys.minko.scene.node.group.Group;
        import aerys.minko.scene.node.group.StyleGroup;
        import aerys.minko.scene.node.group.TransformGroup;
        import aerys.minko.scene.node.light.AmbientLight;
        import aerys.minko.scene.node.light.DirectionalLight;
        import aerys.minko.scene.node.mesh.Mesh;
        import aerys.minko.scene.node.mesh.primitive.CubeMesh;
        import aerys.minko.scene.node.texture.BitmapTexture;
        import aerys.minko.type.log.DebugLevel;
        import aerys.minko.type.math.Vector4;
       
        import flash.display.Sprite;
        import flash.display.StageAlign;
        import flash.display.StageScaleMode;
        import flash.events.Event;
       
        public class minkoShader extends Sprite
        {
               
                private var _view:Viewport;
                private var _camera:ArcBallCamera;
                private var _scene:Group;
                private var _sceneStyle:StyleGroup;
                private var _sceneEffect:EffectGroup;
               
                private var _ambienLight:AmbientLight;
                private var _directionalLight:DirectionalLight;
               
                [Embed(source="texture.jpg")]
                private var TextureClass:Class;
               
                private var _transf:TransformGroup;
                private var _styleGroup:StyleGroup;
                private var _texture:BitmapTexture;
                private var _mesh:Mesh;
               
                public function minkoShader()
                {
                        if (stage)
                                init();
                        else
                                addEventListener(Event.ADDED_TO_STAGE, onAdded);
                }
               
                private function onAdded( e:Event ) : void
                {
                        removeEventListener(Event.ADDED_TO_STAGE, onAdded);
                        init();
                }
               
                private function init():void
                {
                        //
                        stage.frameRate = 30;
                        stage.scaleMode = StageScaleMode.NO_SCALE;
                        stage.align = StageAlign.TOP_LEFT;
                       
                        Minko.debugLevel = DebugLevel.SHADER_AGAL;
                        //
                        _view = new Viewport();
                        _camera = new ArcBallCamera();
                        _scene = new Group();
                        _sceneStyle = new StyleGroup();
                        _sceneEffect = new EffectGroup(  new SinglePassRenderingEffect( new TestShader() ) );
                       
                        stage.addChild( _view );
                        _scene.addChild( _sceneStyle );
                        _sceneStyle.addChild( _sceneEffect );
                        _sceneEffect.addChild( _camera );
                       
                        //
                        _camera.distance = 10;
                       
                        // vire les light au cas où
                        //_ambienLight = new AmbientLight( 0xFFFFFF, 2 );
                        //_directionalLight = new DirectionalLight( 0xFFFFFF, 6, 8, 64, new Vector4(1, -1, 1) );
                        //_view.defaultEffect = new LightingEffect();
                        //_sceneStyle.addChild( _ambienLight );
                        //_sceneStyle.addChild( _directionalLight );
                       
                        //
                        _transf = new TransformGroup();
                        _styleGroup = new StyleGroup();
                        //_styleGroup.style.set( LightingStyle.LIGHTS_ENABLED, true );
                        _texture = new BitmapTexture( new TextureClass().bitmapData );
                        _mesh = CubeMesh.cubeMesh;
                       
                        _sceneStyle.addChild( _transf );
                        _transf.addChild( _styleGroup );
                        _styleGroup.addChild( _texture );
                        _styleGroup.addChild( _mesh );
                       
                        //
                        this.addEventListener( Event.ENTER_FRAME, onEnterFrame );
                }
               
                private function onEnterFrame( e:Event ):void
                {
                        _camera.rotation.x = - Math.PI / 4;
                        _camera.rotation.y = (2 * stage.mouseX / stage.stageWidth - 1) * Math.PI;
                       
                        _view.render( _scene );
                }
               
        }
}

/////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////

import aerys.minko.render.effect.basic.BasicStyle;
import aerys.minko.render.shader.ActionScriptShader;
import aerys.minko.render.shader.SValue;
import aerys.minko.type.math.Vector4;

class TestShader extends ActionScriptShader
{
       
        public function TestShader()
        {
               
        }
       
        protected override function getOutputPosition():SValue
        {
                return vertexClipspacePosition;
        }
       
        private var _mult:Vector4 = new Vector4(0.1, 0.1, 0.1);
        protected override function getOutputColor():SValue
        {
                var uv:SValue = interpolate(vertexUV);
                var diffuse:SValue = sampleTexture(BasicStyle.DIFFUSE, uv);
               
                // juste un test en essayant d'obscurcir
                diffuse = multiply( diffuse, _mult );
               
                return diffuse;
        }
}


 


#6 Jean-Marc Le Roux

    Ceinture Noire

  • Minko
  • PipPipPipPipPipPipPip
  • 210 messages

Posté 20 November 2011 - 15:33 PM

Voir le messageLogic, le 19 November 2011 - 22:26 PM, dit :

Maintenant ça compile mais aucune différence avec/sans shader.


_sceneEffect.addChild( _camera );
 

Mettre la caméra dans un EffectGroup n'a pas beaucoup d'intérêt.
Par contre, ce sont les meshes (entre autres) qu'il faut mettre dedans.
Comme tout groupe, l'EffectGroup a une influence sur ses descendants. En l'occurrence, il dit quel effet sera utilisé lors des rendus.

a+

#7 AlexandroG

    Ceinture Blanche

  • Members
  • Pip
  • 12 messages

Posté 20 November 2011 - 15:45 PM

Thank you! ;-)

#8 Logic

  • Honoris
  • PipPipPipPipPipPipPipPip
  • 2733 messages

Posté 20 November 2011 - 17:41 PM

OK j'avais juste une maladresse dans la hiérarchie (pas la caméra, dans un autre node). Maintenant le shader s'applique bien.

Je donne la page de code au cas où ça intéresse quelqu'un une scène toute prête. La classe TestShader est dans le même fichier AS juste par commodité, c'est évidemment pas une bonne pratique.


package
{
        import aerys.minko.Minko;
        import aerys.minko.render.Viewport;
        import aerys.minko.render.effect.SinglePassRenderingEffect;
        import aerys.minko.render.effect.lighting.LightingEffect;
        import aerys.minko.render.effect.lighting.LightingStyle;
        import aerys.minko.scene.node.camera.ArcBallCamera;
        import aerys.minko.scene.node.group.EffectGroup;
        import aerys.minko.scene.node.group.Group;
        import aerys.minko.scene.node.group.StyleGroup;
        import aerys.minko.scene.node.group.TransformGroup;
        import aerys.minko.scene.node.light.AmbientLight;
        import aerys.minko.scene.node.light.DirectionalLight;
        import aerys.minko.scene.node.mesh.Mesh;
        import aerys.minko.scene.node.mesh.primitive.CubeMesh;
        import aerys.minko.scene.node.texture.BitmapTexture;
        import aerys.minko.type.log.DebugLevel;
        import aerys.minko.type.math.Vector4;
       
        import flash.display.Sprite;
        import flash.display.StageAlign;
        import flash.display.StageScaleMode;
        import flash.events.Event;
       
        public class minkoShader extends Sprite
        {
               
                private var _view:Viewport;
                private var _camera:ArcBallCamera;
                private var _scene:Group;
                private var _sceneStyle:StyleGroup;
                private var _sceneEffect:EffectGroup;
               
                private var _ambienLight:AmbientLight;
                private var _directionalLight:DirectionalLight;
               
                [Embed(source="texture.jpg")]
                private var TextureClass:Class;
               
                private var _transf:TransformGroup;
                private var _styleGroup:StyleGroup;
                private var _texture:BitmapTexture;
                private var _mesh:Mesh;
               
                public function minkoShader()
                {
                        if (stage)
                                init();
                        else
                                addEventListener(Event.ADDED_TO_STAGE, onAdded);
                }
               
                private function onAdded( e:Event ) : void
                {
                        removeEventListener(Event.ADDED_TO_STAGE, onAdded);
                        init();
                }
               
                private function init():void
                {
                        //
                        stage.frameRate = 30;
                        stage.scaleMode = StageScaleMode.NO_SCALE;
                        stage.align = StageAlign.TOP_LEFT;
                       
                        Minko.debugLevel = DebugLevel.SHADER_AGAL;
                        //
                        _view = new Viewport();
                        _camera = new ArcBallCamera();
                        _scene = new Group();
                        _sceneStyle = new StyleGroup();
                        _sceneEffect = new EffectGroup(  new SinglePassRenderingEffect( new TestShader() ) );
                       
                        stage.addChild( _view );
                        _scene.addChild( _camera );
                        _scene.addChild( _sceneStyle );
                        _sceneStyle.addChild( _sceneEffect );
                       
                        //
                        _camera.distance = 10;
                       
                        /*_ambienLight = new AmbientLight( 0xFFFFFF, 2 );
                        _directionalLight = new DirectionalLight( 0xFFFFFF, 6, 8, 64, new Vector4(1, -1, 1, 1) );
                        _view.defaultEffect = new LightingEffect();
                        _sceneStyle.addChild( _ambienLight );
                        _sceneStyle.addChild( _directionalLight );*/

                       
                        //
                        _transf = new TransformGroup();
                        _styleGroup = new StyleGroup();
                        //_styleGroup.style.set( LightingStyle.LIGHTS_ENABLED, true );
                        _texture = new BitmapTexture( new TextureClass().bitmapData );
                        _mesh = CubeMesh.cubeMesh;
                       
                        _sceneEffect.addChild( _transf );
                        _transf.addChild( _styleGroup );
                        _styleGroup.addChild( _texture );
                        _styleGroup.addChild( _mesh );
                       
                        //
                        this.addEventListener( Event.ENTER_FRAME, onEnterFrame );
                }
               
                private function onEnterFrame( e:Event ):void
                {
                        _camera.rotation.x = - Math.PI / 4;
                        _camera.rotation.y = (2 * stage.mouseX / stage.stageWidth - 1) * Math.PI;
                       
                        _view.render( _scene );
                }
               
        }
}

/////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////

import aerys.minko.render.effect.basic.BasicStyle;
import aerys.minko.render.shader.ActionScriptShader;
import aerys.minko.render.shader.SValue;
import aerys.minko.type.math.Vector4;

class TestShader extends ActionScriptShader
{
       
        public function TestShader()
        {
               
        }
       
        protected override function getOutputPosition():SValue
        {
                return vertexClipspacePosition;
        }
       
        private var _mult:Vector4 = new Vector4(2, 2, 2); // ca multipliera les canaux RGB
        protected override function getOutputColor():SValue
        {
                var uv:SValue = interpolate(vertexUV);
                var diffuse:SValue = sampleTexture(BasicStyle.DIFFUSE, uv);
               
                // juste un test en essayant eclaircissant
                diffuse = multiply( diffuse, _mult );
               
                return diffuse;
        }
}


 

Fichier(s) joint(s)



#9 Logic

  • Honoris
  • PipPipPipPipPipPipPipPip
  • 2733 messages

Posté 20 November 2011 - 18:48 PM

Par contre problème maintenant si j'essai de cumuler dans la même scène un StyleGroup activant un éclairage et un EffectGroup activant un shader custom. Le shader interne à Minko s'occupant de calculer les ombrages issus de l'éclairage semble écrasé par le shader custom. J'ai essayé plusieurs hiérarchies, avec le StyleGroup sous le EffectGroup et inversement, mais rien n'y fait, c'est toujours le shader custom qui gagne.

Est-ce qu'il faut recoder totalement le système d'ombrage dans ses propres shader ?

Quelque chose me dit que non... mais je n'ai rien vu pour brancher des shader les uns derrière les autres.

#10 AlexandroG

    Ceinture Blanche

  • Members
  • Pip
  • 12 messages

Posté 20 November 2011 - 19:26 PM

this question is actual for me too. how to use custom shaders with minko-lighting built in shaders?

and second question is how to use 2 or more textures in shader, for ex in multitexuring or detail maps?

Modifié par AlexandroG, 20 November 2011 - 19:27 PM.


#11 Jean-Marc Le Roux

    Ceinture Noire

  • Minko
  • PipPipPipPipPipPipPip
  • 210 messages

Posté 20 November 2011 - 19:50 PM

Voir le messageLogic, le 20 November 2011 - 18:48 PM, dit :

Est-ce qu'il faut recoder totalement le système d'ombrage dans ses propres shader ?

Quelque chose me dit que non... mais je n'ai rien vu pour brancher des shaders les uns derrière les autres.

Oui et non.
Il n'est pas possible de "brancher" plusieurs shaders. Les seuls moyens de faire ça force des contraintes d'architectures et/ou de rendu qui, au final, rende la tâche plus difficile que de recoder un shader. D'ailleurs, on ne peut pas "brancher" des shaders les uns derrières les autres. En règle général, mélanger deux shaders consiste à faire des opérations bien plus compliquées.

Par contre, il est possible d'utiliser ce que nous avons appelé des "shader parts". Chaque "shader part" propose des méthodes utile pour reproduire un effet, par exemple il y'a la classe AnimationShaderPart qui permet de gérer tout ce qui est morphing/skinning avec un simple appel de fonction. Vous n'aurez donc à priori plus jamais à vous soucier des animations sur le GPU grâce à ce shader part.

Malheureusement, minko-lighting est écrit en utilisant les ASG (ActionScript Shader Graph), ce qui est "en dessous" des shaders AS3 ou plutôt la représentation intermédiaire qui est prise en entrée du compilateur. A ce titre, il n'existe pas encore de "LightingShaderPart". Mais nous sommes en train de refaire tout minko-lighting pour la v2 avec, justement, tous les shaders parts utiles pour gérer les lumières, les ombres, le normal mapping, etc...

A partir du moment où minko-lighting sera implémenté avec des AS3 shaders et que les shaders parts correspondant seront également mis à disposition, il sera très simple de réutiliser le moteur d'éclairage ainsi fourni pour le détourner et le modifier à volonté. Mais déjà aujourd'hui vous pouvez jouer avec tout ce que minko-lighting met à disposition, notamment les lumières placées dans la scène, dans vos propres shaders. Un bon exemple est le LightCubeShader utilisé dans la démo Gravity où l'on se sert des points lights avec une formule complètement hackée pour obtenir le rendu que l'on a dans la démo.

Citation

la seconde question est comment utiliser 2 (ou plus) textyre dans un shader, par exemple pour du multi-texturing ou des details maps ?

La méthode ActionScriptShaderPart.sampleTexture prend en premier argument le style associé à la texture que l'on veut sampler. Dans l'exemple ci-dessous, on sample la texture BasicStyle.DIFFUSE :


public class SimpleTextureShader extends ActionScriptShader
{
  // retourne la position du vertex en clipspace (repère écran normalisé [-1 .. 1])
  override protected function getOutputPosition() : SValue
  {
    return vertexClipspacePosition;
  }

  // retourne du rouge pour la couleur du pixel
  override protected function getOutputColor() : SValue
  {
    // on doit utiliser "interpolate" car la valeur viens du vertex shader
    var uv : SValue = interpolate(vertexUV);

    // sample la texture dont la propriété "styleProperty" vaut BasicStyle.DIFFUSE
    return sampleTexture(BasicStyle.DIFFUSE, uv);
  }
}
 

Comment gérer plusieurs textures ? C'est très simple : il suffit de créer le style correspondant.
Par exemple pour le bump mapping :


public final class BumpMappingStyle
{
  public static const BUMP_MAP : int = Style.getStyleId("bump map");
}

public final class BumpMappingShader
{
  override protected function getOutputPosition() : SValue
  {
    return vertexClipspacePosition;
  }

  override protected function getOutputColor() : SValue
  {
    var uv : SValue = interpolate(vertexUV);
    var bump : SValue = sampleTexture(BumpMappingStyle.BUMP_MAP, uv);
    var diffuse : SValue = sampleTexture(BasicStyle.DIFFUSE, uv);

    // do your bump mapping stuff here...

    return bumpMappedDiffuse;
  }
}
 

Comment initialiser la scène :


var bumpMap : BitmapTexture = LoaderGroup.loadClass(EMBED_BUMP)[0];
var diffuseMap : BitmapTexture = LoaderGroup.loadClass(EMBED_DIFFUSE)[0];

bumpMap.styleProperty = BumpMappingStyle.BUMP_MAP;
// inutile car "styleProperty" vaut BasicStyle.DIFFUSE par défaut :
// diffuseMap.styleProperty = BasicStyle.DIFFUSE;

var materialScene : MaterialGroup = new MaterialGroup(new SinglePassRenderingEffect(new BumpMappingShader()));

materialScene.textures.addChild(bumpMap).addChild(diffuseMap);
materialScene.addChild(CubeMesh.cubeMesh);
 

Dans le Shader Lab, cela se traduira par une fonctionnalité spécifique permettant de partager des choses entre plusieurs shaders. Je reviendrais là dessus lors d'une présentation plus détaillée de l'outil, mais ce système s'apparente aux shader parts.

a+

#12 AlexandroG

    Ceinture Blanche

  • Members
  • Pip
  • 12 messages

Posté 20 November 2011 - 20:01 PM

And new question. how to share variables between vertex and fragment shader?
in GLSL (or HLSL) we can use "varying" and compute some vector stuff in vertex shader and then use it in fragment shader.

#13 Logic

  • Honoris
  • PipPipPipPipPipPipPipPip
  • 2733 messages

Posté 20 November 2011 - 20:05 PM

OK thx.

#14 Jean-Marc Le Roux

    Ceinture Noire

  • Minko
  • PipPipPipPipPipPipPip
  • 210 messages

Posté 20 November 2011 - 20:11 PM

Voir le messageAlexandroG, le 20 November 2011 - 20:01 PM, dit :

Comment passer des variables du vertex shader au fragment shader ?

En utilisant la méthode "interpolate". Cette méthode fait toute l'allocation et le passage de valeur du vertex shader vers le fragment shader en utilisant les registres "varying".

Exemple :


public class SimpleDirectionalLightingShader
{
  private const LIGHT_DIRECTION : SValue = float3(1., -1., 0.);

  private var _vertexIllumination : SValue = null;

  override protected function getOutoutPosition()
  {
    var lightDirection : SValue = normalize(LIGHT_DIRECTION);
    var normal : SValue = normalize(vertexNormal);

    _vertexIllumination = dotProduct3(normal, lightDirection);
    _vertexIllumination = negate(_vertexIllumination);

    return vertexClipspacePosition();
  }

  override protected function getOutputColor()
  {
    var uv : SValue = interpolate(vertexUV);
    var diffuse : SValue = sampleTexture(BasicStyle.DIFFUSE, uv);
    var illumination : SValue = interpolate(_vertexIllumination);

    diffuse = float4(
      multiply(diffuse.rgb, illumination),
      diffuse.a
    );

    return diffuse;
  }
}
 


#15 AlexandroG

    Ceinture Blanche

  • Members
  • Pip
  • 12 messages

Posté 20 November 2011 - 20:20 PM

Thank you! Every day I get better and better understand at Minko :smile:

#16 Jean-Marc Le Roux

    Ceinture Noire

  • Minko
  • PipPipPipPipPipPipPip
  • 210 messages

Posté 20 November 2011 - 20:23 PM

Voir le messageAlexandroG, le 20 November 2011 - 20:20 PM, dit :

Thank you! Every day I get better and better understand at Minko :smile:

I'm currently working on the international forum to make it easier for you to ask questions. Just a few hours to wait and it will be available.

Regards,

Je suis en train de travailler sur le forum international pour permettre à tout le monde de poser des questions. Encore quelques heures à attendre et ça sera disponible.

a+

#17 Logic

  • Honoris
  • PipPipPipPipPipPipPipPip
  • 2733 messages

Posté 20 November 2011 - 20:26 PM

Non mais on est bien là :P

#18 AlexandroG

    Ceinture Blanche

  • Members
  • Pip
  • 12 messages

Posté 24 November 2011 - 08:47 AM

Hi!
How to pass variable from actionscript code to Shader, for example time value in particle simulation etc?

#19 Jean-Marc Le Roux

    Ceinture Noire

  • Minko
  • PipPipPipPipPipPipPip
  • 210 messages

Posté 24 November 2011 - 10:46 AM

Voir le messageAlexandroG, le 24 November 2011 - 08:47 AM, dit :

Hi!
How to pass variable from actionscript code to Shader, for example time value in particle simulation etc?

Comme vous l'avez sûrement compris en lisant la documentation des classes ActionScriptShader et SValue, toutes les valeurs avec un types différent de SValue sont implicitement considérées comme des constantes, ce qui est parfaitement logique à partir du moment où on a compris ce qui se passe.

Pour utiliser des valeurs dynamiques, il faut utiliser des "paramètres". Il y'a à ce jour plusieurs types de paramètres :
- getTransformParameter() permet de récupérer les "transform parameters", qui sont des données issue de TransformData et qui contiennent toutes les informations de transformations (local, world, view, projection et leurs différentes combinaisons)
- getWorldParameter() permet de récupérer les "world parameters", qui sont des données issue d'objets placés et accessible via WorldData dans la scène mais ayant une influence sur l'ensemble de cette dernière (la caméra, les lumières, le viewport...)
- getStyleParameter() permet de récupérer les "style parameters", qui sont des valeurs associées à des styles stockés au moment du parcourt mais disposés hiérarchiquement dans la scène, permettant ainsi de faire de l'héritage de styles à la manière d'HTML/CSS

Vous pouvez créer vos propres paramètres répondant à vos besoins précis. Pour ça, il vous suffit par exemple de regarder comment minko-lighting définit et utilise des world parameters pour les lumières. Je vous conseille notamment de lire le LightCubeShader, qui utilise les world parameters des lumières définit dans minko-lighting mais dans un shader custom complètement hacké pour donner le rendu obtenu dans la démo Gravity.

Pour ce qui est de la création de style parameters et leur utilisation, je vous renvoie à l'exemple d'utilisation du multi-texturing qui, pour l'instant, est relativement explicite.

Pour l'exemple précis du timer, voilà comment nous procédons (nous allons ajouter un moteur à particules et également des timers):
- nous créons un world parameter "Timer"
- ce world parameter aura une classe associée "TimeData" (comme LightData) qui stockera toutes les données de temps intéressantes, par exemple le framerate, le temps Unix ou encore le temps obtenu avec getTimer()
- on lit ce world parameter dans le shader avec la méthode "getWorldParameter(1, TimeData.TIME)" par exemple

Je pense que nous allons rajouter ce world parameter dans minko dans une prochaine update, mais si vous arrivez à comprendre comment les paramètres fonctionne, alors vous êtes les rois du shaders paramétriques et vous aurez une puissance incroyable pour customizer vos scènes.

Une dernière précision : tous les paramètres accessibles jusqu'ici sont issues du scene graph, ce qui n'est pas forcément commode dans certaines situations, et parfois même couteux pour rien. Nous allons sûrement ajouter un nouveau type de paramètres, plus simple, qui seront simplement des paramètres nommés. Ces paramètres seront selon toute vraissemblance accessibles via une méthode getNamedParameter().

a+

#20 AlexandroG

    Ceinture Blanche

  • Members
  • Pip
  • 12 messages

Posté 24 November 2011 - 16:28 PM

Voir le messageJean-Marc Le Roux, le 24 November 2011 - 10:46 AM, dit :

Comme vous l'avez sûrement compris en lisant la documentation des classes...
Thank you!



1 utilisateur(s) li(sen)t ce sujet

0 membre(s), 1 invité(s), 0 utilisateur(s) anonyme(s)

authorised training centre

Centre de Formation Mediabox - Adobe et Apple Authorised Training Center.

Déclaré auprès de la Direction du Travail et de la Formation Professionnelle

Mediabox : SARL au capital de 62.000€ - Numéro d'activité : 11 75 44555 75 - SIRET : 49371646800035

MEDIABOX, 23, rue de Bruxelles, 75009 PARIS

FFP