Applying glow effect to square using glsl without texture

I took the same code from the tutorials Android

OpenGL

and I'm wondering if you can see the effect you can see here:

http://glslsandbox.com/e#25224.0

using the implementation Square

below? without using textures? I would like to apply this glowing effect to the whole Square

ie fill

The link above uses a variable resolution

, I'm not sure if this would be necessary if I was trying to influence my form. I am assuming the variable time

is unnecessary?

I've seen many examples of online flash shaders that are used to create a glow effect, but most of them use textures.

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;

import android.opengl.GLES20;

/**
 * A two-dimensional square for use as a drawn object in OpenGL ES 2.0.
 */
public class Square {

    private final String vertexShaderCode =
            "uniform mat4 uMVPMatrix;" +
            "attribute vec4 vPosition;" +
            "void main() {" +
            "  gl_Position = uMVPMatrix * vPosition;" +
            "}";

    private final String fragmentShaderCode =
            "precision mediump float;" +
            "uniform vec4 vColor;" +
            "void main() {" +
            "  gl_FragColor = vColor;" +
            "}";

    private final FloatBuffer vertexBuffer;
    private final ShortBuffer drawListBuffer;
    private final int mProgram;
    private int mPositionHandle;
    private int mColorHandle;
    private int mMVPMatrixHandle;

    // number of coordinates per vertex in this array
    static final int COORDS_PER_VERTEX = 3;
    static float squareCoords[] = {
            -0.5f,  0.5f, 0.0f,   // top left
            -0.5f, -0.5f, 0.0f,   // bottom left
             0.5f, -0.5f, 0.0f,   // bottom right
             0.5f,  0.5f, 0.0f }; // top right

    private final short drawOrder[] = { 0, 1, 2, 0, 2, 3 }; // order to draw vertices
    private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex
    float color[] = { 0.2f, 0.709803922f, 0.898039216f, 1.0f };

    /**
     * Sets up the drawing object data for use in an OpenGL ES context.
     */
    public Square() {

        ByteBuffer bb = ByteBuffer.allocateDirect(squareCoords.length * 4);
        bb.order(ByteOrder.nativeOrder());
        vertexBuffer = bb.asFloatBuffer();
        vertexBuffer.put(squareCoords);
        vertexBuffer.position(0);

        ByteBuffer dlb = ByteBuffer.allocateDirect(drawOrder.length * 2);
        dlb.order(ByteOrder.nativeOrder());
        drawListBuffer = dlb.asShortBuffer();
        drawListBuffer.put(drawOrder);
        drawListBuffer.position(0);

        // prepare shaders and OpenGL program
        int vertexShader = MyGLRenderer.loadShader(
                GLES20.GL_VERTEX_SHADER,
                vertexShaderCode);
        int fragmentShader = MyGLRenderer.loadShader(
                GLES20.GL_FRAGMENT_SHADER,
                fragmentShaderCode);

        mProgram = GLES20.glCreateProgram();             // create empty OpenGL Program
        GLES20.glAttachShader(mProgram, vertexShader);   // add the vertex shader to program
        GLES20.glAttachShader(mProgram, fragmentShader); // add the fragment shader to program
        GLES20.glLinkProgram(mProgram);                  // create OpenGL program executables
    }

    /**
     * Encapsulates the OpenGL ES instructions for drawing this shape.
     *
     * @param mvpMatrix - The Model View Project matrix in which to draw
     * this shape.
     */
    public void draw(float[] mvpMatrix) {

        GLES20.glUseProgram(mProgram);

        mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
        GLES20.glEnableVertexAttribArray(mPositionHandle);

        GLES20.glVertexAttribPointer(
                mPositionHandle, COORDS_PER_VERTEX,
                GLES20.GL_FLOAT, false,
                vertexStride, vertexBuffer);

        mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");
        GLES20.glUniform4fv(mColorHandle, 1, color, 0);

        mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
        MyGLRenderer.checkGlError("glGetUniformLocation");

        GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
        MyGLRenderer.checkGlError("glUniformMatrix4fv");

        GLES20.glDrawElements(
                GLES20.GL_TRIANGLES, drawOrder.length,
                GLES20.GL_UNSIGNED_SHORT, drawListBuffer);

        GLES20.glDisableVertexAttribArray(mPositionHandle);
    }
}

      

+3


source to share


1 answer


The only reason the permission variable is used is just to get a valid uv mapping. Generally, I would recommend that you add uv mapping to your Square

. You don't have to use textures, just texture coordinates. In this case, your fragment shader will look like this:

uniform float u_time;
varying vec2 v_uv;

void main( void ) {
    vec2 uv = v_uv;
    // Zooms out by a factor of 2.0
    uv *= 2.0;
    // Shifts every axis by -1.0
    uv -= 1.0;

    // Base color for the effect
    vec3 finalColor = vec3 ( .2, 1., 0. );

    finalColor *= abs(0.05 / (sin( uv.x + sin(uv.y+u_time)* 0.3 ) * 20.0) );

    gl_FragColor = vec4( finalColor, 1.0 );    
}

      

In the vertex shader, you need to pass the uv coordinate to the fragment shader:

attribute vec4 vPosition;
attribute vec4 uv;
uniform mat4 uMVPMatrix;
varying vec2 v_uv;

void main() 
{
    v_uv = uv;
    gl_Position = uMVPMatrix * vPosition;
}

      

Also you will need to create another vertex buffer for the uv coordinates or copy the uv coordinates into an existing buffer. Then you will need to follow all the steps you did for the vertex attribute vPosition , also for the new uv attribute. I mean, you need to do glGetAttribLocation, glEnableVertexAttribArray and glVertexAttribPointer on the uv attribute .

Here is a tutorial that can help you.

I wrote a small example using three js:

   var container;
   var camera, scene, renderer;
   var mesh;
   var uniforms;

   var clock = new THREE.Clock();

   init();
   animate();

   function init() {
     container = document.getElementById('container');

     camera = new THREE.PerspectiveCamera(40, window.innerWidth / window.innerHeight, 1, 3000);
     camera.position.z = 2.0;
     camera.position.y = 1.0;
     camera.rotation.x = -0.45;

     scene = new THREE.Scene();

     var boxGeometry = new THREE.CubeGeometry(0.75, 0.75, 0.75);

     uniforms = {u_time: {type: "f", value: 0.0 } };

     var material = new THREE.ShaderMaterial({
       uniforms: uniforms,
       vertexShader: document.getElementById('vertexShader').textContent,
       fragmentShader: document.getElementById('fragment_shader').textContent
     });

     mesh = new THREE.Mesh(boxGeometry, material);
     scene.add(mesh);

     renderer = new THREE.WebGLRenderer();
     renderer.setClearColor( 0xffffff, 1 );
     container.appendChild(renderer.domElement);

     onWindowResize();

     window.addEventListener('resize', onWindowResize, false);

   }

   function onWindowResize(event) {
     camera.aspect = window.innerWidth / window.innerHeight;
     camera.updateProjectionMatrix();
     renderer.setSize(window.innerWidth, window.innerHeight);
   }

   function animate() {
     requestAnimationFrame(animate);
     render();
   }

   function render() {
     var delta = clock.getDelta();
     uniforms.u_time.value += delta;
     mesh.rotation.y += delta * 0.5;
     renderer.render(scene, camera);
   }
      

body { margin: 0px; overflow: hidden; }
      

<script src="http://threejs.org/build/three.min.js"></script>
<div id="container"></div>

<script id="fragment_shader" type="x-shader/x-fragment">
    uniform float u_time;
	varying vec2 v_uv;
    
    void main( void ) {
        vec2 uv = v_uv;
        // Zooms out by a factor of 2.0
        uv *= 2.0;
        // Shifts every axis by -1.0
        uv -= 1.0;
        
        // Base color for the effect
        vec3 finalColor = vec3 ( .2, 1., 0. );
        
        finalColor *= abs(0.05 / (sin( uv.x + sin(uv.y+u_time)* 0.3 ) * 20.0) );
    
        gl_FragColor = vec4( finalColor, 1.0 );    
    }
</script>

<script id="vertexShader" type="x-shader/x-vertex">
    varying vec2 v_uv;
                
    void main()
    {
		v_uv = uv;
		vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
		gl_Position = projectionMatrix * mvPosition;
    }
</script>
      

Run codeHide result


Alternatively, you can not modify your Java code at all, just compute the uv coordinates from the vertex coordinates of your square's object space in the vertex shader and then pass them to the fragment shader.

Vertex shader:

attribute vec4 vPosition;
uniform mat4 uMVPMatrix;
varying vec2 v_uv;

void main() 
{
    v_uv = vPosition.xy + vec2(0.5);      //this expression depends on the actual vertex coordinates values.
    gl_Position = uMVPMatrix * vPosition;
}

      



The fragment shader will be the same.

UPDATE

I thought that you want the exact same line in your square. If you only want a glow effect without using textures, you can use the distance field. For a rectangle, the distance field can be calculated as simply as:

float distanceField = length(max(abs(uv)-rectangleSize,0.0));

      

Where rectangleSize is the size of the rectangle in the display uv, uv and uv are the coordinates of the point of interest. To make the distance field appear as: 0.0 is a point inside the rectangle, 1.0 point is at the extreme edge of the border. You can do the following:

float distanceField = length(max(abs(uv)-rectangleSize,0.0) / borderSize);

      

Where borderSize is the size of the border in the uv display.

So your final fragment shader will look like this:

varying vec2 v_uv;

void main( void ) {
    vec2 uv = v_uv;
    // Zooms out by a factor of 2.0
    uv *= 2.0;
    // Shifts every axis by -1.0
    uv -= 1.0;

    // Base color for the effect
    vec3 color = vec3 ( .2, 1., 0. );

    // specify size of border. 0.0 - no border, 1.0 - border occupies the entire space
    vec2 borderSize = vec2(0.3); 

    // size of rectangle in terms of uv 
    vec2 rectangleSize = vec2(1.0) - borderSize; 

    // distance field, 0.0 - point is inside rectangle, 1.0 point is on the far edge of the border.
    float distanceField = length(max(abs(uv)-rectangleSize,0.0) / borderSize);

    // calculate alpha accordingly to the value of the distance field
    float alpha = 1.0 - distanceField;

    gl_FragColor = vec4(color, alpha);    
}

      

Here's an example:

 var container;
   var camera, scene, renderer;
   var mesh;
   var uniforms;

   var clock = new THREE.Clock();

   init();
   animate();

   function init() {
     container = document.getElementById('container');

     camera = new THREE.PerspectiveCamera(40, window.innerWidth / window.innerHeight, 1, 3000);
     camera.position.z = 2.0;
     camera.position.y = 1.0;
     camera.rotation.x = -0.45;

     scene = new THREE.Scene();

     var boxGeometry = new THREE.PlaneGeometry(0.75, 0.75, 1);

     uniforms = {u_time: {type: "f", value: 0.0 } };

     var material = new THREE.ShaderMaterial({
       uniforms: uniforms,
       side: THREE.DoubleSide, 
       transparent: true,
       vertexShader: document.getElementById('vertexShader').textContent,
       fragmentShader: document.getElementById('fragment_shader').textContent
     });

     mesh = new THREE.Mesh(boxGeometry, material);
     scene.add(mesh);

     renderer = new THREE.WebGLRenderer();
     renderer.setClearColor( 0xffffff, 1 );
     container.appendChild(renderer.domElement);

     onWindowResize();

     window.addEventListener('resize', onWindowResize, false);

   }

   function onWindowResize(event) {
     camera.aspect = window.innerWidth / window.innerHeight;
     camera.updateProjectionMatrix();
     renderer.setSize(window.innerWidth, window.innerHeight);
   }

   function animate() {
     requestAnimationFrame(animate);
     render();
   }

   function render() {
     var delta = clock.getDelta();
     uniforms.u_time.value += delta;
     mesh.rotation.y += delta * 0.5;
     renderer.render(scene, camera);
   }
      

body { margin: 0px; overflow: hidden; }
      

<script src="http://threejs.org/build/three.min.js"></script>
<div id="container"></div>

<script id="fragment_shader" type="x-shader/x-fragment">
	varying vec2 v_uv;
    
    void main( void ) {
        vec2 uv = v_uv;
        // Zooms out by a factor of 2.0
        uv *= 2.0;
        // Shifts every axis by -1.0
        uv -= 1.0;
        
        // Base color for the effect
        vec3 color = vec3 ( .2, 1., 0. );
    
        // specify size of border. 0.0 - no border, 1.0 - border occupies the entire space
        vec2 borderSize = vec2(0.3); 
    
        // size of rectangle in terms of uv 
        vec2 rectangleSize = vec2(1.0) - borderSize; 
    
        // distance field, 0.0 - point is inside rectangle, 1.0 point is on the far edge of the border.
        float distanceField = length(max(abs(uv)-rectangleSize,0.0) / borderSize);
        
        // calculate alpha accordingly to the value of the distance field
        float alpha = 1.0 - distanceField;
    
        gl_FragColor = vec4(color, alpha);    
    }
</script>

<script id="vertexShader" type="x-shader/x-vertex">
    varying vec2 v_uv;
                
    void main()
    {
		v_uv = uv;
		vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
		gl_Position = projectionMatrix * mvPosition;
    }
</script>
      

Run codeHide result


+3


source







All Articles