在圆的中间更改颜色 [英] Change color in middle of circle

查看:195
本文介绍了在圆的中间更改颜色的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我刚刚接触WebGL,我想在这个绿色圆圈的中间创建一个黑色圆环,而不添加其他圆圈。我相信我可以做到这一点,使这些三角形的法线以其他方式,但我不知道如何做到这一点。我的朋友建议更改纹理坐标,但我真的不明白这将如何帮助。任何人都可以发现一些光这些想法和可能的直觉?



_______ HTML文件__________

 <!DOCTYPE html& 
< html>
< head>

< script id =vertex-shadertype =x-shader / x-vertex>
attribute vec4 vPosition;

void
main()
{
gl_Position = vPosition;
}
< / script>

< script id =fragment-shadertype =x-shader / x-fragment>
precision mediump float;

void
main()
{
gl_FragColor = vec4(0.0,1.0,0.0,1.0);
}
< / script>

< script type =text / javascriptsrc =../ Common / webgl-utils.js>< / script>
< script type =text / javascriptsrc =../ Common / initShaders.js>< / script>
< script type =text / javascriptsrc =../ Common / MV.js>< / script>
< script type =text / javascriptsrc =Circle.js>< / script>
< / head>

< body>
< canvas id =gl-canvaswidth =512height =512>
糟糕...您的浏览器不支持HTML5 canvas元素
< / canvas>
< / body>
< / html>

_____ Javascript文件______

  var gl; 
var points;


window.onload = function init()
{
var canvas = document.getElementById(gl-canvas);

gl = WebGLUtils.setupWebGL(canvas);
if(!gl){alert(WebGL is not available); }


//顶点
var pi = 3.14159;
var x = 2 * pi / 100;
var y = 2 * pi / 100;
var r = 0.9;

points = [vec2(0.0,0.0)]; //建立起源

// for循环推动点
for(var i = 0; i <100; i ++){
points.push(vec2(r * Math.cos(x * i),r * Math.sin(y * i)));
points.push(vec2(r * Math.cos(x *(i + 1)),r * Math.sin(y *(i + 1))));
}

//
//配置WebGL
//
gl.viewport(0,0,canvas.width,canvas.height)
gl.clearColor(0.3,0.3,0.3,1.0);

//加载着色器和初始化属性缓冲区

var program = initShaders(gl,vertex-shader,fragment-shader);
gl.useProgram(program);

//将数据加载到GPU中

var bufferId = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER,bufferId);
gl.bufferData(gl.ARRAY_BUFFER,flatten(points),gl.STATIC_DRAW);

//将着色器变量与数据缓冲区关联

var vPosition = gl.getAttribLocation(program,vPosition);
gl.vertexAttribPointer(vPosition,2,gl.FLOAT,false,0,0);
gl.enableVertexAttribArray(vPosition);

render();
};


function render(){
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLE_FAN,0,points.length);
}


解决方案

任务。我试图不改变你的代码太多,所以你可以理解我做的所有改变。第一个小展示:




  • ,这可能会帮助你做疯狂的锋利形状,只是几点。但这一切都是你想做什么。一种技术不能解决所有问题,你必须不断寻找更多的解决方案。



    编辑1: var middle = vec2(0.0,0.0)?I meam,vec2? >



    在我的解决方案中(在左侧的jsfiddle中:外部资源)复制的问题中还有3个其他脚本。这不是这个问题的一部分,但是很容易找到他们的起源:

     < script type =text / javascript src =../ Common / webgl-utils.js>< / script> 
    < script type =text / javascriptsrc =../ Common / initShaders.js>< / script>
    < script type =text / javascriptsrc =../ Common / MV.js>< / script>

    MV.js是一些供应javascript与基本数学...或代数结构像矢量和矩阵。 vec2 是返回长度为2的数组的函数。因此 var middle = [0.0,0.0]; 事情。这不是本机javascript的一部分,所以你需要一些库(你不需要它,但它是非常有用的)。我使用 glmatrix



    另一方面,在着色器中,向量和矩阵是原生的。您可以在 4.1基本类型中自行查找>。


    I'm new to WebGL and I'm trying to create a black ring in the middle of this green circle without making additional circles. I believe I can do this by making the normal of those triangles go the other way but I'm not sure exactly how to do this. My friend suggested changing the texture coordinates but I don't really understand how this would help. Can anyone shine some light on these ideas and possible intuition?

    _______HTML File__________

    <!DOCTYPE html>
    <html>
    <head>
    
    <script id="vertex-shader" type="x-shader/x-vertex">
    attribute vec4 vPosition;
    
    void
    main()
    {
        gl_Position = vPosition;
    }
    </script>
    
    <script id="fragment-shader" type="x-shader/x-fragment">
    precision mediump float;
    
    void
    main()
    {
        gl_FragColor = vec4( 0.0, 1.0, 0.0, 1.0 );
    }
    </script>
    
    <script type="text/javascript" src="../Common/webgl-utils.js"></script>
    <script type="text/javascript" src="../Common/initShaders.js"></script>
    <script type="text/javascript" src="../Common/MV.js"></script>
    <script type="text/javascript" src="Circle.js"></script>
    </head>
    
    <body>
    <canvas id="gl-canvas" width="512" height="512">
    Oops ... your browser doesn't support the HTML5 canvas element
    </canvas>
    </body>
    </html>
    

    _____Javascript File______

    var gl;
    var points;
    
    
    window.onload = function init()
    {
        var canvas = document.getElementById( "gl-canvas" );
    
        gl = WebGLUtils.setupWebGL( canvas );
        if ( !gl ) { alert( "WebGL isn't available" ); }
    
    
        // The Vertices
        var pi = 3.14159;
        var x = 2*pi/100;
        var y = 2*pi/100;
        var r = 0.9;
    
        points = [ vec2(0.0, 0.0) ]; //establish origin 
    
        //for loop to push points
        for(var i = 0; i < 100; i++){
            points.push(vec2(r*Math.cos(x*i), r*Math.sin(y*i)));
            points.push(vec2(r*Math.cos(x*(i+1)), r*Math.sin(y*(i+1))));
        }
    
        //
        //  Configure WebGL
        //
        gl.viewport( 0, 0, canvas.width, canvas.height );
        gl.clearColor( 0.3, 0.3, 0.3, 1.0 );
    
        //  Load shaders and initialize attribute buffers
    
        var program = initShaders( gl, "vertex-shader", "fragment-shader" );
        gl.useProgram( program );
    
        // Load the data into the GPU
    
        var bufferId = gl.createBuffer();
        gl.bindBuffer( gl.ARRAY_BUFFER, bufferId );
        gl.bufferData( gl.ARRAY_BUFFER, flatten(points), gl.STATIC_DRAW );
    
        // Associate out shader variables with our data buffer
    
        var vPosition = gl.getAttribLocation( program, "vPosition" );
        gl.vertexAttribPointer( vPosition, 2, gl.FLOAT, false, 0, 0 );
        gl.enableVertexAttribArray( vPosition );
    
        render();
    };
    
    
    function render() {
        gl.clear( gl.COLOR_BUFFER_BIT );
        gl.drawArrays( gl.TRIANGLE_FAN, 0, points.length );
    }
    

    解决方案

    I assembled some part of your task as you requested. I tried to not change your code much, so you can understand all changes I have done. First small show:

    You made circle out of 100 points (vertices). Now you want to make another shape inside. It means use another 100 points, which is probably what you don't want to do. Instead of this, you would like to use normals. But from the point of view of shaders (which are responsible for drawing), normals, vertices and other things like texture coordinates are just data and you are the one who decides, if data means vertices, normals, texture coordinates or anything else.

    If I understand good, you want to customize your object without adding too much additional data. I don't think normals or textures can help you.

    There are few problems you will have to face with texture ...

    • First is, if circle will be too big (close to you), then it will be not that nice with just 100 points.
    • If circle will be too small (far from you), but there will be a lot circles, you will use too many points for nothing which will lower performance.
    • If you use texture for black ring inside, it will be fuzzy if you will be closer.
    • And if you use too large texture for a lot of small circles, it will again lower performance.

    ... and normals are used to do light reflection like this.

    Way I think about the problem. You can define circle with just few params, radius and center. With webgl, you can draw only triangles (and points). But you can for example customize shader to draw inscribed circle in each triangle.

    So I defined just radius and center:

    var r = 0.9;
    var middle = vec2(0.0, 0.0);
    

    Then I generate 3 points of triangle around the circle (circle is inscribed circle of this new triangle):

    function buildCircle(center, r) {
        var points = [];
    
        points.push(vec2((r * TRI_HEIGHT_MOD * Math.cos(0 * DEG_TO_RAD)) + center[0], (r * TRI_HEIGHT_MOD * Math.sin(0 * DEG_TO_RAD)) + center[1]));
        points.push(vec2((r * TRI_HEIGHT_MOD * Math.cos(120 * DEG_TO_RAD)) + center[0], (r * TRI_HEIGHT_MOD * Math.sin(120 * DEG_TO_RAD) + center[1])));
        points.push(vec2((r * TRI_HEIGHT_MOD * Math.cos(240 * DEG_TO_RAD)) + center[0], (r * TRI_HEIGHT_MOD * Math.sin(240 * DEG_TO_RAD)) + center[1]));
    
        vertexPositions = points;
    }
    

    Then I pass middle, radius and triangle to my shader:

    var vPosition = gl.getAttribLocation(program, "vPosition");
    gl.vertexAttribPointer(vPosition, 2, gl.FLOAT, false, 0, 0);
    gl.enableVertexAttribArray(vPosition);
    
    program.middle = gl.getUniformLocation(program, "middle");
    gl.uniform2f(program.middle, middle[0], middle[1]);
    
    program.r = gl.getUniformLocation(program, "r");
    gl.uniform1f(program.r, r);
    

    And then I just render it with same as you do, except I need to allow alpha drawing, because some parts of triangle will be invisible, so it will look as circle:

    gl.blendFunc(gl.SRC_ALPHA, gl.ONE);
    gl.enable(gl.BLEND);
    gl.disable(gl.DEPTH_TEST);
    

    Ok now shaders.

    There are few things you really need to know to continue, so please read about it here: http://webglfundamentals.org/webgl/lessons/webgl-how-it-works.html

    My vertex shader is same as yours, except I need to pass interpolated vertex position to fragment shader:

    varying vec4 pos;
    
    ... 
    
    void main() {
        pos = vPosition;
    

    My fragment shader needs to do only one thing and it is to decide, if pixel is in the circle or not. Simple equation:

    If the left side is smaller then the right side, then pixel is inside the circle. If not, then it is outside, so invisible:

        float inside = pow(pos.r - middle.r, 2.0) + pow(pos.g - middle.g, 2.0);
        if (inside < pow(r, 2.0)) {
            gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
        } else {
            gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);
        }
    

    End

    So now you might know how to make a circle just from few points. You can use similar way to draw a ring inside. Then you can draw thousands of them in any distance and make them move. Program will be still fast and shapes will be as sharp as possible.

    Just one last thing. Usually you dont simplify shapes like that, but sometimes you might. Good example is Bézier curve which might help you to do crazy sharp shapes with just few points. But it all matters what would you like to do. One technique can't solve all problems and you have to keep looking for more solutions.

    EDIT 1: "What is var middle = vec2(0.0, 0.0)? I meam, vec2?"

    There are 3 other scripts in this question that I replicated in my solution (in jsfiddle on the left: External Resources). It wasnt part of this question, but it was easy to find theirs origin:

    <script type="text/javascript" src="../Common/webgl-utils.js"></script>
    <script type="text/javascript" src="../Common/initShaders.js"></script>
    <script type="text/javascript" src="../Common/MV.js"></script>
    

    MV.js is some supply javascript with basic math... or algebraic constructs like vectors and matrices. vec2 is function that returns array with length 2. So var middle = [0.0, 0.0]; is exactly the same thing. This is not part of native javascript, so you need some library for it (you don't need it, but it is very useful). I use glmatrix.

    On the other hand in shaders, vectors and matrices are native. Find it out on your own in chapter 4.1 Basic Types.

    这篇关于在圆的中间更改颜色的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