簡體   English   中英

有沒有辦法在頂點着色器的一個點的位置用片段着色器繪制一個圓?

[英]Is there a way to draw a circle with the fragment shader at the position of a point from the vertex shader?

所以我在某個……嗯……屏幕的點上畫一個點,然后四處移動。 我的頂點着色器看起來像這樣。

private final String vertexShaderCode =
     "attribute vec4 vPosition;" +
                "uniform mat4 Projection; \n" +
                "uniform mat4 ModelView; \n" +
                "void main() {" +
                        "  gl_Position = Projection * ModelView * vPosition;" +
                        "  gl_PointSize = 900.0; " +
                        "}"; 

我想要實現的是然后圍繞這個頂點的位置渲染一個圓圈。 為此,我正在使用片段着色器:

 private final String fragmentShaderCode =
        "precision highp float; \n" +
                "uniform vec2 aCirclePosition; \n" +
                "uniform float aRadius; \n" +
                "uniform vec4 aColor; \n" +
                "const float threshold = 0.3;\n" +
                "void main() \n" +
                "{ \n" +
                "   float d, dist;\n" +
                "   dist = distance(aCirclePosition, gl_FragCoord.xy);\n" +
                "   if(dist == 0.)\n" +
                "       dist = 1.;\n" +
                "   d = aRadius / dist;\n" +
                "   if(d >= 1.)\n" +
                "        gl_FragColor = aColor;\n" +
                "   else if(d >= 1. - threshold) \n" +
                "   {\n" +
                "        float a = (d - (1. - threshold)) / threshold;\n" +
                "        gl_FragColor = vec4(0., 0., 0., 1.); \n" +
                "    }\n" +
                "    else\n" +
                "        gl_FragColor = vec4(aColor.r, aColor.g, aColor.b, 0.);\n" +
                "} \n";

如本例所示: https : //gist.github.com/beetsolutions/9c343f86ec44987de4550cada118e560

然而,這樣繪制的圓將始終保持在屏幕上的靜態位置,與我使用的一個頂點的實際位置無關。 有什么方法可以將這兩個職位聯系起來或以任何其他方式實現我想要做的事情嗎?

我的想法是在頂點着色器中使用一個“可變”變量來保持位置,但是這似乎不起作用,因為它們使用不同的空間,(我相信頂點着色器中的 gl_position 在剪輯空間中,而片段着色器使用實際屏幕坐標,但我不確定那里),我不知道如何轉換它們。

有人可以幫助我或為我指出解決該問題的正確方向嗎? 我真的剛開始使用 openGL,所以請告訴我這里是否有一些基本的東西。

計算頂點着色器中點的窗口坐標。 為此,您必須知道視口的大小( uResolution )。 將點的位置傳遞給片段着色器 ( pointPos ):

precision mediump float;

attribute vec4 vPosition;
varying   vec2 pointPos;
uniform   vec2 uResolution; // = (window-width, window-height)
uniform   mat4 Projection;
uniform   mat4 ModelView;

void main()
{
    gl_Position  = Projection * ModelView * vPosition;
    gl_PointSize = 900.0;

    vec2 ndcPos = gl_Position.xy / gl_Position.w;
    pointPos    = uResolution * (ndcPos*0.5 + 0.5);
}

在片段着色器中使用點的位置 ( pointPos ) 而不是統一的aCirclePosition

如果你想把這個點重新指向一個圓形區域,那么你可以使用discard關鍵字來防止片段着色器輸出:

precision highp float;

varying vec2  pointPos;
uniform float aRadius;
uniform vec4  aColor;

const float threshold = 0.3;

void main()
{
    float dist = distance(pointPos, gl_FragCoord.xy);
    if (dist > aRadius)
        discard;

    float d = dist / aRadius;
    vec3 color = mix(aColor.rgb, vec3(0.0), step(1.0-threshold, d));

    gl_FragColor = vec4(color, 1.0);
}

請注意,點圖元的varying變量沒有內插,因為varying變量是在渲染的圖元上內插的,但一個點只有一個坐標。

請參閱OpenGL ES 2.0 完整規范; 3.3 積分; 第 51 頁

[...] 在光柵化一個點時產生的所有片段都分配有相同的關聯數據,這些數據是與該點對應的頂點的數據。


請參閱以下 WebGL 示例,其中我使用了答案中的着色器:

 var gl; var prog; var bufObj = {}; var ShaderProgram = {}; function renderScene(){ var canvas = document.getElementById( "ogl-canvas" ); var vp = [canvas.width, canvas.height]; gl.viewport( 0, 0, canvas.width, canvas.height ); gl.enable( gl.DEPTH_TEST ); gl.clearColor( 0.0, 0.0, 1.0, 1.0 ); gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT ); ShaderProgram.Use( progDraw ); ShaderProgram.SetUniformF1( progDraw, "aRadius", 50 ) ShaderProgram.SetUniformF2( progDraw, "uResolution", [canvas.width, canvas.height] ) ShaderProgram.SetUniformF4( progDraw, "aColor", [1.0, 1.0, 0.0, 1.0] ) gl.enableVertexAttribArray( progDraw.inPos ); gl.bindBuffer( gl.ARRAY_BUFFER, bufObj.pos ); gl.vertexAttribPointer( progDraw.inPos, 2, gl.FLOAT, false, 0, 0 ); gl.drawArrays( gl.POINTS, 0, 5 ); gl.disableVertexAttribArray( progDraw.pos ); requestAnimationFrame(renderScene); } function initScene() { 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, "vPosition" ); if ( prog == 0 ) return; var pos = [ 0.0, 1.0, 0.0, -1.0, 0.0, 0.0, 1.0, 0.0, -1.0, 0.0 ]; bufObj.pos = gl.createBuffer(); gl.bindBuffer( gl.ARRAY_BUFFER, bufObj.pos ); gl.bufferData( gl.ARRAY_BUFFER, new Float32Array( pos ), gl.STATIC_DRAW ); } 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; } initScene(); renderScene();
 <script id="draw-shader-vs" type="x-shader/x-vertex"> precision mediump float; attribute vec4 vPosition; varying vec2 pointPos; uniform vec2 uResolution; void main() { gl_PointSize = 100.0; gl_Position = vPosition; vec2 ndcPos = gl_Position.xy / gl_Position.w; pointPos = uResolution * (ndcPos*0.5 + 0.5); } </script> <script id="draw-shader-fs" type="x-shader/x-fragment"> precision highp float; varying vec2 pointPos; uniform float aRadius; uniform vec4 aColor; const float threshold = 0.3; void main() { float dist = distance(pointPos, gl_FragCoord.xy); if (dist > aRadius) discard; float d = dist / aRadius; vec3 color = mix(aColor.rgb, vec3(0.0), step(1.0-threshold, d)); gl_FragColor = vec4(color, 1.0); } </script> <canvas id="ogl-canvas" style="border: none;" width="256" height="256"></canvas>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM