Simple Lava Shader for mobile.

모바일용으로 아주 간단한 공식을 이용해서 만든 용암쉐이더 입니다.
퍼린 노이즈도 적용 하는 중입니다.
일단 개별적으로 테스트 했고 이제 합쳐야 겠네요.
퍼포먼스에 따라 펄린노이즈가 들어 갈지 아닐지 체크 할 수 있는 우버쉐이더 구성으로 디파인 해서 제작해야겠네요.

Simple Lava Shader for mobile.
It made for our mobile game project that is very simple vertex shader and pixel shader use.
Then It also this shader is unlit type shader and not light map support but lava is very dark and very bright each area and I thing lava ground those not have receiving casted shadow from another object.
It is very simple... And I will be additional Ashima noise function for improve vertex wave.




Simple LAVA mobile shader code below.
string description = "LAVA_Shader.cgfx :: PLAYNERY";

float3 mainColor : Diffuse
<
 string UIName = "Main Color";
> = {1.0f, 1.0f, 1.0f}; // It will be change to application uniform variable value

texture lavaTexture
<
 string name = "default_color.dds";
 string UIName = "lava map";
 string TextureType = "2D";
>;

sampler2D lavaMap = sampler_state
{

texture = ;
AddressU = Wrap;
AddressV = Wrap;

};

texture lavaEmissiveMaskTexture
<
 string name ="default_color.dds";
 string UIName = "lava Emissive MaskMap";
 string TextureType = "2D";
>;

sampler2D lavaEmissiveMaskMap = sampler_state
{

texture = ;
AddressU = Wrap;
AddressV = Wrap;
};

float addMixVal
<
 string UIName = "Mix value";
 string UIWidget = "Slider";
 float UIMin = 1.0f;
 float UIMax = 2.0f;
> = 1.0f;

float offsetX
<
 string UIName = "offset X";
 string UIWidget = "Slider";
 float UIMin = 0.0f;
 float UIMax = 10.0f;
> = 1.0f;

float offsetY
<
 string UIName = "offset Y";
 string UIWidget = "Slider";
 float UIMin = 0.0f;
 float UIMax = 1.0f;
> = 1.0f;



float2 offsetVectorXY // 값에 따라 흐르는 속도가 변경 됩니다.
<
 string UIName = "offset Vector XY ";
> = {0.0f , 0.0f};

float SineSpeed //라바 물결을 사인함수로 한쪽으로 흐르는 거 아닌 위아래로 일렁거리게 함.
<
 string UIName = "Sine Speed";
 string UIWidget = "Slider";
 float UIMin = 0.0f;
 float UIMax = 1.0f;
> = 0.169f;

/////////////////////////////////////////////
//sinVert var
float3 deformSinVert
<
 string UIName = "deform Sin Vert";
> = {0.0f, 0.0f , 0.0f};

float WaveSinSpeed
<
 string UIName = "WaveSine Speed";
 string UIWidget = "Slider";
 float UIMin = 0.0f;
 float UIMax = 2.0f;
> = 1.0f;



float LavaSinWaveFactor 
<
 string UIWidget = "slider";
 string UIName = "Lava Wave Seed";
 float UIMin = 0.1f;
 float UIMax = 10.0f;
 float UIStep = 0.01f;
 
> = 1.0f;



struct a2v {
float4 position  : POSITION; // In this simple shader, all we really need passed is the position
float2 texCoord  : TEXCOORD0;

};

struct v2f {
float4 position  : POSITION;
float2 texCoord  : TEXCOORD0;

};


//Matrix
float4x4 WorldViewProjection     : WorldViewProjection;

//uniform variables
float time : Time;

// Vertex Shader 
v2f vShader(a2v In)
{
v2f Out;

//vert deform
float4 deformamtionVertPos = In.position;
float4 deformationVertPosVertical = In.position;



//세로축의 웨이브 펙터.
deformamtionVertPos.xyz = deformamtionVertPos.xyz + (sin(time * WaveSinSpeed + In.position.z * LavaSinWaveFactor )) * deformSinVert ;

//가로축의 웨이브 펙터.
deformationVertPosVertical.xyz = deformationVertPosVertical.xyz + (sin(time * WaveSinSpeed + In.position.x * LavaSinWaveFactor )) * deformSinVert ;

float4 mixed_deformationVertPos = (deformamtionVertPos + deformationVertPosVertical); //두개의 웨이브 팩터를 더합니다.

Out.position = mul(WorldViewProjection, mixed_deformationVertPos);

Out.texCoord = In.texCoord;

return Out;
}


// Pixel Shader 
float4 pShader(v2f In) : COLOR
{

float4 outColor; 
float4 addColor;
float4 colorMap;
float variationMixedColor;
float4 emmiveMaskMap;
float4 uvScaleTranslate;


///////////////////////////////////////////////////////////////////////////////
//유비 타일링 입력 파라메터를 위젯 인터페이스에서 받아 오도록 임시로...
uvScaleTranslate.x = offsetX;
uvScaleTranslate.y = offsetY; 
///////////////////////////////////////////////////////////////////////////////


float2 uv = (In.texCoord - 0.5f) * uvScaleTranslate.xy + uvScaleTranslate.zw + (time * SineSpeed * offsetVectorXY )  + 0.5f;

//컬러 믹스 관련.
colorMap = tex2D(lavaMap , uv);
emmiveMaskMap = tex2D(lavaEmissiveMaskMap , uv);
addColor = float4(mainColor,1);


//용암 밝기에 대한 혼합변수에 사인파형을 사용하고 다시 코사인으로 묶어서 1 아래 값을 절삭.
variationMixedColor = variationMixedColor + (cos(sin((time/4.0f) *  addMixVal)));

outColor.rgb = ( colorMap.rgb * addColor.rgb ) * (emmiveMaskMap.rgb + variationMixedColor);
outColor.a = 1.0f;

return outColor;
}


// Techniques
technique Opaque
{
pass one
{
VertexShader = compile vp30 vShader();
PixelShader = compile fp30 pShader();
}
}



Test Perlin Noise Code below.

#define LIGHT_COORDS "World"
#define BSIZE 32
#define FULLSIZE 66
#define NOISEFRAC 0.03125

//Below line block is noise pre calculated table.
//-Noise table start.
const float4 NTab[FULLSIZE]  = {
{-0.569811,0.432591,-0.698699,0},
{0.78118,0.163006,0.60265,1},
{0.436394,-0.297978,0.848982,2},
{0.843762,-0.185742,-0.503554,3},
{0.663712,-0.68443,-0.301731,4},
{0.616757,0.768825,0.168875,5},
{0.457153,-0.884439,-0.093694,6},
{-0.956955,0.110962,-0.268189,7},
{0.115821,0.77523,0.620971,8},
{-0.716028,-0.477247,-0.50945,9},
{0.819593,-0.123834,0.559404,10},
{-0.522782,-0.586534,0.618609,11},
{-0.792328,-0.577495,-0.196765,12},
{-0.674422,0.0572986,0.736119,13},
{-0.224769,-0.764775,-0.60382,14},
{0.492662,-0.71614,0.494396,15},
{0.470993,-0.645816,0.600905,16},
{-0.19049,0.321113,0.927685,17},
{0.0122118,0.946426,-0.32269,18},
{0.577419,0.408182,0.707089,19},
{-0.0945428,0.341843,-0.934989,20},
{0.788332,-0.60845,-0.0912217,21},
{-0.346889,0.894997,-0.280445,22},
{-0.165907,-0.649857,0.741728,23},
{0.791885,0.124138,0.597919,24},
{-0.625952,0.73148,0.270409,25},
{-0.556306,0.580363,0.594729,26},
{0.673523,0.719805,0.168069,27},
{-0.420334,0.894265,0.153656,28},
{-0.141622,-0.279389,0.949676,29},
{-0.803343,0.458278,0.380291,30},
{0.49355,-0.402088,0.77119,31},
{-0.569811,0.432591,-0.698699,0},
{0.78118,0.163006,0.60265,1},
{0.436394,-0.297978,0.848982,2},
{0.843762,-0.185742,-0.503554,3},
{0.663712,-0.68443,-0.301731,4},
{0.616757,0.768825,0.168875,5},
{0.457153,-0.884439,-0.093694,6},
{-0.956955,0.110962,-0.268189,7},
{0.115821,0.77523,0.620971,8},
{-0.716028,-0.477247,-0.50945,9},
{0.819593,-0.123834,0.559404,10},
{-0.522782,-0.586534,0.618609,11},
{-0.792328,-0.577495,-0.196765,12},
{-0.674422,0.0572986,0.736119,13},
{-0.224769,-0.764775,-0.60382,14},
{0.492662,-0.71614,0.494396,15},
{0.470993,-0.645816,0.600905,16},
{-0.19049,0.321113,0.927685,17},
{0.0122118,0.946426,-0.32269,18},
{0.577419,0.408182,0.707089,19},
{-0.0945428,0.341843,-0.934989,20},
{0.788332,-0.60845,-0.0912217,21},
{-0.346889,0.894997,-0.280445,22},
{-0.165907,-0.649857,0.741728,23},
{0.791885,0.124138,0.597919,24},
{-0.625952,0.73148,0.270409,25},
{-0.556306,0.580363,0.594729,26},
{0.673523,0.719805,0.168069,27},
{-0.420334,0.894265,0.153656,28},
{-0.141622,-0.279389,0.949676,29},
{-0.803343,0.458278,0.380291,30},
{0.49355,-0.402088,0.77119,31},
{-0.569811,0.432591,-0.698699,0},
{0.78118,0.163006,0.60265,1}};
//-Noise table end.


