opengl - 使用没有纹理的 glsl 将发光效果应用于正方形

标签 opengl glsl glow

我从 Android 中获取了一些相同的代码OpenGL教程,我想知道是否有可能实现这里看到的发光效果:

http://glslsandbox.com/e#25224.0

使用 Square下面执行?即不使用纹理?我想将这种发光效果应用于整个 Square即填充

上面的链接使用了 resolution变量,如果我想对我的形状施加影响,我不确定是否需要这样做。我假设 time不需要变量?

我在网上看到了许多用于产生发光效果的片段着色器示例,但其中大多数使用纹理。

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);
    }
}

最佳答案

使用分辨率变量的唯一原因只是为了获得有效的 uv 映射。通常,我会建议您将纹理坐标(uv 映射)添加到您的 Square 中。 .您不必使用纹理,只需使用纹理坐标。
在这种情况下,您的片段着色器将是:

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 );    
}

在顶点着色器中,您需要将 uv 坐标传递给片段着色器:
attribute vec4 vPosition;
attribute vec4 uv;
uniform mat4 uMVPMatrix;
varying vec2 v_uv;

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

此外,您还必须为 uv 坐标创建一个更多的顶点缓冲区,或者将 uv 坐标打包到现有缓冲区中。
然后您将需要执行您为顶点属性 所做的所有操作。 vPosition 也适用于新的 uv 属性。我的意思是,您需要为 执行 glGetAttribLocation、glEnableVertexAttribArray 和 glVertexAttribPointer紫外线 属性。

Here是一个教程,可以帮助你。

我用threejs写了一个小例子:

   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>


作为替代方案,您根本不能修改 Java 代码,只需在顶点着色器中根据正方形的对象空间顶点坐标计算 uv 坐标,然后将它们传递给片段着色器。

顶点着色器:
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;
}

片段着色器将是相同的。

更新

我想,你想要在你的正方形上完全相同的线。如果您只想要一些发光效果而不使用纹理,您可以使用距离场。
对于矩形,距离场可以简单地计算为:
float distanceField = length(max(abs(uv)-rectangleSize,0.0));

哪里矩形尺寸 uv 映射中矩形的大小,紫外线 兴趣点的 uv 坐标。
要将距离场映射为:
0.0 - 点在矩形内,1.0 点在边界的远边缘。
你可以做以下事情:
float distanceField = length(max(abs(uv)-rectangleSize,0.0) / borderSize);

哪里边框尺寸 uv 映射中边框的大小。

因此,您的最终片段着色器将是:
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);    
}

下面是一个例子:

 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>

关于opengl - 使用没有纹理的 glsl 将发光效果应用于正方形,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30282060/

相关文章:

visual-studio - 以编程方式切换 MESA 软件渲染器的 dll

c++ - 使用鼠标拖动的 OpenGL 绘图矩形?

c++ - 将属性传递给 OpenGL 顶点着色器的行为很奇怪

java - libgdx 中的着色器没有效果 [桌面]

html - 如何在 HTML 和 CSS 中制作发光的文本

shader - Directx 11 HLSL 发光效果

javascript - 如何向图像添加发光滤镜

Opengl 像素完美 2D 绘图

c++ - 使用 glTextCoordPointer 贴花纹理

opengl - glProgramUniform() 和 glUniform() 有什么区别?