3Dプログラミング講座・その8:応用その4・GLSL、シェーダー、その2



同次座標がw,x,y,z,...の順番で定義されたものの説明です。順番が違うだけで、機能に変わりはありませんが・・・


ポイントセットシェーダーを作ります。
サンプルはこちら
ファイルはこちら



コードはこちら。


pointsetshader.htm

...省略...

<script language="JavaScript" type="text/javascript">
var TMan = new N6LTimerMan();  //タイマーマネージャー
var intvl = 50;
var baseTime;
var x3domRuntime;


//メインループ
function GLoop(id)
{
  if(!x3domRuntime) {
    x3domRuntime = document.getElementById('x3dabs').runtime;
    if(!x3domRuntime) return;
  }

  var elm = document.getElementById('vp');

  var SWM = x3domRuntime.viewMatrix().inverse(); //ワールド回転行列取得
  var WM = new N6LMatrix().FromX3DOM(SWM);
  var Seye = SWM.multMatrixPnt(new x3dom.fields.SFVec3f(0, 0, 0)); //視点位置取得
  var sp = new x3dom.fields.SFVec3f(0, 0, 0);
  var Sat = x3dom.fields.SFVec3f.copy(sp);
  var lookat = new N6LVector([1.0, Sat.x, Sat.y, Sat.z], true);
  var LAM = WM.LookAtMat2(lookat);
  var Vec = LAM.Vector();
  var ori = Vec.ToX3DOM();

  elm.setAttribute('position', Seye.toString());
  elm.setAttribute('orientation', ori.toString());
  elm.setAttribute('centerOfRotation', sp.toString());

  var t = (new Date().getTime() - baseTime) / 1000;
  changeShaderParamValue('time', String(t));

  TMan.timer[id].setalerm(function() { GLoop(id); }, intvl);  //メインループセット
  return true;
}

function enter() {
  baseTime = new Date().getTime();
  var numParticles = 10000;
  var cdDOMNode;
  var cdObj;
  var clDOMNode;
  var clObj;
  cdDOMNode = document.getElementById("cd");
  cdObj = cdDOMNode.requestFieldRef("point");
  clDOMNode = document.getElementById("cl");
  clObj = clDOMNode.requestFieldRef("color");
  for(var i = 0 ; i < numParticles ; i++) {
    var a = Math.PI * 2 * Math.random();
    var d = 8 + Math.random() * 8;
    var x = Math.sin(a)*d;
    var y = 3 + Math.random() * 2;
    var z = Math.cos(a)*d;
    var ltime = (3 + Math.random()) / 4.0;
    var sft = Math.random();
    cdObj.push(new x3dom.fields.SFVec3f(x, y, z)); //座標セット
    clObj.push(new x3dom.fields.SFColor(ltime, sft, 0.0)); //追加情報セット
  }
  cdDOMNode.releaseFieldRef("point");
  clDOMNode.releaseFieldRef("color");

  TMan.add();
  TMan.timer[0].setalerm(function() { GLoop(0); }, intvl);  //メインループセット
}

</script>

...省略...

<x3d id='x3dabs' showStat='false' showLog='false' width='600px' height='400px'>
      <Scene id='scene'>
        <Viewpoint id='vp' position='0 40 40' centerOfRotation='0 0 0'></Viewpoint>
        <Transform>
          <Shape>
            <Appearance>
                <Material diffuseColor=".7 .7 .7" specularColor=".5 .5 .5"></Material>
                <ImageTexture url='img/particle.png'></ImageTexture>
                <ComposedShader DEF='ComposedShader'>
                  <field name='matCol' type='SFVec3f' value='1.0 0.8 0.53'></field>
                  <field id='time' name='time' type='SFFloat' value='0.0'></field>
                  <field id='size' name='size' type='SFFloat' value='0.1'></field>
                  <ShaderPart type='VERTEX'>
                        attribute vec3 position;
                        attribute vec3 color;
                        uniform float time;
                        uniform float size;
                        uniform mat4 modelViewMatrix;
                        uniform mat4 modelViewMatrixInverse;
                        uniform mat4 modelViewProjectionMatrix;
                        varying float fragAlpha;
                        
                        void main()
                        {

                            float lifetime = color.r * 4.0;
                            float shift = color.g;
                            float t = fract(time / lifetime + shift);
                            float c = pow(t, 1.7) * 10.0;
                            float s = ceil(c);
                            float y = (1.0 - pow((s - c) * 2.0 - 1.0, 2.0)) / (s * s);

                            fragAlpha = 1.0 - smoothstep(0.8, 1.0, t);

                            vec3 p;
                            p.x = position.x * t;
                            p.y = position.y * y;
                            p.z = position.z * t;
                            vec4 mvPosition = vec4(p, 1.0);
                            gl_Position = modelViewProjectionMatrix * mvPosition;

                            float r = length(p);
                            if(r < 1.0) r = 256.0;
                            gl_PointSize = size * (256.0 / r) * (1.0 + smoothstep(0.8, 1.0, t) * 6.0);

                        }
                  </ShaderPart>
                  
                  <ShaderPart type='FRAGMENT'>
                        #ifdef GL_FRAGMENT_PRECISION_HIGH
                          precision highp float;
                        #else
                          precision mediump float;
                        #endif
                        
                        uniform vec3 matCol;
                        uniform sampler2D tex;
                        varying float fragAlpha;
                        
                        void main()
                        {
                            vec4 texCol = texture2D(tex, gl_PointCoord);
                            float sq = 1.4142135623;
                            vec2 p = (gl_PointCoord - 0.5) * 2.0;
                            float r = (1.0 - length(p) / sq) * 1.5;
                            vec4 col = vec4(matCol, fragAlpha);
                            col.r = col.r * r * 0.9;
                            col.g = col.g * r * 0.9;
                            col.b = col.b * r * 0.9;
                            col.a = col.a * r * 0.9;
                            //col.r = texCol.r * col.r * r * 0.9;
                            //col.g = texCol.g * col.g * r * 0.9;
                            //col.b = texCol.b * col.b * r * 0.9;
                            //col.a = texCol.a * col.a * r * 0.9;
                            col = clamp(col, 0.0, 1.0);
                            gl_FragColor = mix(col, texCol, 0.3);
                            //gl_FragColor = col;
                        }
                  </ShaderPart>
                </ComposedShader>
            </Appearance>
            
            <PointSet id='ps'>
                <Coordinate id='cd'></Coordinate>
                <Color id='cl'></Color>
            </PointSet>
          </Shape>
        </Transform>
      </Scene>
</x3d>

...省略...



大量のパーティクルの描画です。
こちらを参考にした。
シェーダーへの頂点毎の情報渡しに、<COLOR>タグを使っています。もちろん、この場合、色情報としては使えません。
<COLOR>タグを使いたいのであれば、他のattribute(アトリビュート)に、<FloatVertexAttribute>等で下を参考に、同様に、多分、変えられます。
<particleset>タグでは、<composedshader>が効かなかったので、<pointset>タグにしました。
vec3 p;
p = (p - 0.5) * 2.0;
p = p * vec3(x, y, z);
こういう書き方も出来るはずなんですけど、なんかエラーになったら、要素ごと個別に行えばいいです。


Shader Variables

Type

Name

Comment

Type

Name

Comment

attribute vec3

position

vec4 if normals embedded

attribute vec3

normal

attribute vec2

texcoord

attribute vec3

color

vec4 for ColorRGBA

attribute vec3

tangent

from FloatVertexAttribute

attribute vec3

binormal

from FloatVertexAttribute

uniform mat4

viewMatrix

uniform mat4

viewMatrixInverse

uniform mat4

projectionMatrix

uniform mat4

normalMatrix

uniform mat4