//////////////////////////////////////////////////////////////
// UNTWEAKABLES //////////////////////////////////////////////
//////////////////////////////////////////////////////////////

float gTimer : TIME < string UIWidget = "None"; >;
float4x4 gWvpXf : WORLDVIEWPROJECTION ;

//////////////////////////////////////////////////////////////
// TWEAKABLES ////////////////////////////////////////////////
//////////////////////////////////////////////////////////////

float gDisplacement <
    string UIWidget = "slider";
    float UIMin = 0.0;
    float UIMax = 2.0;
    float UIStep = 0.01;
> = 1.6f;

float gSharpness <
    string UIWidget = "slider";
    float UIMin = 0.1;
    float UIMax = 5.0;
    float UIStep = 0.1;
> = 1.90f;



float gSpeed <
    string UIWidget = "slider";
    float UIMin = 0.01;
    float UIMax = 1.0;
    float UIStep = 0.001;
    string UIName = "Speed";
> = 0.3f;

float gTurbDensity <
    string UIWidget = "slider";
    string UIName = "Turbulence Density";
    float UIMin = 0.01;
    float UIMax = 8.0;
    float UIStep = 0.001;
> = 2.27f;

float gColorRange <
    string UIWidget = "slider";
    string UIName = "Color Range";
    float UIMin = 0.0;
    float UIMax = 6.0;
    float UIStep = 0.01;
> = 1.0f;

float4x4 gNoiseXf <
    string UIName = "Coordinate System for Noise";
> = {{1,0,0,0}, {0,1,0,0}, {0,0,1,0}, {0,0,0,1}};

//float4 dd[5] = {
// 0,2,3,1, 2,2,2,2, 3,3,3,3, 4,4,4,4, 5,5,5,5 };

//////////////////////////// texture ///////////////////////

texture gGradeTex <
    
    string ResourceName = "default_color.dds";
    string ResourceType = "2D";
    string UIName = "Fire Gradient";
>;

sampler2D gGradeSampler = sampler_state
{
Texture = ;
AddressU = Wrap;
AddressV = Wrap;

};

///////////// functions 

// this is the smoothstep function f(t) = 3t^2 - 2t^3, without the normalization
float3 s_curve(float3 t) { return t*t*( float3(3,3,3) - float3(2,2,2)*t); }
float2 s_curve(float2 t) { return t*t*( float2(3,3) - float2(2,2)*t); }
float  s_curve(float  t) { return t*t*(3.0-2.0*t); }

// 3D version
float noise(float3 v, const uniform float4 pg[FULLSIZE])
{
v = v + (10000.0f).xxx;   // hack to avoid negative numbers

float3 i = frac(v * NOISEFRAC) * BSIZE;   // index between 0 and BSIZE-1
float3 f = frac(v);            // fractional position

// lookup in permutation table
float2 p;
p.x = pg[ i[0]     ].w;
p.y = pg[ i[0] + 1 ].w;
p = p + i[1];

float4 b;
b.x = pg[ p[0] ].w;
b.y = pg[ p[1] ].w;
b.z = pg[ p[0] + 1 ].w;
b.w = pg[ p[1] + 1 ].w;
b = b + i[2];

// compute dot products between gradients and vectors
float4 r;
r[0] = dot( pg[ b[0] ].xyz, f );
r[1] = dot( pg[ b[1] ].xyz, f - float3(1.0f, 0.0f, 0.0f) );
r[2] = dot( pg[ b[2] ].xyz, f - float3(0.0f, 1.0f, 0.0f) );
r[3] = dot( pg[ b[3] ].xyz, f - float3(1.0f, 1.0f, 0.0f) );

float4 r1;
r1[0] = dot( pg[ b[0] + 1 ].xyz, f - float3(0.0f, 0.0f, 1.0f) );
r1[1] = dot( pg[ b[1] + 1 ].xyz, f - float3(1.0f, 0.0f, 1.0f) );
r1[2] = dot( pg[ b[2] + 1 ].xyz, f - float3(0.0f, 1.0f, 1.0f) );
r1[3] = dot( pg[ b[3] + 1 ].xyz, f - float3(1.0f, 1.0f, 1.0f) );

// interpolate
f = s_curve(f);
r = lerp( r, r1, f[2] );
r = lerp( r.xyyy, r.zwww, f[1] );
return lerp( r.x, r.y, f[0] );
}

