在圆的中间更改颜色 [英] Change color in middle of circle
问题描述
我刚刚接触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. Sovar 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屋!