这是一个非常基本的 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);
canvas { border: 1px solid black; }
<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>
如果您稍后想要点亮它,您还需要 normals(您可以使用这些值来判断某物朝向哪个方向)。我们可以通过添加来添加它们
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);
canvas { border: 1px solid black; }
<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>
PS:您发布的picture 实际上是在每个矩形中绘制更多三角形。绿色和粉红色之间的区别并不直截了当。