modelViewMatrix

uniform mat4

modelViewMatrixInverse

uniform mat4

modelViewProjectionMatrix

uniform mat4

worldMatrix

uniform mat4

worldInverseTranspose

uniform mat4

texTrafoMatrix

texture coordinate transform matrix

uniform sampler2D

diffuseMap

from CommonSurfaceShader

uniform sampler2D

normalMap

from CommonSurfaceShader

uniform sampler2D

specularMap

from CommonSurfaceShader

uniform sampler2D

cubeMap

from ComposedCubeMap

uniform vec3

diffuseColor

uniform vec3

specularColor

uniform vec3

emissiveColor

uniform float

shininess

uniform float

transparency

uniform float

ambientIntensity

uniform float

light0_On

same for light1, light2, etc.

uniform float

light0_Type

same for light1, light2, etc.

uniform vec3

light0_Location

same for light1, light2, etc.

uniform vec3

light0_Direction

same for light1, light2, etc.

uniform vec3

light0_Color

same for light1, light2, etc.

uniform vec3

light0_Attenuation

same for light1, light2, etc.

uniform float

light0_Radius

same for light1, light2, etc.

uniform float

light0_Intensity

same for light1, light2, etc.

uniform float

light0_AmbientIntensity

same for light1, light2, etc.

uniform float

light0_BeamWidth

same for light1, light2, etc.

uniform float

light0_CutOffAngle

same for light1, light2, etc.

uniform float

light0_ShadowIntensity

same for light1, light2, etc.

uniform vec3

fogColor

uniform vec3

fogType

uniform vec3

fogRange



スライドショーの画像切り替えエフェクトのシェーダーを作ります。
サンプルはこちら
ファイルはこちら



コードはこちら。

slideshow3.htm

...省略...

<script language="JavaScript" type="text/javascript">
var TMan = new N6LTimerMan();  //タイマーマネージャー
var intvl = 50;
var baseTime;
var x3domRuntime;


//メインループ
function GLoop(id)
{
  if(!x3domRuntime) {
    x3domRuntime = document.getElementById('x3dabs').runtime;
    if(!x3domRuntime) return;
  }

  var elm = document.getElementById('vp');

  var SWM = x3domRuntime.viewMatrix().inverse(); //ワールド回転行列取得
  var WM = new N6LMatrix().FromX3DOM(SWM);
  var Seye = SWM.multMatrixPnt(new x3dom.fields.SFVec3f(0, 0, 0)); //視点位置取得
  var sp = new x3dom.fields.SFVec3f(0, 0, 0);
  var Sat = x3dom.fields.SFVec3f.copy(sp);
  var lookat = new N6LVector([1.0, Sat.x, Sat.y, Sat.z], true);
  var LAM = WM.LookAtMat2(lookat);
  var Vec = LAM.Vector();
  var ori = Vec.ToX3DOM();

  elm.setAttribute('position', Seye.toString());
  elm.setAttribute('orientation', ori.toString());
  elm.setAttribute('centerOfRotation', sp.toString());

  var t = (new Date().getTime() - baseTime) / 1000;
  changeShaderParamValue('time', String(t));

  TMan.timer[id].setalerm(function() { GLoop(id); }, intvl);  //メインループセット
  return true;
}

function enter() {
  baseTime = new Date().getTime();

  TMan.add();
  TMan.timer[0].setalerm(function() { GLoop(0); }, intvl);  //メインループセット
}


function radio(id) {
    changeShaderParamValue('calcSw', String(id));
}


</script>

...省略...

<x3d id='x3dabs' showStat='false' showLog='false' width='600px' height='400px'>
      <Scene id='scene'>
        <Viewpoint id='vp' position='0 0 8' centerOfRotation='0 0 0'></Viewpoint>


        <Transform translation='0 0 -0.1'>
          <Shape>
            <Appearance>
                <Material diffuseColor=".7 .7 .7" specularColor=".5 .5 .5"></Material>
                <ImageTexture url='img/koala.jpg'></ImageTexture>
            </Appearance>
            <Box size='5, 5, 0.1'></Box>
          </Shape>
        </Transform>


        <Transform translation=''0 0 0'>
          <Shape>
            <Appearance>
                <Material diffuseColor=".7 .7 .7" specularColor=".5 .5 .5"></Material>
                <ImageTexture url='img/kumausagineko.jpg'></ImageTexture>

                <ComposedShader DEF='ComposedShader'>
                  <field id='time' name='time' type='SFFloat' value='0.0'></field>
                  <field id='calcSw' name='calcSw' type='SFFloat' value='0.0'></field>
                  <ShaderPart type='VERTEX'>
                        attribute vec3 position;
                        attribute vec2 texcoord;
                        uniform mat4 modelViewMatrix;
                        uniform mat4 modelViewMatrixInverse;
                        uniform mat4 modelViewProjectionMatrix;
                        varying vec2 fragTexCoord;
                        
                        void main()
                        {
                            fragTexCoord = vec2(texcoord.x, 1.0 - texcoord.y);
                            gl_Position = modelViewProjectionMatrix * vec4(position, 1.0);
                        }
                  </ShaderPart>
                  
                  <ShaderPart type='FRAGMENT'>
                        #ifdef GL_FRAGMENT_PRECISION_HIGH
                          precision highp float;
                        #else
                          precision mediump float;
                        #endif
                        
                        uniform sampler2D tex;
                        uniform float time;
                        uniform float calcSw;
                        varying vec2 fragTexCoord;

                        const int   oct  = 8;
                        const float per  = 0.5;
                        const float PI   = 3.1415926;
                        const float SQ   = 1.4142136;
                        const float EX   = 2.7182818;
                        const float SQ10 = 3.1622777;
                        const float eps  = 0.000001;
                        // 補間関数
                        float interpolate(float a, float b, float x){
                            float f = (1.0 - cos(x * PI)) * 0.5;
                            return a * (1.0 - f) + b * f;
                        }

                        // 乱数生成
                        float rnd(vec2 p){
                            return fract(sin(dot(p ,vec2(12.9898,78.233))) * 43758.5453);
                        }

                        // 補間乱数
                        float irnd(vec2 p){
                            vec2 i = floor(p);
                            vec2 f = fract(p);
                            vec4 v = vec4(rnd(vec2(i.x,       i.y      )),
                                          rnd(vec2(i.x + 1.0, i.y      )),
                                          rnd(vec2(i.x,       i.y + 1.0)),
                                          rnd(vec2(i.x + 1.0, i.y + 1.0)));
                            return interpolate(interpolate(v.x, v.y, f.x), interpolate(v.z, v.w, f.x), f.y);
                        }

                        // ノイズ生成
                        float noise(vec2 p){
                            float t = 0.0;
                            for(int i = 0; i < oct; i++){
                                float freq = pow(2.0, float(i));
                                float amp  = pow(per, float(oct - i));
                                t += irnd(vec2(p.x / freq, p.y / freq)) * amp;
                            }
                            return t;
                        }

                        // シームレスノイズ生成
                        float snoise(vec2 p, vec2 q, vec2 r){
                            return noise(vec2(p.x,       p.y      )) *        q.x  *        q.y  +
                                   noise(vec2(p.x,       p.y + r.y)) *        q.x  * (1.0 - q.y) +
                                   noise(vec2(p.x + r.x, p.y      )) * (1.0 - q.x) *        q.y  +
                                   noise(vec2(p.x + r.x, p.y + r.y)) * (1.0 - q.x) * (1.0 - q.y);
                        }

                        //星
                        void star(void){
                            vec2 q = vec2(fragTexCoord.x, 1.0 - fragTexCoord.y);
                            vec2 p = (q - 0.5) * 2.0;
                            float l = length(p);
                            float th = atan(p.y, p.x);
                            float f0 = cos((acos(sin(5.0 * th)) - 2.0 * PI) / 5.0);
                            if(abs(f0) < eps) { discard; }
                            float t = mod(time, 4.0) / 4.0;
                            float r = 1.0 / f0 / SQ10 * t * 3.0;
                            r = mix(r, SQ, t);
                            float inner = 0.0;
                            if(l <= r) { inner = 1.0; }
                            vec4 texCol = texture2D(tex, fragTexCoord);
                            texCol.a = inner;
                            gl_FragColor = texCol;
                        }

                        //円
                        void circle(void){
                            vec4 texCol = texture2D(tex, fragTexCoord);
                            float t = 1.0 - length((fragTexCoord - 0.5) * 2.0) / SQ;
                            //float t = length((fragTexCoord - 0.5) * 2.0) / SQ;
                            float spn = 32.0;
                            float rt = 4.0;
                            float pw = 32.0;
                            float m = pow(min(t * mod(time * rt, spn), 1.0), pw);
                            //float m = min(t * mod(time * rt, spn), 1.0);
                            texCol.a = texCol.a * m;
                            gl_FragColor = texCol;
                        }

                        //ランダムモザイク
                        void mosaic(void){
                            vec4 texCol = texture2D(tex, fragTexCoord);
                            // noise
                            //vec2 t = floor(gl_FragCoord.xy / 16.0);
                            vec2 t = floor(gl_FragCoord.xy / 16.0) + vec2(time * 10.0, time * 3.0);
                            //vec2 t = gl_FragCoord.xy + vec2(time * 10.0);
                            //float n = noise(t);
                            float n = rnd(t);

                            // seamless noise
                            //const float map = 256.0;
                            //vec2 t = mod(gl_FragCoord.xy + vec2(time * 10.0), map);
                            //float n = snoise(t, t / map, vec2(map));

                            //texCol.a = texCol.a * n;
                            float spn = 32.0;
                            float rt = 4.0;
                            float pw = 32.0;
                            //float m = min(floor(n * mod(time * rt, spn)), 1.0);
                            float m = pow(min(n * mod(time * rt, spn), 1.0), pw);
                            //float m = floor(n * 2.0);
                            texCol.a = texCol.a * m;
                            gl_FragColor = texCol;
                            //gl_FragColor = vec4(vec3(n), 1.0);
                        }

                        void main(void) {
                            //mosaic();
                            //circle();
                            //star();
                            if(0.0 <= calcSw && calcSw < 1.0) { mosaic(); }
                            else if(calcSw < 2.0) { circle(); }
                            else if(calcSw < 3.0) { star(); }
                            else { mosaic(); }
                        }
                  </ShaderPart>
                </ComposedShader>

            </Appearance>
            
            <Box size='5, 5, 0.1'></Box>
          </Shape>
        </Transform>


      </Scene>
