有没有一种方法可以用碎片着色器在顶点着色器的点位置绘制圆



所以我在某个。。。好屏幕上移动的点。我的顶点着色器如下所示。

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" +
"    elsen" +
"        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>

最新更新