我编写了一个程序,只使用HTML5和常规Javascript绘制一些参数形状(球体,圆环和圆柱体)。我正在尝试转换此代码,以便它使用WebGL,使用三角形条实现形状,如this tutorial中所述。我的困惑之处在于三角带甚至是如何用于创建球体的。我之前做的方式只是计算根据for循环中的纬度线绘制每个水平切片或圆的位置,并嵌套在该循环内部是计算该圆上的每个点。在生成所有这些点之后,我将它们传递给一个函数,该函数将所有顶点添加到一个数组中,该数组返回并传递给使用moveTo()
和lineTo()
绘制的曲线绘制函数以便绘制每个点之间的线。问题是,当使用三角形形状时,我不知道webGL中moveTo()
和lineTo()
的等价物是什么。如何将我的实现转换为WebGL?
以下是我原始实现中的一些代码:
//Calculates point on sphere
function spherePoint(uv) {
var u = uv[0];
var v = uv[1];
var phi = -Math.PI/2 + Math.PI * v;
var theta = 2 * Math.PI * u;
return [ Math.cos(phi) * Math.cos(theta),
Math.cos(phi) * Math.sin(theta),
Math.sin(phi)];
}
// Takes the parametric function as an argument and constructs 3D shape
function makeShape(num_u, num_v, eq, possRad) {
var shell = [];
for (var j = 0 ; j <= num_v ; j++) {
var v = j / num_v;
shell.push([]);
for (var i = 0 ; i <= num_u ; i++) {
var u = i / num_u;
var p = eq([u, v], possRad);
shell[j].push(p);
}
}
return shell;
}
// Used to create shapes to render parametric surface
function renderShape(shape) {
var num_j = shape.length;
var num_i = shape[0].length;
for (var j = 0 ; j < num_j - 1 ; j++)
for (var i = 0 ; i < num_i - 1 ; i++) {
plotCurve([shape[j][i],
shape[j + 1][i],
shape[j + 1][i + 1],
shape[j][i + 1]]);
}
}
//plot curve on canvas
function plotCurve(C) {
g.beginPath();
for (var i = 0 ; i < C.length ; i++)
if (i == 0)
moveTo(C[i]);
else
lineTo(C[i]);
g.stroke();
}
function moveTo(p) {
var q = m.transform(p); // APPLY 3D MATRIX TRANFORMATION
var xy = viewport(q); // APPLY VIEWPORT TRANSFORM
g.moveTo(xy[0], xy[1]);
}
function lineTo(p) {
var q = m.transform(p); // APPLY 3D MATRIX TRANFORMATION
var xy = viewport(q); // APPLY VIEWPORT TRANSFORM
g.lineTo(xy[0], xy[1]);
}
答案 0 :(得分:2)
这是一个非常基本的WebGL问题。 Some more tutorials on webgl might be helpful。
WebGL仅绘制大量数据。它实际上没有lineTo
或moveTo
。相反,你给它缓冲数据,告诉它如何从这些缓冲区中提取数据,然后你编写一个函数(一个顶点着色器)来使用该数据告诉WebGL如何将它转换为剪辑空间坐标以及是否绘制点,线,或带有结果的三角形。您还提供了一个函数(片段着色器)来告诉它用于点,线或三角形的颜色。
基本上要绘制想要绘制的东西,您需要为该球体上的每个矩形生成2个三角形。换句话说,您需要为每个矩形生成6个顶点。原因是为了绘制不同颜色的每个三角形,您不能共享任何顶点,因为颜色与顶点相关联。
因此,对于一个矩形,您需要生成这些点
0--1 4
| / /|
|/ / |
2 3--5
其中0,1和2是粉红点,3,4,5是绿点。 1和4具有相同的位置,但由于它们的颜色不同,它们必须是不同的点。与第2点和第3点相同。
var pink = [1, 0.5, 0.5, 1];
var green = [0.5, 1, 0.5, 1];
var positions = [];
var colors = [];
var across = 20;
var down = 10;
function addPoint(x, y, color) {
var u = x / across;
var v = y / down;
var radius = Math.sin(v * Math.PI);
var angle = u * Math.PI * 2;
var nx = Math.cos(angle);
var ny = Math.cos(v * Math.PI);
var nz = Math.sin(angle);
positions.push(
nx * radius, // x
ny, // y
nz * radius); // z
colors.push(color[0], color[1], color[2], color[3]);
}
for (var y = 0; y < down; ++y) {
for (var x = 0; x < across; ++x) {
// for each rect we need 6 points
addPoint(x , y , pink);
addPoint(x + 1, y , pink);
addPoint(x , y + 1, pink);
addPoint(x , y + 1, green);
addPoint(x + 1, y , green);
addPoint(x + 1, y + 1, green);
}
}
这里是上面渲染的球体,但没有任何光线,透视或任何东西。
var pink = [1, 0.5, 0.5, 1];
var green = [0.5, 1, 0.5, 1];
var positions = [];
var colors = [];
var across = 20;
var down = 10;
function addPoint(x, y, color) {
var u = x / across;
var v = y / down;
var radius = Math.sin(v * Math.PI);
var angle = u * Math.PI * 2;
var nx = Math.cos(angle);
var ny = Math.cos(v * Math.PI);
var nz = Math.sin(angle);
positions.push(
nx * radius, // x
ny, // y
nz * radius); // z
colors.push(color[0], color[1], color[2], color[3]);
}
for (var y = 0; y < down; ++y) {
for (var x = 0; x < across; ++x) {
// for each rect we need 6 points
addPoint(x , y , pink);
addPoint(x + 1, y , pink);
addPoint(x , y + 1, pink);
addPoint(x , y + 1, green);
addPoint(x + 1, y , green);
addPoint(x + 1, y + 1, green);
}
}
var gl = twgl.getWebGLContext(document.getElementById("c"));
var programInfo = twgl.createProgramInfo(gl, ["vs", "fs"]);
var arrays = {
position: positions,
color: colors,
};
var bufferInfo = twgl.createBufferInfoFromArrays(gl, arrays);
var uniforms = {
resolution: [gl.canvas.width, gl.canvas.height],
};
gl.useProgram(programInfo.program);
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
twgl.setUniforms(programInfo, uniforms);
twgl.drawBufferInfo(gl, bufferInfo);
&#13;
canvas { border: 1px solid black; }
&#13;
<canvas id="c"></canvas>
<script id="vs" type="not-js">
attribute vec4 position;
attribute vec4 color;
uniform vec2 resolution;
varying vec4 v_color;
void main() {
gl_Position = position * vec4(resolution.y / resolution.x, 1, 1, 1);
v_color = color;
}
</script>
<script id="fs" type="not-js">
precision mediump float;
varying vec4 v_color;
void main() {
gl_FragColor = v_color;
}
</script>
<script src="https://twgljs.org/dist/3.x/twgl-full.min.js"></script>
&#13;
如果您以后想点亮它,您还需要法线(您可以使用这些值来判断某些方向正面)。我们可以通过添加
来添加它们var normals = [];
和addPoint
function addPoint(x, y, color) {
var u = x / across;
var v = y / down;
var radius = Math.sin(v * Math.PI);
var angle = u * Math.PI * 2;
var nx = Math.cos(angle);
var ny = Math.cos(v * Math.PI);
var nz = Math.sin(angle);
positions.push(
nx * radius, // x
ny, // y
nz * radius); // z
colors.push(color[0], color[1], color[2], color[3]);
normals.push(nx, ny, nz);
}
这是一个带有黑客照明的样本
var pink = [1, 0.5, 0.5, 1];
var green = [0.5, 1, 0.5, 1];
var positions = [];
var colors = [];
var normals = [];
var across = 20;
var down = 10;
function addPoint(x, y, color) {
var u = x / across;
var v = y / down;
var radius = Math.sin(v * Math.PI);
var angle = u * Math.PI * 2;
var nx = Math.cos(angle);
var ny = Math.cos(v * Math.PI);
var nz = Math.sin(angle);
positions.push(
nx * radius, // x
ny, // y
nz * radius); // z
normals.push(nx, ny, nz);
colors.push(color[0], color[1], color[2], color[3]);
}
for (var y = 0; y < down; ++y) {
for (var x = 0; x < across; ++x) {
// for each rect we need 6 points
addPoint(x , y , pink);
addPoint(x + 1, y , pink);
addPoint(x , y + 1, pink);
addPoint(x , y + 1, green);
addPoint(x + 1, y , green);
addPoint(x + 1, y + 1, green);
}
}
var gl = document.getElementById("c").getContext("webgl");
var programInfo = twgl.createProgramInfo(gl, ["vs", "fs"]);
var arrays = {
position: positions,
normal: normals,
color: colors,
};
var bufferInfo = twgl.createBufferInfoFromArrays(gl, arrays);
var uniforms = {
resolution: [gl.canvas.width, gl.canvas.height],
lightDirection: [0.5, 0.5, -1],
};
gl.useProgram(programInfo.program);
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
twgl.setUniforms(programInfo, uniforms);
twgl.drawBufferInfo(gl, bufferInfo);
&#13;
canvas { border: 1px solid black; }
&#13;
<canvas id="c"></canvas>
<script id="vs" type="not-js">
attribute vec4 position;
attribute vec4 color;
attribute vec3 normal;
uniform vec2 resolution;
varying vec4 v_color;
varying vec3 v_normal;
void main() {
gl_Position = position * vec4(resolution.y / resolution.x, 1, 1, 1);
v_color = color;
v_normal = normal;
}
</script>
<script id="fs" type="not-js">
precision mediump float;
varying vec4 v_color;
varying vec3 v_normal;
uniform vec3 lightDirection;
void main() {
float light = pow(abs(dot(v_normal, normalize(lightDirection))), 2.0);
gl_FragColor = vec4(v_color.xyz * light, v_color.a);
}
</script>
<script src="https://twgljs.org/dist/3.x/twgl-full.min.js"></script>
&#13;
PS:您发布的picture实际上是每个矩形绘制更多三角形。绿色和粉红色之间的区分并不直。
答案 1 :(得分:1)
gl.LINES很好,几乎画了连线。因此lineTo(x,y,z)只会向用于存储行数据的VBO添加一个顶点。 moveTo(x,y,z)只是为了创建一个&#34; break&#34;线之间。这可以通过新的drawArrays调用来完成。