</x3d>

...省略...




この例では、フラグメントシェーダーのみをいじっていますが、頂点シェーダーをいじると
さらにダイナミックなエフェクトになるでしょう。

今まで見てきて分かるように、シェーダーの基本的な書き方は、このように簡単に書けてしまいます。

<Shape>
 <Appearance>
  <Material diffuseColor=".7 .7 .7"></Material>
  <ImageTexture url='img/image.jpg'></ImageTexture>

  <ComposedShader DEF='ComposedShader'>
   <ShaderPart type='VERTEX'> //頂点シェーダー
    attribute vec3 position;
    uniform mat4 modelViewMatrix;
    uniform mat4 modelViewMatrixInverse;
    uniform mat4 modelViewProjectionMatrix;

    void main(){
     gl_Position = modelViewProjectionMatrix * vec4(position, 1.0); //頂点を決める
    }

   </ShaderPart>

   <ShaderPart type='FRAGMENT'> //フラグメントシェーダー
    #ifdef GL_FRAGMENT_PRECISION_HIGH
     precision highp float;
    #else
     precision mediump float;
    #endif

    uniform sampler2D tex;

    void main(void){
     gl_FragColor = texture2D(tex, gl_FragCoord); //色を決める
    }

   </ShaderPart>
  </ComposedShader>
 </Appearance>

 <Box size='5, 5, 0.1'></Box>
</Shape>

ここから、アトリビュートなどで、変化をつけて、いろいろなエフェクトを作ります。
普通は時間あるいは法線関連アトリビュートを設定することになるでしょう。


半透明のバンプマップ両面球にするため、x3domのシェーダーをオーバーロードします。
サンプルはこちら
ファイルはこちら



コードはこちら。


earth.htm

...省略...

<script language="JavaScript" type='text/javascript'>
//<![CDATA[


//########SHADERCODE########/


