WebGL Tessellate - 每个三角形的特定颜色模式
WebGL Tessellate - Specific colour pattern for each triangle
我目前正在尝试自学 WebGL 并专门创建一个 Tessellate 应用程序。
我试过颜色,现在整个三角形都有彩虹效果,不会随着曲面细分而改变:
<script id="vertex-shader" type="x-shader/x-vertex">
attribute vec4 vPosition;
uniform vec4 u_offset;
varying vec4 v_positionWithOffset;
void main() {
gl_Position = vPosition + u_offset;
v_positionWithOffset = vPosition + u_offset;
}
</script>
<script id="fragment-shader" type="x-shader/x-fragment">
precision mediump float;
varying vec4 v_positionWithOffset;
void main() {
vec4 color = v_positionWithOffset * 0.99 + 0.75;
gl_FragColor = color;
}
</script>
我真正想做的是在每个三角形分开时分别给它上色。由于使用块色效果不可见,我想使用某种任意配色方案为每个三角形着色,因此每个三角形的中心是一个阴影,外面是另一个(可能更暗)阴影。
我将如何实施它?
提前致谢!
首先,在 WebGL 中为任何东西着色的最明显的方法是使用纹理和纹理坐标,但我相信你知道这一点。
否则,如果您想为中心涂上一种颜色,而边缘则不同,这是一个基于 this article.
的想法
我们可以将他所谓的重心添加到每个三角形的每个顶点。
triangle vertex 0: 1, 0, 0
triangle vertex 1: 0, 1, 0
triangle vertex 2: 0, 0, 1
我们现在有了在每个三角形上插值的值,每个点对应于它的对边。我们可以在着色器中使用它。这是一个想法。这使中心变白。
precision mediump float;
#define PI radians(180.0)
varying vec4 v_color;
varying vec3 v_barycentric;
uniform float u_fudge;
uniform float u_sharpness;
void main() {
vec3 t = sin(v_barycentric * PI);
float center = pow(t.x * t.y * t.z * u_fudge, u_sharpness);
gl_FragColor = mix(v_color, vec4(1,1,1,1), center);
}
示例:
var positions = [];
var colors = [];
var barycentrics = [];
var subDivisions = 3;
for (var yy = 0; yy < subDivisions; ++yy) {
// making the positions in clip space so no extra
// math needed in shader
var y0 = (yy + 0) / subDivisions * 2 - 1;
var y1 = (yy + 1) / subDivisions * 2 - 1;
for (var xx = 0; xx < subDivisions; ++xx) {
var x0 = (xx + 0) / subDivisions * 2 - 1;
var x1 = (xx + 1) / subDivisions * 2 - 1;
// pick a random color
var r = Math.random();
var g = Math.random();
var b = Math.random();
// make a triangle
positions.push(x0, y0);
positions.push(x1, y0);
positions.push(x0, y1);
// and it's colors, one for each triangle vertex
colors.push(r, g, b);
colors.push(r, g, b);
colors.push(r, g, b);
barycentrics.push(1, 0, 0);
barycentrics.push(0, 1, 0);
barycentrics.push(0, 0, 1);
// pick a random color
r = Math.random();
g = Math.random();
b = Math.random();
// make a triangle
positions.push(x0, y1);
positions.push(x1, y0);
positions.push(x1, y1);
// and it's colors, one for each triangle vertex
colors.push(r, g, b);
colors.push(r, g, b);
colors.push(r, g, b);
barycentrics.push(1, 0, 0);
barycentrics.push(0, 1, 0);
barycentrics.push(0, 0, 1);
}
}
var gl = twgl.getWebGLContext(document.getElementById("c"));
var programInfo = twgl.createProgramInfo(gl, ["vs", "fs"]);
var arrays = {
position: { numComponents: 2, data: positions },
color: { numComponents: 3, data: colors },
barycentric: { numComponents: 3, data: barycentrics },
};
var bufferInfo = twgl.createBufferInfoFromArrays(gl, arrays);
var uniforms = {
u_fudge: 1,
u_sharpness: 1,
};
function render() {
gl.useProgram(programInfo.program);
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
twgl.setUniforms(programInfo, uniforms);
twgl.drawBufferInfo(gl, gl.TRIANGLES, bufferInfo);
}
render();
document.querySelectorAll("input[type=range]").forEach(function(elem) {
elem.addEventListener('input', function(event) {
var id = event.target.id;
uniforms["u_" + id] = event.target.value / 100;
render();
});
});
<script src="https://twgljs.org/dist/twgl.min.js"></script>
<script id="vs" type="notjs">
attribute vec4 position;
attribute vec4 color;
attribute vec3 barycentric;
varying vec4 v_color;
varying vec3 v_barycentric;
void main() {
gl_Position = position;
v_color = color;
v_barycentric = barycentric;
}
</script>
<script id="fs" type="notjs">
precision mediump float;
#define PI radians(180.0)
varying vec4 v_color;
varying vec3 v_barycentric;
uniform float u_fudge;
uniform float u_sharpness;
void main() {
vec3 t = sin(v_barycentric * PI);
float center = pow(t.x * t.y * t.z * u_fudge, u_sharpness);
gl_FragColor = mix(v_color, vec4(1,1,1,1), center);
}
</script>
<canvas id="c"></canvas>
<div id="ui">
<label for="fudge">fudge</label>
<input id="fudge" type="range" min="0" max="500" value="100" />
<label for="sharpness">sharpness</label>
<input id="sharpness" type="range" min="0" max="500" value="100" />
</div>
我们可以为 2 种颜色传递 2 种制服,或者使用两组顶点颜色或从 2 种纹理中采样。
我目前正在尝试自学 WebGL 并专门创建一个 Tessellate 应用程序。
我试过颜色,现在整个三角形都有彩虹效果,不会随着曲面细分而改变:
<script id="vertex-shader" type="x-shader/x-vertex">
attribute vec4 vPosition;
uniform vec4 u_offset;
varying vec4 v_positionWithOffset;
void main() {
gl_Position = vPosition + u_offset;
v_positionWithOffset = vPosition + u_offset;
}
</script>
<script id="fragment-shader" type="x-shader/x-fragment">
precision mediump float;
varying vec4 v_positionWithOffset;
void main() {
vec4 color = v_positionWithOffset * 0.99 + 0.75;
gl_FragColor = color;
}
</script>
我真正想做的是在每个三角形分开时分别给它上色。由于使用块色效果不可见,我想使用某种任意配色方案为每个三角形着色,因此每个三角形的中心是一个阴影,外面是另一个(可能更暗)阴影。
我将如何实施它?
提前致谢!
首先,在 WebGL 中为任何东西着色的最明显的方法是使用纹理和纹理坐标,但我相信你知道这一点。
否则,如果您想为中心涂上一种颜色,而边缘则不同,这是一个基于 this article.
的想法我们可以将他所谓的重心添加到每个三角形的每个顶点。
triangle vertex 0: 1, 0, 0
triangle vertex 1: 0, 1, 0
triangle vertex 2: 0, 0, 1
我们现在有了在每个三角形上插值的值,每个点对应于它的对边。我们可以在着色器中使用它。这是一个想法。这使中心变白。
precision mediump float;
#define PI radians(180.0)
varying vec4 v_color;
varying vec3 v_barycentric;
uniform float u_fudge;
uniform float u_sharpness;
void main() {
vec3 t = sin(v_barycentric * PI);
float center = pow(t.x * t.y * t.z * u_fudge, u_sharpness);
gl_FragColor = mix(v_color, vec4(1,1,1,1), center);
}
示例:
var positions = [];
var colors = [];
var barycentrics = [];
var subDivisions = 3;
for (var yy = 0; yy < subDivisions; ++yy) {
// making the positions in clip space so no extra
// math needed in shader
var y0 = (yy + 0) / subDivisions * 2 - 1;
var y1 = (yy + 1) / subDivisions * 2 - 1;
for (var xx = 0; xx < subDivisions; ++xx) {
var x0 = (xx + 0) / subDivisions * 2 - 1;
var x1 = (xx + 1) / subDivisions * 2 - 1;
// pick a random color
var r = Math.random();
var g = Math.random();
var b = Math.random();
// make a triangle
positions.push(x0, y0);
positions.push(x1, y0);
positions.push(x0, y1);
// and it's colors, one for each triangle vertex
colors.push(r, g, b);
colors.push(r, g, b);
colors.push(r, g, b);
barycentrics.push(1, 0, 0);
barycentrics.push(0, 1, 0);
barycentrics.push(0, 0, 1);
// pick a random color
r = Math.random();
g = Math.random();
b = Math.random();
// make a triangle
positions.push(x0, y1);
positions.push(x1, y0);
positions.push(x1, y1);
// and it's colors, one for each triangle vertex
colors.push(r, g, b);
colors.push(r, g, b);
colors.push(r, g, b);
barycentrics.push(1, 0, 0);
barycentrics.push(0, 1, 0);
barycentrics.push(0, 0, 1);
}
}
var gl = twgl.getWebGLContext(document.getElementById("c"));
var programInfo = twgl.createProgramInfo(gl, ["vs", "fs"]);
var arrays = {
position: { numComponents: 2, data: positions },
color: { numComponents: 3, data: colors },
barycentric: { numComponents: 3, data: barycentrics },
};
var bufferInfo = twgl.createBufferInfoFromArrays(gl, arrays);
var uniforms = {
u_fudge: 1,
u_sharpness: 1,
};
function render() {
gl.useProgram(programInfo.program);
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
twgl.setUniforms(programInfo, uniforms);
twgl.drawBufferInfo(gl, gl.TRIANGLES, bufferInfo);
}
render();
document.querySelectorAll("input[type=range]").forEach(function(elem) {
elem.addEventListener('input', function(event) {
var id = event.target.id;
uniforms["u_" + id] = event.target.value / 100;
render();
});
});
<script src="https://twgljs.org/dist/twgl.min.js"></script>
<script id="vs" type="notjs">
attribute vec4 position;
attribute vec4 color;
attribute vec3 barycentric;
varying vec4 v_color;
varying vec3 v_barycentric;
void main() {
gl_Position = position;
v_color = color;
v_barycentric = barycentric;
}
</script>
<script id="fs" type="notjs">
precision mediump float;
#define PI radians(180.0)
varying vec4 v_color;
varying vec3 v_barycentric;
uniform float u_fudge;
uniform float u_sharpness;
void main() {
vec3 t = sin(v_barycentric * PI);
float center = pow(t.x * t.y * t.z * u_fudge, u_sharpness);
gl_FragColor = mix(v_color, vec4(1,1,1,1), center);
}
</script>
<canvas id="c"></canvas>
<div id="ui">
<label for="fudge">fudge</label>
<input id="fudge" type="range" min="0" max="500" value="100" />
<label for="sharpness">sharpness</label>
<input id="sharpness" type="range" min="0" max="500" value="100" />
</div>
我们可以为 2 种颜色传递 2 种制服,或者使用两组顶点颜色或从 2 种纹理中采样。