// 2D version
float noise(float2 v, const uniform float4 pg[FULLSIZE])
{
v = v + (10000.0f).xx;

float2 i = frac(v * NOISEFRAC) * BSIZE;   // index between 0 and BSIZE-1
float2 f = frac(v);            // fractional position

// lookup in permutation table
float2 p;
p[0] = pg[ i[0]   ].w;
p[1] = pg[ i[0]+1 ].w;
p = p + i[1];

// compute dot products between gradients and vectors
float4 r;
r[0] = dot( pg[ p[0] ].xy,   f);
r[1] = dot( pg[ p[1] ].xy,   f - float2(1.0f, 0.0f) );
r[2] = dot( pg[ p[0]+1 ].xy, f - float2(0.0f, 1.0f) );
r[3] = dot( pg[ p[1]+1 ].xy, f - float2(1.0f, 1.0f) );

// interpolate
f = s_curve(f);
r = lerp( r.xyyy, r.zwww, f[1] );
return lerp( r.x, r.y, f[0] );
}

// 1D version
float noise(float v, const uniform float4 pg[FULLSIZE])
{
v = v + 10000.0f;

float i = frac(v * NOISEFRAC) * BSIZE;   // index between 0 and BSIZE-1
float f = frac(v);            // fractional position

// compute dot products between gradients and vectors
float2 r;
r[0] = pg[i].x * f;
r[1] = pg[i + 1].x * (f - 1.0f);

// interpolate
f = s_curve(f);
return lerp( r[0], r[1], f);
}

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

struct appData 
{
float4 Position     : POSITION;
float4 Normal       : NORMAL;
float2 texCoord    : TEXCOORD0;

};

// define outputs from vertex shader
struct vbombVertexData
{
float4 HPosition : POSITION;
float2 texCoord  : TEXCOORD0;
};

////////

vbombVertexData mainVS(appData IN,
uniform float4x4 WvpXf,
uniform float Timer,
uniform float Speed,
uniform float Displacement,
uniform float Sharpness,

uniform float TurbDensity,
uniform float ColorRange,
uniform float4x4 NoiseXf
) {
vbombVertexData OUT;
OUT.texCoord = IN.texCoord;
float4 noisePos = TurbDensity*mul(NoiseXf,IN.Position+(Speed*Timer));
float i = (noise(noisePos.xyz, NTab) + 1.0f) * 0.5f;
float cr = 1.0-(0.5+ColorRange*(i-0.5));
// displacement along normal
float ni = pow(abs(i),Sharpness);
i -=  0.5;
//i = sign(i) * pow(i,Sharpness);
// we will use our own "normal" vector because the default geom is a sphere
float4 Nn = float4(normalize(IN.Position).xyz,0);
float4 NewPos = IN.Position - (Nn * (ni-0.5) * Displacement);
//position.w = 1.0f;
OUT.HPosition = mul(WvpXf,NewPos);


return OUT;
}

float4 hotPS(vbombVertexData IN) : COLOR 
{

float4 outColor;
float4 ColorMap;
float2 uv = IN.texCoord;
ColorMap = tex2D(gGradeSampler, uv);
outColor.rgb = ColorMap.rgb;
outColor.a = 1.0f;

return outColor;
}


///////////////////////////////////////
/// TECHNIQUES ////////////////////////
///////////////////////////////////////

technique Main <
 string Script = "Pass=p0;";
> {
pass p0 <
 string Script = "Draw=geometry;";
    > {
VertexProgram = compile vp30 mainVS(gWvpXf,
gTimer,gSpeed,
gDisplacement,
gSharpness,
gTurbDensity,
gColorRange,
gNoiseXf);
DepthTestEnable = true;
DepthMask = true;
CullFaceEnable = false;
BlendEnable = false;
DepthFunc = LEqual;

FragmentProgram = compile fp30 hotPS(  );
}
}

///////////////////////////////////////////////////////////////// eof //


Game Developer Leegoon copyright all right reserved since 2010.

old,












Game Developer Leegoon copyright all right reserved since 2010.

Comments