x3dom.shader.DynamicShader.prototype.generateVertexShader=function(gl,properties){
var shader="";
shader+="uniform mat4 modelViewMatrix;\n";
shader+="uniform mat4 modelViewProjectionMatrix;\n";
if(properties.POSCOMPONENTS==3){shader+="attribute vec3 position;\n";}
else if(properties.POSCOMPONENTS==4){shader+="attribute vec4 position;\n";}
if(properties.IMAGEGEOMETRY){
  shader+="uniform vec3 IG_bboxMin;\n";
  shader+="uniform vec3 IG_bboxMax;\n";
  shader+="uniform float IG_coordTextureWidth;\n";
  shader+="uniform float IG_coordTextureHeight;\n";
  shader+="uniform vec2 IG_implicitMeshSize;\n";
  for(var i=0;i<properties.IG_PRECISION;i++){
    shader+="uniform sampler2D IG_coords"+i+"\n;";
  }
  if(properties.IG_INDEXED){
    shader+="uniform sampler2D IG_index;\n";
    shader+="uniform float IG_indexTextureWidth;\n";
    shader+="uniform float IG_indexTextureHeight;\n";
  }
}
if(properties.POPGEOMETRY){
  shader+="uniform float PG_precisionLevel;\n";
  shader+="uniform float PG_powPrecision;\n";
  shader+="uniform vec3 PG_maxBBSize;\n";
  shader+="uniform vec3 PG_bbMin;\n";
  shader+="uniform vec3 PG_bbMaxModF;\n";
  shader+="uniform vec3 PG_bboxShiftVec;\n";
  shader+="uniform float PG_numAnchorVertices;\n";
  shader+="attribute float PG_vertexID;\n";
}
if(properties.LIGHTS){
  if(properties.NORMALMAP&&properties.NORMALSPACE=="OBJECT"){}
  else{
    shader+="varying vec3 fragNormal;\n";
    shader+="uniform mat4 normalMatrix;\n";
    if(properties.IMAGEGEOMETRY){shader+="uniform sampler2D IG_normals;\n";
    }else{
      if(properties.NORCOMPONENTS==2){
        if(properties.POSCOMPONENTS!=4){
          shader+="attribute vec2 normal;\n";
        }
      }else if(properties.NORCOMPONENTS==3){shader+="attribute vec3 normal;\n";}
    }
  }
}
if(properties.VERTEXCOLOR){
  if(properties.IMAGEGEOMETRY){
    shader+="uniform sampler2D IG_colors;\n";
    if(properties.COLCOMPONENTS==3){shader+="varying vec3 fragColor;\n";}
    else if(properties.COLCOMPONENTS==4){shader+="varying vec4 fragColor;\n";}
  }else{
    if(properties.COLCOMPONENTS==3){
      shader+="attribute vec3 color;\n";
      shader+="varying vec3 fragColor;\n";
    }else if(properties.COLCOMPONENTS==4){
      shader+="attribute vec4 color;\n";
      shader+="varying vec4 fragColor;\n";
    }
  }
}
if(properties.TEXTURED||properties.CSSHADER){
  shader+="varying vec2 fragTexcoord;\n";
  if(!properties.SPHEREMAPPING){
    if(properties.IMAGEGEOMETRY){shader+="uniform sampler2D IG_texCoords;\n";}
    else if(!properties.IS_PARTICLE){shader+="attribute vec2 texcoord;\n";}
  }
  if(properties.TEXTRAFO){shader+="uniform mat4 texTrafoMatrix;\n";}
  if(properties.NORMALMAP&&properties.NORMALSPACE=="TANGENT"&&!x3dom.caps.STD_DERIVATIVES){
    x3dom.debug.logWarning("Your System doesn't support the 'OES_STANDARD_DERIVATIVES' Extension. "+
    "You must set tangents and binormals manually via the FloatVertexAttribute-Node "+"to use normal maps");
    shader+="attribute vec3 tangent;\n";
    shader+="attribute vec3 binormal;\n";
    shader+="varying vec3 fragTangent;\n";
    shader+="varying vec3 fragBinormal;\n";
  }
  if(properties.CUBEMAP){shader+="varying vec3 fragViewDir;\n";shader+="uniform mat4 viewMatrix;\n";}
  if(properties.DISPLACEMENTMAP){
    shader+="uniform sampler2D displacementMap;\n";
    shader+="uniform float displacementFactor;\n";
    shader+="uniform float displacementWidth;\n";
    shader+="uniform float displacementHeight;\n";
    shader+="uniform float displacementAxis;\n";
  }
  if(properties.DIFFPLACEMENTMAP){
    shader+="uniform sampler2D diffuseDisplacementMap;\n";
    shader+="uniform float displacementFactor;\n";
    shader+="uniform float displacementWidth;\n";
    shader+="uniform float displacementHeight;\n";
    shader+="uniform float displacementAxis;\n";
  }
  if(properties.MULTIDIFFALPMAP||properties.MULTIVISMAP){shader+="attribute float id;\n";shader+="varying float fragID;\n";}
}
if(properties.IS_PARTICLE){shader+="attribute vec3 particleSize;\n";}
if(properties.LIGHTS||properties.FOG||properties.CLIPPLANES){
  shader+="uniform vec3 eyePosition;\n";
  shader+="varying vec4 fragPosition;\n";
  if(properties.FOG){shader+="varying vec3 fragEyePosition;\n";}
}
if(properties.REQUIREBBOX){shader+="uniform vec3 bgCenter;\n";shader+="uniform vec3 bgSize;\n";shader+="uniform float bgPrecisionMax;\n";}
if(properties.REQUIREBBOXNOR){shader+="uniform float bgPrecisionNorMax;\n";}
if(properties.REQUIREBBOXCOL){shader+="uniform float bgPrecisionColMax;\n";}
if(properties.REQUIREBBOXTEX){shader+="uniform float bgPrecisionTexMax;\n";}

shader+="void main(void) {\n";
if(properties.IMAGEGEOMETRY){
  if(properties.IG_INDEXED){
    shader+="vec2 halfPixel = vec2(0.5/IG_indexTextureWidth,0.5/IG_indexTextureHeight);\n";
    shader+="vec2 IG_texCoord = vec2(position.x*(IG_implicitMeshSize.x/IG_indexTextureWidth), position.y*(IG_implicitMeshSize.y/IG_indexTextureHeight)) + halfPixel;\n";
    shader+="vec2 IG_indices = texture2D( IG_index, IG_texCoord ).rg;\n";
    shader+="halfPixel = vec2(0.5/IG_coordTextureWidth,0.5/IG_coordTextureHeight);\n";
    shader+="IG_texCoord = (IG_indices * 0.996108948) + halfPixel;\n";
  }else{
    shader+="vec2 halfPixel = vec2(0.5/IG_coordTextureWidth, 0.5/IG_coordTextureHeight);\n";
    shader+="vec2 IG_texCoord = vec2(position.x*(IG_implicitMeshSize.x/IG_coordTextureWidth), position.y*(IG_implicitMeshSize.y/IG_coordTextureHeight)) + halfPixel;\n";
  }
  shader+="vec3 temp = vec3(0.0, 0.0, 0.0);\n";
  shader+="vec3 vertPosition = vec3(0.0, 0.0, 0.0);\n";
  for(var i=0;i<properties.IG_PRECISION;i++){
    shader+="temp = 255.0 * texture2D( IG_coords"+i+", IG_texCoord ).rgb;\n";
    shader+="vertPosition *= 256.0;\n";
    shader+="vertPosition += temp;\n";
  }
  shader+="vertPosition /= (pow(2.0, 8.0 * "+properties.IG_PRECISION+".0) - 1.0);\n";
  shader+="vertPosition = vertPosition * (IG_bboxMax - IG_bboxMin) + IG_bboxMin;\n";
  if(properties.LIGHTS){
    shader+="vec3 vertNormal = texture2D( IG_normals, IG_texCoord ).rgb;\n";
    shader+="vertNormal = vertNormal * 2.0 - 1.0;\n";
  }
  if(properties.VERTEXCOLOR){
    if(properties.COLCOMPONENTS==3){
      shader+="fragColor = texture2D( IG_colors, IG_texCoord ).rgb;\n";
    }else if(properties.COLCOMPONENTS==4){
      shader+="fragColor = texture2D( IG_colors, IG_texCoord ).rgba;\n";
    }
  }
  if(properties.TEXTURED||properties.CSSHADER){
    shader+="vec4 IG_doubleTexCoords = texture2D( IG_texCoords, IG_texCoord );\n";
    shader+="vec2 vertTexCoord;";
    shader+="vertTexCoord.r = (IG_doubleTexCoords.r * 0.996108948) + (IG_doubleTexCoords.b * 0.003891051);\n";
    shader+="vertTexCoord.g = (IG_doubleTexCoords.g * 0.996108948) + (IG_doubleTexCoords.a * 0.003891051);\n";
  }
}else{
  shader+="vec3 vertPosition = position.xyz;\n";
  if(properties.POPGEOMETRY){
    shader+="vec3 offsetVec = step(vertPosition / bgPrecisionMax, PG_bbMaxModF) * PG_bboxShiftVec;\n";
    shader+="if ((PG_precisionLevel <= 2.0) || PG_vertexID >= PG_numAnchorVertices) {\n";
    shader+="   vertPosition = floor(vertPosition / PG_powPrecision) * PG_powPrecision;\n";
    shader+="   vertPosition /= (65536.0 - PG_powPrecision);\n";
    shader+="}\n";
    shader+="else {\n";
    shader+="   vertPosition /= bgPrecisionMax;\n";
    shader+="}\n";
    shader+="vertPosition = (vertPosition + offsetVec + PG_bbMin) * PG_maxBBSize;\n";
  }else if(properties.REQUIREBBOX){
    shader+="vertPosition = bgCenter + bgSize * vertPosition / bgPrecisionMax;\n";
  }
  if(properties.LIGHTS){
    if(properties.NORCOMPONENTS==2){
      if(properties.POSCOMPONENTS==4){
        shader+="vec3 vertNormal = vec3(position.w / 256.0); \n";
        shader+="vertNormal.x = floor(vertNormal.x) / 255.0; \n";
        shader+="vertNormal.y = fract(vertNormal.y) * 1.00392156862745; \n";
      }else if(properties.REQUIREBBOXNOR){
        shader+="vec3 vertNormal = vec3(normal.xy, 0.0) / bgPrecisionNorMax;\n";
      }
      shader+="vec2 thetaPhi = 3.14159265358979 * vec2(vertNormal.x, vertNormal.y*2.0-1.0); \n";
      shader+="vec4 sinCosThetaPhi = sin( vec4(thetaPhi, thetaPhi + 1.5707963267949) ); \n";
      shader+="vertNormal.x = sinCosThetaPhi.x * sinCosThetaPhi.w; \n";
      shader+="vertNormal.y = sinCosThetaPhi.x * sinCosThetaPhi.y; \n";
      shader+="vertNormal.z = sinCosThetaPhi.z; \n";
    }else{
      if(properties.NORMALMAP&&properties.NORMALSPACE=="OBJECT"){}
      else{
        shader+="vec3 vertNormal = normal;\n";
        if(properties.REQUIREBBOXNOR){shader+="vertNormal = vertNormal / bgPrecisionNorMax;\n";}
        if(properties.POPGEOMETRY){shader+="vertNormal = 2.0*vertNormal - 1.0;\n";}
      }
    }
  }if(properties.VERTEXCOLOR){
    shader+="fragColor = color;\n";
    if(properties.REQUIREBBOXCOL){shader+="fragColor = fragColor / bgPrecisionColMax;\n";}
  }if((properties.TEXTURED||properties.CSSHADER)&&!properties.SPHEREMAPPING){
    if(properties.IS_PARTICLE){shader+="vec2 vertTexCoord = vec2(0.0);\n";}
    else{
      shader+="vec2 vertTexCoord = texcoord;\n";
      if(properties.REQUIREBBOXTEX){shader+="vertTexCoord = vertTexCoord / bgPrecisionTexMax;\n";}
    }
  }
}
if(properties.LIGHTS){
  if(properties.DISPLACEMENTMAP||properties.DIFFPLACEMENTMAP&&!properties.NORMALMAP){
    shader+="float dx = 1.0 / displacementWidth;\n";
    shader+="float dy = 1.0 / displacementHeight;\n";
    if(properties.DISPLACEMENTMAP){
      shader+="float s1 = texture2D(displacementMap, vec2(vertTexCoord.x - dx, 1.0 - vertTexCoord.y)).r;\n";
      shader+="float s2 = texture2D(displacementMap, vec2(vertTexCoord.x, 1.0 - vertTexCoord.y - dy)).r;\n";
      shader+="float s3 = texture2D(displacementMap, vec2(vertTexCoord.x + dx, 1.0 - vertTexCoord.y)).r;\n";
      shader+="float s4 = texture2D(displacementMap, vec2(vertTexCoord.x, 1.0 - vertTexCoord.y + dy)).r;\n";
    }else if(properties.DIFFPLACEMENTMAP){
      shader+="float s1 = texture2D(diffuseDisplacementMap, vec2(vertTexCoord.x - dx, 1.0 - vertTexCoord.y)).a;\n";
      shader+="float s2 = texture2D(diffuseDisplacementMap, vec2(vertTexCoord.x, 1.0 - vertTexCoord.y - dy)).a;\n";
      shader+="float s3 = texture2D(diffuseDisplacementMap, vec2(vertTexCoord.x + dx, 1.0 - vertTexCoord.y)).a;\n";
      shader+="float s4 = texture2D(diffuseDisplacementMap, vec2(vertTexCoord.x, 1.0 - vertTexCoord.y + dy)).a;\n";
    }
    shader+="float coef = displacementFactor;\n";
    shader+="vec3 calcNormal;\n";
    shader+="if (displacementAxis == 0.0) {\n";
    shader+="calcNormal = vec3((s1 - s3) * coef, -5.0, (s2 - s4) * coef);\n";
    shader+="} else if(displacementAxis == 1.0) {\n";
    shader+="calcNormal = vec3((s1 - s3) * coef, -5.0, (s2 - s4) * coef);\n";
    shader+="} else {\n";
    shader+="calcNormal = vec3((s1 - s3) * coef, -(s2 - s4) * coef, 5.0);\n";
    shader+="}\n";
    shader+="calcNormal = normalize(calcNormal);\n";
    shader+="fragNormal = (normalMatrix * vec4(calcNormal, 0.0)).xyz;\n";
  }else if(properties.NORMALMAP&&properties.NORMALSPACE=="OBJECT"){}
  else{
    shader+="fragNormal = (normalMatrix * vec4(vertNormal, 0.0)).xyz;\n";
  }
}
if(properties.TEXTURED||properties.CSSHADER){
  if(properties.CUBEMAP){shader+="fragViewDir = (viewMatrix[3].xyz);\n";}
  else if(properties.SPHEREMAPPING){shader+=" fragTexcoord = 0.5 + fragNormal.xy / 2.0;\n";}
  else if(properties.TEXTRAFO){shader+=" fragTexcoord = (texTrafoMatrix * vec4(vertTexCoord, 1.0, 1.0)).xy;\n";}
  else{
    shader+=" fragTexcoord = vertTexCoord;\n";
    if(properties.POPGEOMETRY&&x3dom.debug.usePrecisionLevelAsTexCoord===true)
      shader+="fragTexcoord = vec2(0.03125 + 0.9375 * (PG_precisionLevel / 16.0), 1.0);";
  }if(properties.NORMALMAP&&properties.NORMALSPACE=="TANGENT"&&!x3dom.caps.STD_DERIVATIVES){
    shader+="fragTangent  = (normalMatrix * vec4(tangent, 0.0)).xyz;\n";
    shader+="fragBinormal = (normalMatrix * vec4(binormal, 0.0)).xyz;\n";
  }
}
if(properties.LIGHTS||properties.FOG||properties.CLIPPLANES){
  shader+="fragPosition = (modelViewMatrix * vec4(vertPosition, 1.0));\n";
  if(properties.FOG){shader+="fragEyePosition = eyePosition - fragPosition.xyz;\n";}
}
if(properties.MULTIDIFFALPMAP){shader+="fragID = id;\n";}
if(properties.DISPLACEMENTMAP){
  shader+="vertPosition += normalize(vertNormal) * texture2D(displacementMap, vec2(fragTexcoord.x, 1.0-fragTexcoord.y)).r * displacementFactor;\n";
}else if(properties.DIFFPLACEMENTMAP){
  shader+="vertPosition += normalize(vertNormal) * texture2D(diffuseDisplacementMap, vec2(fragTexcoord.x, 1.0-fragTexcoord.y)).a * displacementFactor;\n";
}
shader+="gl_Position = modelViewProjectionMatrix * vec4(vertPosition, 1.0);\n";
if(properties.IS_PARTICLE){
  shader+="float spriteDist = (gl_Position.w > 0.000001) ? gl_Position.w : 0.000001;\n";
  shader+="float pointSize = floor(length(particleSize) * 256.0 / spriteDist + 0.5);\n";
  shader+="gl_PointSize = clamp(pointSize, 2.0, 256.0);\n";
}else{shader+="gl_PointSize = 2.0;\n";}
shader+="}\n";
var vertexShader=gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader,shader);
gl.compileShader(vertexShader);
if(!gl.getShaderParameter(vertexShader,gl.COMPILE_STATUS)){
  x3dom.debug.logInfo("VERTEX:\n"+shader);
  x3dom.debug.logError("VertexShader "+gl.getShaderInfoLog(vertexShader));
}
return vertexShader;};


