实现制作片状法线贴图纹理

时间:2017-09-26 13:13:48

标签: opengl glsl shader

我正在尝试像这样制作片状法线贴图纹理。

剥落法线贴图纹理flake normal map texture

我找到了page

在页面中,有一个OSL代码,我试图用GLSL实现。 但是,我不能这样做。

我不知道如何使用GLSL实现cellnoise

以下是OSL代码。

shader
flakes
(
        float flake_scale = 10.0,
        float flake_size = 0.5,
        float flake_size_variance = 0.0,
        float flake_normal_orientation = 0.0,
        output color result = 1.0,
        output float alpha  = 1.0
)
{
    float safe_flake_size_variance = clamp(flake_size_variance, 0.1, 1.0);
    vector cellCenters[9] = {
            vector( 0.5,  0.5,  0.0),
            vector( 1.5,  0.5,  0.0),
            vector( 1.5,  1.5,  0.0),
            vector( 0.5,  1.5,  0.0),
            vector(-0.5,  1.5,  0.0),
            vector(-0.5,  0.5,  0.0),
            vector(-0.5, -0.5,  0.0),
            vector( 0.5, -0.5,  0.0),
            vector( 1.5, -0.5,  0.0)
    };
    point position = vector(u, v, 0.0);
    position = flake_scale * position;
    point base = floor(position);
    point nearestCell = point(0.0, 0.0, 1.0);
    int nearestCellIndex = -1;
    for(int cellIndex = 0; cellIndex < 9; ++cellIndex)   {
            point cellCenter = base + cellCenters[cellIndex];

            vector centerOffset = cellnoise(cellCenter) * 2.0 - 1.0;
            centerOffset[2] *= safe_flake_size_variance;
            centerOffset = normalize(centerOffset);

            cellCenter += 0.5 * centerOffset;
            float cellDistance = distance(position, cellCenter);
            if(cellDistance < flake_size && cellCenter[2] < nearestCell[2]) {
                    nearestCell = cellCenter;
                    nearestCellIndex = cellIndex;
            }
    }

    result = color(0.5, 0.5, 1.0);
    alpha = 0.0;

    if (nearestCellIndex != -1) {
            vector randomNormal = cellnoise(base + cellCenters[nearestCellIndex] + vector(0.0, 0.0, 1.5));
            randomNormal = 2.0 * randomNormal - 1.0;
            randomNormal = faceforward(randomNormal, I, randomNormal);
            randomNormal = normalize(mix(randomNormal, vector(0.0, 0.0, 1.0), flake_normal_orientation));

            result = color(0.5*randomNormal[0]+0.5, 0.5*randomNormal[1]+0.5, randomNormal[2]);
            alpha = 1.0;
    }
}

有没有人知道如何创建片状法线贴图。

1 个答案:

答案 0 :(得分:1)

根据你的问题:

  

我不知道如何使用GLSL实现cellnoise

一种可能性是Voronoi diagram(另见glslsandbox)。从Voronoi算法计算的颜色必须转换为法向量(标准化)。 Z坐标必须为正。最后,法向量必须在纹理的RGB通道中编码(nv * 0.5 + 0.5):

in vec2 ndcPos;  // normaliced device coordinates in range [-1.0, 1.0]
uniform float u_time;

vec2 hash( vec2 p ) { 
p=vec2(dot(p,vec2(127.1,311.7)),dot(p,vec2(269.5,183.3))); 
return fract(sin(p)*18.5453); }

// return distance, and cell id
vec2 voronoi( in vec2 x )
{
    vec2 n = floor( x );
    vec2 f = fract( x );
    vec3 m = vec3( 8.0 );
    for( int j=-1; j<=1; j++ )
    {
        for( int i=-1; i<=1; i++ )
        {
            vec2  g = vec2( float(i), float(j) );
            vec2  o = hash( n + g );
            vec2  r = g - f + (0.5+0.5*sin(u_time+6.2831*o));
            float d = dot( r, r );
            if( d<m.x ) m = vec3( d, o );
        }
    }
    return vec2( sqrt(m.x), m.y+m.z );
}

void main()
{
    vec2 p = ndcPos * 2.0;
    vec2 c = voronoi( (14.0+6.0*sin(0.2*u_time))*p );
    float x = 0.5 + 0.5 * cos( c.y*6.2831 );
    float y = 0.5 + 0.5 * sin( c.y*6.2831 );

    // calculate normal vector
    vec3 nv = normalize( vec3( x * 2.0 - 1.0, y * 2.0 - 1.0, 1.0 ) );

    // encode normal vector
    gl_FragColor = vec4( nv * 0.5 + 0.5, 1.0 );
}