//########SHADERCODE########/


x3dom.shader.DynamicShader.prototype.generateFragmentShader=function(gl,properties){
var shader="#ifdef GL_FRAGMENT_PRECISION_HIGH\n";
shader+=" precision highp float;\n";
shader+="#else\n";
shader+=" precision mediump float;\n";
shader+="#endif\n\n";
shader+="uniform mat4 modelMatrix;\n";
shader+="uniform mat4 modelViewMatrix;\n";
shader+="uniform mat4 viewMatrixInverse;\n";
shader+=x3dom.shader.material();
if(properties.TWOSIDEDMAT){shader+=x3dom.shader.twoSidedMaterial();}
if(properties.VERTEXCOLOR){
  if(properties.COLCOMPONENTS==3){shader+="varying vec3 fragColor;  \n";}
  else if(properties.COLCOMPONENTS==4){shader+="varying vec4 fragColor;  \n";}
}
if(properties.CUBEMAP||properties.CLIPPLANES){shader+="uniform mat4 modelViewMatrixInverse;\n";}
if(properties.TEXTURED||properties.CSSHADER){
  shader+="varying vec2 fragTexcoord;\n";
  if((properties.TEXTURED||properties.DIFFUSEMAP)&&!properties.CUBEMAP){shader+="uniform sampler2D diffuseMap;\n";}
  else if(properties.CUBEMAP){shader+="uniform samplerCube cubeMap;\n";shader+="varying vec3 fragViewDir;\n";}
  if(properties.SPECMAP){shader+="uniform sampler2D specularMap;\n";}
  if(properties.SHINMAP){shader+="uniform sampler2D shininessMap;\n";}
  if(properties.DISPLACEMENTMAP){
    shader+="uniform sampler2D displacementMap;\n";
    shader+="uniform float displacementWidth;\n";
    shader+="uniform float displacementHeight;\n";
  }
  if(properties.DIFFPLACEMENTMAP){
    shader+="uniform sampler2D diffuseDisplacementMap;\n";
    shader+="uniform float displacementWidth;\n";
    shader+="uniform float displacementHeight;\n";
  }
  if(properties.MULTIDIFFALPMAP||properties.MULTIVISMAP){shader+="varying float fragID;\n";}
  if(properties.MULTIDIFFALPMAP){
    shader+="uniform sampler2D multiDiffuseAlphaMap;\n";
    shader+="uniform float multiDiffuseAlphaWidth;\n";
    shader+="uniform float multiDiffuseAlphaHeight;\n";
  }
  if(properties.MULTIEMIAMBMAP){
    shader+="uniform sampler2D multiEmissiveAmbientMap;\n";
    shader+="uniform float multiEmissiveAmbientWidth;\n";
    shader+="uniform float multiEmissiveAmbientHeight;\n";
  }
  if(properties.MULTISPECSHINMAP){
    shader+="uniform sampler2D multiSpecularShininessMap;\n";
    shader+="uniform float multiSpecularShininessWidth;\n";
    shader+="uniform float multiSpecularShininessHeight;\n";
  }
  if(properties.MULTIVISMAP){
    shader+="uniform sampler2D multiVisibilityMap;\n";
    shader+="uniform float multiVisibilityWidth;\n";
    shader+="uniform float multiVisibilityHeight;\n";
  }
  if(properties.NORMALMAP){
    shader+="uniform sampler2D normalMap;\n";
    if(properties.NORMALSPACE=="TANGENT"){
      if(x3dom.caps.STD_DERIVATIVES){
        shader+="#extension GL_OES_standard_derivatives:enable\n";
        shader+=x3dom.shader.TBNCalculation();
      }else{
        shader+="varying vec3 fragTangent;\n";
        shader+="varying vec3 fragBinormal;\n";
      }
    }else if(properties.NORMALSPACE=="OBJECT"){shader+="uniform mat4 normalMatrix;\n";}
  }
}
if(properties.FOG){shader+=x3dom.shader.fog();}
if(properties.LIGHTS||properties.CLIPPLANES){shader+="varying vec4 fragPosition;\n";}
if(properties.LIGHTS){
  if(properties.NORMALMAP&&properties.NORMALSPACE=="OBJECT"){}
  else{shader+="varying vec3 fragNormal;\n";}
  shader+=x3dom.shader.light(properties.LIGHTS);
}
if(properties.CLIPPLANES){shader+=x3dom.shader.clipPlanes(properties.CLIPPLANES);}
shader+=x3dom.shader.gammaCorrectionDecl(properties);


shader+="void main(void) {\n";

if(properties.CLIPPLANES){shader+="vec3 cappingColor = calculateClipPlanes();\n";}
shader+="vec4 color;\n";
shader+="color.rgb = "+x3dom.shader.decodeGamma(properties,"diffuseColor")+";\n";
shader+="color.a = 1.0 - transparency;\n";
shader+="vec3 _emissiveColor     = emissiveColor;\n";
shader+="float _shininess        = shininess;\n";
shader+="vec3 _specularColor     = specularColor;\n";
shader+="float _ambientIntensity = ambientIntensity;\n";
if(properties.MULTIVISMAP||properties.MULTIDIFFALPMAP||properties.MULTISPECSHINMAP||properties.MULTIEMIAMBMAP){
  shader+="vec2 idCoord;\n";
  shader+="float roundedIDVisibility = floor(fragID+0.5);\n";
  shader+="float roundedIDMaterial = floor(fragID+0.5);\n";
  shader+="if(!gl_FrontFacing) {\n";
  shader+="    roundedIDMaterial = floor(fragID + (multiDiffuseAlphaWidth*multiDiffuseAlphaWidth) + 0.5);\n";
  shader+="}\n";
}
if(properties.MULTIVISMAP){
  shader+="idCoord.x = mod(roundedIDVisibility, multiVisibilityWidth) * (1.0 / multiVisibilityWidth) + (0.5 / multiVisibilityWidth);\n";
  shader+="idCoord.y = floor(roundedIDVisibility / multiVisibilityWidth) * (1.0 / multiVisibilityHeight) + (0.5 / multiVisibilityHeight);\n";
  shader+="vec4 visibility = texture2D( multiVisibilityMap, idCoord );\n";
  shader+="if (visibility.r < 1.0) discard; \n";
}
if(properties.MULTIDIFFALPMAP){
  shader+="idCoord.x = mod(roundedIDMaterial, multiDiffuseAlphaWidth) * (1.0 / multiDiffuseAlphaWidth) + (0.5 / multiDiffuseAlphaWidth);\n";
  shader+="idCoord.y = floor(roundedIDMaterial / multiDiffuseAlphaWidth) * (1.0 / multiDiffuseAlphaHeight) + (0.5 / multiDiffuseAlphaHeight);\n";
  shader+="vec4 diffAlpha = texture2D( multiDiffuseAlphaMap, idCoord );\n";
  shader+="color.rgb = "+x3dom.shader.decodeGamma(properties,"diffAlpha.rgb")+";\n";
  shader+="color.a = diffAlpha.a;\n";
}
if(properties.MULTIEMIAMBMAP){
  shader+="idCoord.x = mod(roundedIDMaterial, multiDiffuseAlphaWidth) * (1.0 / multiDiffuseAlphaWidth) + (0.5 / multiDiffuseAlphaWidth);\n";
  shader+="idCoord.y = floor(roundedIDMaterial / multiDiffuseAlphaWidth) * (1.0 / multiDiffuseAlphaHeight) + (0.5 / multiDiffuseAlphaHeight);\n";
  shader+="vec4 emiAmb = texture2D( multiEmissiveAmbientMap, idCoord );\n";
  shader+="_emissiveColor = emiAmb.rgb;\n";shader+="_ambientIntensity = emiAmb.a;\n";
}
if(properties.VERTEXCOLOR){
  if(properties.COLCOMPONENTS===3){
    shader+="color.rgb = "+x3dom.shader.decodeGamma(properties,"fragColor")+";\n";
  }else if(properties.COLCOMPONENTS===4){
    shader+="color = "+x3dom.shader.decodeGamma(properties,"fragColor")+";\n";
  }
}


// [ OriginalCode
/*
*/
// OriginalCode ]
// [ AddCode
  shader+="float backf = 0.0;\n";
// AddCode ]


if(properties.LIGHTS){
  shader+="vec3 ambient   = vec3(0.0, 0.0, 0.0);\n";
  shader+="vec3 diffuse   = vec3(0.0, 0.0, 0.0);\n";
  shader+="vec3 specular  = vec3(0.0, 0.0, 0.0);\n";
  shader+="vec3 eye    = -fragPosition.xyz;\n";
  if(properties.NORMALMAP&&properties.NORMALSPACE=="OBJECT"){shader+="vec3 normal  = vec3(0.0, 0.0, 0.0);\n";}
  else{shader+="vec3 normal    = normalize(fragNormal);\n";}
  if(properties.NORMALMAP){
    if(properties.NORMALSPACE=="TANGENT"){
      shader+="vec3 n = normal;\n";
      if(x3dom.caps.STD_DERIVATIVES){
        shader+="normal = perturb_normal( n, fragPosition.xyz, vec2(fragTexcoord.x, 1.0-fragTexcoord.y) );\n";
      }else{
        shader+="vec3 t = normalize( fragTangent );\n";
        shader+="vec3 b = normalize( fragBinormal );\n";
        shader+="mat3 tangentToWorld = mat3(t, b, n);\n";
        shader+="normal = texture2D( normalMap, vec2(fragTexcoord.x, 1.0-fragTexcoord.y) ).rgb;\n";
        shader+="normal = 2.0 * normal - 1.0;\n";
        shader+="normal = normalize( normal * tangentToWorld );\n";
        shader+="normal.y = -normal.y;\n";shader+="normal.x = -normal.x;\n";
      }
    }else if(properties.NORMALSPACE=="OBJECT"){
      shader+="normal = texture2D( normalMap, vec2(fragTexcoord.x, 1.0-fragTexcoord.y) ).rgb;\n";
      shader+="normal = 2.0 * normal - 1.0;\n";
      shader+="normal = (normalMatrix * vec4(normal, 0.0)).xyz;\n";
      shader+="normal = normalize(normal);\n";
    }
  }if(properties.SHINMAP){shader+="_shininess = texture2D( shininessMap, vec2(fragTexcoord.x, 1.0-fragTexcoord.y) ).r;\n";}
  if(properties.SPECMAP){shader+="_specularColor = "+x3dom.shader.decodeGamma(properties,"texture2D(specularMap, vec2(fragTexcoord.x, 1.0-fragTexcoord.y)).rgb")+";\n";}
  if(properties.MULTISPECSHINMAP){
    shader+="idCoord.x = mod(roundedIDMaterial, multiSpecularShininessWidth) * (1.0 / multiSpecularShininessWidth) + (0.5 / multiSpecularShininessWidth);\n";
    shader+="idCoord.y = floor(roundedIDMaterial / multiSpecularShininessWidth) * (1.0 / multiSpecularShininessHeight) + (0.5 / multiSpecularShininessHeight);\n";
    shader+="vec4 specShin = texture2D( multiSpecularShininessMap, idCoord );\n";
    shader+="_specularColor = specShin.rgb;\n";shader+="_shininess = specShin.a;\n";
  }if(!properties.SOLID||properties.TWOSIDEDMAT){
    shader+="if (dot(normal, eye) < 0.0) {\n";
    shader+="  normal *= -1.0;\n";


// [ OriginalCode
/*
*/
// OriginalCode ]
// [ AddCode
    shader+="backf = 1.0;\n";
// AddCode ]


    shader+="}\n";
  }if(properties.SEPARATEBACKMAT){
    shader+="  if(!gl_FrontFacing) {\n";
    shader+="    color.rgb = "+x3dom.shader.decodeGamma(properties,"backDiffuseColor")+";\n";
    shader+="    color.a = 1.0 - backTransparency;\n";
    shader+="    _shininess = backShininess;\n";
    shader+="    _emissiveColor = backEmissiveColor;\n";
    shader+="    _specularColor = backSpecularColor;\n";
    shader+="    _ambientIntensity = backAmbientIntensity;\n";shader+="  }\n";
  }if(properties.LIGHTS){
    shader+="vec3 ads;\n";
    for(var l=0;l<properties.LIGHTS;l++){
      var lightCol="light"+l+"_Color";



// [ OriginalCode
/*
      shader+="ads = lighting(light"+l+"_Type, "+"light"+l+"_Location, "+"light"+l+"_Direction, "+lightCol+", "+"light"+l+"_Attenuation, "+
        "light"+l+"_Radius, "+"light"+l+"_Intensity, "+"light"+l+"_AmbientIntensity, "+"light"+l+"_BeamWidth, "+"light"+l+"_CutOffAngle, "+
        "normal, eye, _shininess, _ambientIntensity);\n";
      shader+="   ambient  += "+lightCol+" * ads.r;\n"+
        "   diffuse  += "+lightCol+" * ads.g;\n"+"   specular += "+lightCol+" * ads.b;\n";
*/
// OriginalCode ]
// [ AddCode
      shader+="if(backf != 1.0) {\n";
      shader+="ads = lighting(light"+l+"_Type, "+"light"+l+"_Location, "+"light"+l+"_Direction, "+lightCol+", "+"light"+l+"_Attenuation, "+
        "light"+l+"_Radius, "+"light"+l+"_Intensity, "+"light"+l+"_AmbientIntensity, "+"light"+l+"_BeamWidth, "+"light"+l+"_CutOffAngle, "+
        "normal, eye, _shininess, _ambientIntensity);\n";
      shader+="   ambient  += "+lightCol+" * ads.r;\n"+
        "   diffuse  += "+lightCol+" * ads.g;\n"+"   specular += "+lightCol+" * ads.b;\n";
      shader+="}else{\n";
      shader+="   ambient  += vec3(0.0);\n"+
        "   diffuse  +=  vec3(0.0);\n"+"   specular +=  vec3(0.0);\n";
      shader+="}\n";
// AddCode ]



    }
    shader+="ambient = max(ambient, 0.0);\n";
    shader+="diffuse = max(diffuse, 0.0);\n";
    shader+="specular = max(specular, 0.0);\n";
  }

  if(properties.TEXTURED||properties.DIFFUSEMAP||properties.DIFFPLACEMENTMAP){
    if(properties.CUBEMAP){
      shader+="vec3 viewDir = normalize(fragViewDir);\n";
      shader+="vec3 reflected = reflect(viewDir, normal);\n";
      shader+="reflected = (modelViewMatrixInverse * vec4(reflected,0.0)).xyz;\n";
      shader+="vec4 texColor = "+x3dom.shader.decodeGamma(properties,"textureCube(cubeMap, reflected)")+";\n";
      shader+="color.a *= texColor.a;\n";
    }else if(properties.DIFFPLACEMENTMAP){
      shader+="vec2 texCoord = vec2(fragTexcoord.x, 1.0-fragTexcoord.y);\n";
      shader+="vec4 texColor = texture2D(diffuseDisplacementMap, texCoord);\n";
    }else{
      if(properties.PIXELTEX){shader+="vec2 texCoord = fragTexcoord;\n";}
      else{shader+="vec2 texCoord = vec2(fragTexcoord.x, 1.0-fragTexcoord.y);\n";}
      shader+="vec4 texColor = "+x3dom.shader.decodeGamma(properties,"texture2D(diffuseMap, texCoord)")+";\n";



// [ OriginalCode
/*
      shader+="color.a *= texColor.a;\n";
*/
// OriginalCode ]
// [ AddCode
      //shader+="color.a = 0.0;\n";
      shader+="color.a *= texColor.a;\n";
      //shader+="if(texColor.a != 1.0) color.a = 0.9;\n";
// AddCode ]



    }if(properties.BLENDING){
      shader+="color.rgb = (_emissiveColor + max(ambient + diffuse, 0.0) * color.rgb + specular*_specularColor);\n";
      if(properties.CUBEMAP){shader+="color.rgb = mix(color.rgb, texColor.rgb, vec3(0.75));\n";}
      else{shader+="color.rgb *= texColor.rgb;\n";}
    }else{
      shader+="color.rgb = (_emissiveColor + max(ambient + diffuse, 0.0) * texColor.rgb + specular*_specularColor);\n";
    }
  }else{
    shader+="color.rgb = (_emissiveColor + max(ambient + diffuse, 0.0) * color.rgb + specular*_specularColor);\n";
  }


// [ OriginalCode
/*
*/
// OriginalCode ]
// [ AddCode
  if(properties.NORMALMAP){

    //法線の影響を強くする
    shader+="if(backf != 1.0) {\n";
    shader+="   float p = max(0.1, dot(normalize(normal), normalize(-light0_Direction)));\n";
    shader+="   color.rgb *= p;\n";
    shader+="   color.rgb += max(0.0, pow(p, 128.0)) * vec3(0.8);\n";
    shader+="}\n";
    shader+="   if(backf == 1.0) color.a *= 1.0 - 0.75;\n";   //backface alpha
    shader+="   color *= vec4(1.0, 1.0, 1.0, 1.0 - 0.4);\n"; //multiply color
    //shader+="   gl_FragColor = color;\n";

  }
// AddCode ]



}else{
  if(properties.APPMAT&&!properties.VERTEXCOLOR){shader+="color = vec4(0.0, 0.0, 0.0, 1.0 - transparency);\n";}
  if(properties.TEXTURED||properties.DIFFUSEMAP){
    if(properties.PIXELTEX){shader+="vec2 texCoord = fragTexcoord;\n";}
    else{shader+="vec2 texCoord = vec2(fragTexcoord.x, 1.0-fragTexcoord.y);\n";}
    if(properties.IS_PARTICLE){shader+="texCoord = clamp(gl_PointCoord, 0.01, 0.99);\n";}
    shader+="vec4 texColor = "+x3dom.shader.decodeGamma(properties,"texture2D(diffuseMap, texCoord)")+";\n";
    shader+="color.a = texColor.a;\n";
    if(properties.BLENDING||properties.IS_PARTICLE){
      shader+="color.rgb += _emissiveColor.rgb;\n";
      shader+="color.rgb *= texColor.rgb;\n";
    }else{shader+="color = texColor;\n";}
  }else if(!properties.VERTEXCOLOR&&!properties.POINTLINE2D){shader+="color.rgb += _emissiveColor;\n";}
  else if(!properties.VERTEXCOLOR&&properties.POINTLINE2D){
    shader+="color.rgb = _emissiveColor;\n";
    if(properties.IS_PARTICLE){
      shader+="float pAlpha = 1.0 - clamp(length((gl_PointCoord - 0.5) * 2.0), 0.0, 1.0);\n";
      shader+="color.rgb *= vec3(pAlpha);\n";shader+="color.a = pAlpha;\n";
    }
  }else if(properties.IS_PARTICLE){
    shader+="float pAlpha = 1.0 - clamp(length((gl_PointCoord - 0.5) * 2.0), 0.0, 1.0);\n";
    shader+="color.rgb *= vec3(pAlpha);\n";shader+="color.a = pAlpha;\n";
  }
}
if(properties.CLIPPLANES){
  shader+="if (cappingColor.r != -1.0) {\n";
  shader+="    color.rgb = cappingColor;\n";shader+="}\n";
}if(properties.TEXT){shader+="if (color.a <= 0.5) discard;\n";
}else{shader+="if (color.a <= "+properties.ALPHATHRESHOLD+") discard;\n";}
shader+="color = clamp(color, 0.0, 1.0);\n";
shader+="color = "+x3dom.shader.encodeGamma(properties,"color")+";\n";
if(properties.FOG){
  shader+="float f0 = calcFog(fragEyePosition);\n";
  shader+="color.rgb = fogColor * (1.0-f0) + f0 * (color.rgb);\n";
}
shader+="gl_FragColor = color;\n";
shader+="}\n";
var fragmentShader=gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader,shader);
gl.compileShader(fragmentShader);
if(!gl.getShaderParameter(fragmentShader,gl.COMPILE_STATUS)){
  x3dom.debug.logInfo("FRAGMENT:\n"+shader);x3dom.debug.logError("FragmentShader "+gl.getShaderInfoLog(fragmentShader));
}