enter image description here

请参阅演示算法的WebGL示例:

&#13;
&#13;
var ShaderProgram = {};
ShaderProgram.Create = function( shaderList ) {
    var shaderObjs = [];
    for ( var i_sh = 0; i_sh < shaderList.length; ++ i_sh ) {
        var shderObj = this.CompileShader( shaderList[i_sh].source, shaderList[i_sh].stage );
        if ( shderObj == 0 )
            return 0;
        shaderObjs.push( shderObj );
    }
    var progObj = this.LinkProgram( shaderObjs )
    if ( progObj != 0 ) {
        progObj.attribIndex = {};
        var noOfAttributes = gl.getProgramParameter( progObj, gl.ACTIVE_ATTRIBUTES );
        for ( var i_n = 0; i_n < noOfAttributes; ++ i_n ) {
            var name = gl.getActiveAttrib( progObj, i_n ).name;
            progObj.attribIndex[name] = gl.getAttribLocation( progObj, name );
        }
        progObj.unifomLocation = {};
        var noOfUniforms = gl.getProgramParameter( progObj, gl.ACTIVE_UNIFORMS );
        for ( var i_n = 0; i_n < noOfUniforms; ++ i_n ) {
            var name = gl.getActiveUniform( progObj, i_n ).name;
            progObj.unifomLocation[name] = gl.getUniformLocation( progObj, name );
        }
    }
    return progObj;
}
ShaderProgram.AttributeIndex = function( progObj, name ) { return progObj.attribIndex[name]; } 
ShaderProgram.UniformLocation = function( progObj, name ) { return progObj.unifomLocation[name]; } 
ShaderProgram.Use = function( progObj ) { gl.useProgram( progObj ); } 
ShaderProgram.SetUniformI1  = function( progObj, name, val ) { if(progObj.unifomLocation[name]) gl.uniform1i( progObj.unifomLocation[name], val ); }
ShaderProgram.SetUniformF1  = function( progObj, name, val ) { if(progObj.unifomLocation[name]) gl.uniform1f( progObj.unifomLocation[name], val ); }
ShaderProgram.SetUniformF2  = function( progObj, name, arr ) { if(progObj.unifomLocation[name]) gl.uniform2fv( progObj.unifomLocation[name], arr ); }
ShaderProgram.SetUniformF3  = function( progObj, name, arr ) { if(progObj.unifomLocation[name]) gl.uniform3fv( progObj.unifomLocation[name], arr ); }
ShaderProgram.SetUniformF4  = function( progObj, name, arr ) { if(progObj.unifomLocation[name]) gl.uniform4fv( progObj.unifomLocation[name], arr ); }
ShaderProgram.SetUniformM33 = function( progObj, name, mat ) { if(progObj.unifomLocation[name]) gl.uniformMatrix3fv( progObj.unifomLocation[name], false, mat ); }
ShaderProgram.SetUniformM44 = function( progObj, name, mat ) { if(progObj.unifomLocation[name]) gl.uniformMatrix4fv( progObj.unifomLocation[name], false, mat ); }
ShaderProgram.CompileShader = function( source, shaderStage ) {
    var shaderScript = document.getElementById(source);
    if (shaderScript) {
      source = "";
      var node = shaderScript.firstChild;
      while (node) {
        if (node.nodeType == 3) source += node.textContent;
        node = node.nextSibling;
      }
    }
    var shaderObj = gl.createShader( shaderStage );
    gl.shaderSource( shaderObj, source );
    gl.compileShader( shaderObj );
    var status = gl.getShaderParameter( shaderObj, gl.COMPILE_STATUS );
    if ( !status ) alert(gl.getShaderInfoLog(shaderObj));
    return status ? shaderObj : 0;
} 
ShaderProgram.LinkProgram = function( shaderObjs ) {
    var prog = gl.createProgram();
    for ( var i_sh = 0; i_sh < shaderObjs.length; ++ i_sh )
        gl.attachShader( prog, shaderObjs[i_sh] );
    gl.linkProgram( prog );
    status = gl.getProgramParameter( prog, gl.LINK_STATUS );
    if ( !status ) alert("Could not initialise shaders");
    gl.useProgram( null );
    return status ? prog : 0;
}
        
function drawScene(){

    var canvas = document.getElementById( "ogl-canvas" );
    var vp = [canvas.width, canvas.height];
    var currentTime = Date.now();   
    var deltaMS = currentTime - startTime;
    
    gl.viewport( 0, 0, canvas.width, canvas.height );
    gl.enable( gl.DEPTH_TEST );
    gl.clearColor( 0.0, 0.0, 0.0, 1.0 );
    gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT );
    ShaderProgram.Use( progDraw );
    ShaderProgram.SetUniformF1( progDraw, "u_time", deltaMS/200.0 );
    gl.enableVertexAttribArray( progDraw.inPos );
    gl.bindBuffer( gl.ARRAY_BUFFER, bufObj.pos );
    gl.vertexAttribPointer( progDraw.inPos, 2, gl.FLOAT, false, 0, 0 ); 
    gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, bufObj.inx );
    gl.drawElements( gl.TRIANGLES, bufObj.inx.len, gl.UNSIGNED_SHORT, 0 );
    gl.disableVertexAttribArray( progDraw.pos );
}  

var startTime;
var gl;
var prog;
var bufObj = {};
function sceneStart() {

    var canvas = document.getElementById( "ogl-canvas");
    gl = canvas.getContext( "experimental-webgl" );
    if ( !gl )
      return;

    progDraw = ShaderProgram.Create( 
      [ { source : "draw-shader-vs", stage : gl.VERTEX_SHADER },
        { source : "draw-shader-fs", stage : gl.FRAGMENT_SHADER }
      ] );
    progDraw.inPos = gl.getAttribLocation( progDraw, "inPos" );
    if ( prog == 0 )
        return;

    var pos = [ -1, -1, 1, -1, 1, 1, -1, 1 ];
    var inx = [ 0, 1, 2, 0, 2, 3 ];
    bufObj.pos = gl.createBuffer();
    gl.bindBuffer( gl.ARRAY_BUFFER, bufObj.pos );
    gl.bufferData( gl.ARRAY_BUFFER, new Float32Array( pos ), gl.STATIC_DRAW );
    bufObj.inx = gl.createBuffer();
    bufObj.inx.len = inx.length;
    gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, bufObj.inx );
    gl.bufferData( gl.ELEMENT_ARRAY_BUFFER, new Uint16Array( inx ), gl.STATIC_DRAW );

    startTime = Date.now();
    setInterval(drawScene, 50);
}
&#13;
<script id="draw-shader-vs" type="x-shader/x-vertex">
precision mediump float;

attribute vec2 inPos;

varying vec2 ndcPos;

void main()
{
    ndcPos = inPos;
    gl_Position = vec4( inPos.xy, 0.0, 1.0 );
}
</script>

<script id="draw-shader-fs" type="x-shader/x-fragment">
precision mediump float;

varying vec2 ndcPos;  // normaliced device coordinates in range [-1.0, 1.0]
uniform float u_time;

vec2 hash( vec2 p ) { p=vec2(dot(p,vec2(127.1,311.7)),dot(p,vec2(269.5,183.3))); return fract(sin(p)*18.5453); }

// return distance, and cell id
vec2 voronoi( in vec2 x )
{
    vec2 n = floor( x );
    vec2 f = fract( x );
	vec3 m = vec3( 8.0 );
    for( int j=-1; j<=1; j++ )
    {
        for( int i=-1; i<=1; i++ )
        {
            vec2  g = vec2( float(i), float(j) );
            vec2  o = hash( n + g );
            vec2  r = g - f + (0.5+0.5*sin(u_time+6.2831*o));
	        float d = dot( r, r );
            if( d<m.x ) m = vec3( d, o );
        }
    }
    return vec2( sqrt(m.x), m.y+m.z );
}

void main()
{
    vec2 p = ndcPos * 2.0;
    vec2 c = voronoi( (14.0+6.0*sin(0.2*u_time))*p );
    float x = 0.5 + 0.5 * cos( c.y*6.2831 );
    float y = 0.5 + 0.5 * sin( c.y*6.2831 );
    
    // calculate normal vector
    vec3 nv = normalize( vec3( x * 2.0 - 1.0, y * 2.0 - 1.0, 1.0 ) );
    
    // encode normal vector
    gl_FragColor = vec4( nv * 0.5 + 0.5, 1.0 );
}
</script>

<body onload="sceneStart();">
    <canvas id="ogl-canvas" style="border: none;" width="256" height="256"></canvas>
</body>
&#13;
&#13;
&#13;