return fragmentShader;};




var TMan = new N6LTimerMan();  //timer manager//タイマーマネージャー
var x3domRuntime;
var basetime = 0.0;
var time = 0.0;
var span = 3000.0;

//エントリーポイント
function enter(){
  basetime = new Date().getTime();
  TMan.add();
  TMan.timer[0].setalerm(function() { GLoop(0); }, 25);  //set main loop//メインループセット
}

//メインループ
function GLoop(id) {
  if(!x3domRuntime) {
    x3domRuntime = document.getElementById('x3drn').runtime;
    TMan.timer[id].setalerm(function() { GLoop(id); }, 25);  //set main loop//メインループセット
    if(!x3domRuntime) return;
  }

  //地球回転
  var elm = document.getElementById('earthT');
  var t = ((new Date().getTime() - basetime) % span) / span;
  var mat = new N6LMatrix(4).UnitMat().RotAxis(new N6LVector([1.0, 0.0, 1.0, 0.0], true), t * Math.PI * 2.0);
  elm.setAttribute('rotation', mat.Vector().ToX3DOM().toString());

  //時計
  var dt = new Date()
  var year = dt.getFullYear();
  var month = dt.getMonth()+1;
  var day = dt.getDate();
  var hour = dt.getHours();
  var minute = dt.getMinutes();
  var second = dt.getSeconds();
  var msecond = dt.getMilliseconds();
  elm = document.getElementById('divT');
  elm.innerHTML = zero_padding(year, 4) + '/' + zero_padding(month, 2) + '/' + zero_padding(day, 2) + ' ' +
    zero_padding(hour, 2) + ':' + zero_padding(minute, 2) + ':' + zero_padding(second, 2) + ':' + zero_padding(msecond, 3);


  TMan.timer[id].setalerm(function() { GLoop(id); }, 25);  //set main loop//メインループセット
}

function zero_padding(number, digit){
    var str = '';
    for(var i=0; i<digit; i++){
        str += '0';
    }
    str += number;
    return str.slice(digit*-1);
}


//]]>
</script>

...省略...



x3dom.shader.DynamicShader.prototype.generateVertexShader
x3dom.shader.DynamicShader.prototype.generateFragmentShader
のオーバーロードのほとんどはx3domのソースのコピペで
// [ AddCode
// AddCode ]
に囲まれた箇所だけ変更した。だから、その箇所を
// [ OriginalCode
/*
*/
// OriginalCode ]
に囲まれた箇所に戻したものから、自分の作りたいようにカスタマイズしていけば、おけ。
モバイルでちゃんと表示するには、x3dom.shader.DynamicMobileShaderを解析してください。
後のコードはいたって普通です。
角度とアルファ値によっては、縞模様が出るけど、それは前面と背面の透明度付きの描画の順番によるもので
<depthmode>で、軽減したけどまだ残っていて、全部なくすのは大変かも。







3Dプログラミング講座
NAS6LIB
ポリゴンテスト解説・x3dom使い方
その1:ベクトル
その2:行列
その3:クォータニオン
その4:基本総復習・実践
その5:応用その1・メッシュアニメーション、動的テクスチャ
その6:応用その2・GLSL、カスタムシェーダー、キーボード、ファイル
その7:応用その3・ゲームプログラミング、タグの動的追加
その8:応用その4・GLSL、シェーダー、その2

<<prev ゲームプログラミング、タグの動的追加 : 工事中 next>>





戻る