我有以下代码试图通过将恒星放在圆上来绘制花圈。我能够画一颗恒星,但是当我尝试画一块花圈时,只会在圆圈周围或圆圈上的一个点绘制一个分支。我知道我如何嵌套模型视图的方式存在问题,我想不出要进行转换的正确方法。我需要画恒星,然后翻译整个星星。
function DrawWreath()
{
var radius = 0.5;
for (var i = 0; i < 1; i++) {
var theta = i * 30;
var x = radius * Math.cos(theta);
var y = radius * Math.sin(theta);
var t = translate(x, y, 0);
if (modelViewMatrix) {
modelViewMatrix = mult(modelViewMatrix, t) ;
} else {
modelViewMatrix = t;
}
modelViewStack.push(modelViewMatrix);
DrawOneStar();
modelViewMatrix = modelViewStack.pop();
}
}
function DrawOneStar()
{
// draw the full star
for (var i=1; i <= 5; i++) {
r = rotate(72*i, 0, 0, 1);
if (modelViewMatrix) {
modelViewMatrix = mult(r, modelViewMatrix) ;
} else {
modelViewMatrix = r;
}
modelViewMatrix = r;
DrawOneBranch();
}
}
function DrawOneBranch()
{
var s;
// one branch
s = scale4(1/16, 1/16, 1);
modelViewStack.push(modelViewMatrix);
modelViewMatrix = mult(modelViewMatrix, s);
gl.uniformMatrix4fv(modelViewMatrixLoc, false, flatten(modelViewMatrix));
gl.drawArrays( gl.LINE_LOOP, 0, vertices.length);
/*
modelViewMatrix = modelViewStack.pop();
//s = scale4(1/8, -1/8, 1);
modelViewMatrix = mult(modelViewMatrix, s);
gl.uniformMatrix4fv(modelViewMatrixLoc, false, flatten(modelViewMatrix));
gl.drawArrays( gl.LINE_STRIP, 0, vertices.length);
*/
}
代码的许多问题
-
DrawOneStar
中的代码在左侧旋转mult(r, modelViewMatrix) // ???
似乎您想要这个
mult(modelViewMatrix, r)
就像您对
translate
和scale
一样 DrawOneStar
中的代码没有保存矩阵这意味着您要修复代码,以保存矩阵或您要旋转固定量。
由于代码现在旋转72,然后旋转72 144,然后旋转72 144 216,因为每次都在旋转矩阵之前旋转
DrawOneBranch
中的代码没有弹出矩阵该线被评论
theta
使用度大多数数学库都使用弧度,因此此代码可能不做您期望的
var theta = i * 30; var x = radius * Math.cos(theta); var y = radius * Math.sin(theta);
Math.sin
和Math.cos
要求弧度不是学位。外循环仅进行一次迭代
for (var i = 0; i < 1; i++) { // ???
其他建议
-
使用更好的数学库。无论数学库都需要调用
flatten
函数以准备由WebGL使用的矩阵的准备要比不慢的矩阵要慢。还有一个将弧度用于旋转和视场的库,这意味着它将匹配其他内置的数学功能,例如Math.cos
等... -
将
modelViewMatrix
中的矩阵放置。然后,您可以删除所有检查是否存在矩阵 -
在循环和计算值时,请考虑使用归一化数字(数字从0到1的数字),然后基于此计算其他值。
例如,该代码在外循环中具有
theta = i * 30
,在下一个循环中有rotate(i * 72, ...)
,但是如果更改迭代次数,则还必须更改这些数字以匹配。首先根据循环计算从0到1的值。示例
const numStars = 10; for (let i = 0; i < numStars; ++i) { const l = i / numStars; // goes from 0 to 1
然后使用该值计算角度;
const theta = l * 360; // or l * Math.PI * 2 for radians
类似地
const numRotations = 5; for (let i = 0; i < numRotations; ++i) { const l = i / numRotations; // goes from 0 to 1 rotate(i * 360, ....
这样,您可以轻松更改
numStars
和numRotations
而不是必须更改任何其他代码
function DrawWreath()
{
var radius = 0.5;
for (var i = 0; i < 10; i++) {
var theta = i / 10 * Math.PI * 2;
var x = radius * Math.cos(theta);
var y = radius * Math.sin(theta);
var t = translate(x, y, 0);
modelViewStack.push(modelViewMatrix);
modelViewMatrix = mult(modelViewMatrix, t) ;
DrawOneStar();
modelViewMatrix = modelViewStack.pop();
}
}
function DrawOneStar()
{
// draw the full star
for (var i=1; i <= 5; i++) {
var r = rotate(72, 0, 0, 1);
modelViewMatrix = mult(modelViewMatrix, r) ;
DrawOneBranch();
}
}
function DrawOneBranch()
{
var s;
// one branch
s = scale4(1/16, 1/16, 1);
modelViewStack.push(modelViewMatrix);
modelViewMatrix = mult(modelViewMatrix, s);
gl.uniformMatrix4fv(modelViewMatrixLoc, false, flatten(modelViewMatrix));
gl.drawArrays( gl.LINE_LOOP, 0, vertices.length);
modelViewMatrix = modelViewStack.pop();
/*
//s = scale4(1/8, -1/8, 1);
modelViewMatrix = mult(modelViewMatrix, s);
gl.uniformMatrix4fv(modelViewMatrixLoc, false, flatten(modelViewMatrix));
gl.drawArrays( gl.LINE_STRIP, 0, vertices.length);
*/
}
function flatten(m) {
return m;
}
function translate(x, y, z) {
return m4.translation([x, y, z]);
}
function scale4(x, y, z) {
return m4.scaling([x, y, z]);
}
function rotate(a, x, y, z) {
return m4.axisRotation([x, y, z], a * Math.PI / 180);
}
function mult(a, b) {
return m4.multiply(a, b);
}
const m4 = twgl.m4;
const gl = document.querySelector("canvas").getContext("webgl");
const modelViewStack = [];
let modelViewMatrix = m4.identity();
const vs = `
attribute vec4 position;
uniform mat4 u_projectionMatrix;
uniform mat4 u_modelViewMatrix;
void main() {
gl_Position = u_projectionMatrix * u_modelViewMatrix * position;
}
`;
const fs = `
void main() { gl_FragColor = vec4(1,0,0,1); }
`;
const programInfo = twgl.createProgramInfo(gl, [vs, fs]);
const bufferInfo = twgl.createBufferInfoFromArrays(gl, {
position: {
numComponents: 2,
data: [
0, 1,
-.33, 0,
.33, 0,
],
},
});
twgl.resizeCanvasToDisplaySize(gl.canvas);
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
gl.useProgram(programInfo.program);
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
const scale = 1;
twgl.setUniforms(programInfo, {
u_projectionMatrix: m4.ortho(
-aspect / scale, aspect / scale, -1 / scale, 1 / scale, -1, 1),
u_modelViewMatrix: m4.identity(),
});
const vertices = { length: 3, };
const modelViewMatrixLoc = gl.getUniformLocation(programInfo.program, "u_modelViewMatrix");
DrawWreath();
body { margin: 0; }
canvas { width: 100vw; height: 100vh; display: block; }
<script src="https://twgljs.org/dist/3.x/twgl-full.min.js"></script>
<canvas></canvas>
另外一件事,而不是手动计算在cirlce上的位置,您也可以使用矩阵函数,旋转,然后翻译
function DrawWreath()
{
const radius = 0.5;
const numStars = 20;
for (let i = 0; i < numStars; ++i) {
const l = i / numStars;
const theta = l * Math.PI * 2;
const r = rotateInRadians(theta, 0, 0, 1);
const t = translate(radius, 0, 0);
modelViewStack.push(modelViewMatrix);
modelViewMatrix = mult(modelViewMatrix, r);
modelViewMatrix = mult(modelViewMatrix, t);
DrawOneStar();
modelViewMatrix = modelViewStack.pop();
}
}
function DrawOneStar()
{
// draw the full star
const numParts = 6;
for (let i = 0; i < numParts; ++i) {
const l = i / numParts;
const r = rotateInRadians(l * Math.PI * 2, 0, 0, 1);
modelViewStack.push(modelViewMatrix);
modelViewMatrix = mult(modelViewMatrix, r) ;
DrawOneBranch();
modelViewMatrix = modelViewStack.pop();
}
}
function DrawOneBranch()
{
var s;
// one branch
s = scale4(1/16, 1/16, 1);
modelViewStack.push(modelViewMatrix);
modelViewMatrix = mult(modelViewMatrix, s);
gl.uniformMatrix4fv(modelViewMatrixLoc, false, flatten(modelViewMatrix));
gl.drawArrays( gl.LINE_LOOP, 0, vertices.length);
modelViewMatrix = modelViewStack.pop();
}
function flatten(m) {
return m;
}
function translate(x, y, z) {
return m4.translation([x, y, z]);
}
function scale4(x, y, z) {
return m4.scaling([x, y, z]);
}
function rotate(a, x, y, z) {
return m4.axisRotation([x, y, z], a * Math.PI / 180);
}
function rotateInRadians(a, x, y, z) {
return m4.axisRotation([x, y, z], a);
}
function mult(a, b) {
return m4.multiply(a, b);
}
const m4 = twgl.m4;
const gl = document.querySelector("canvas").getContext("webgl");
const modelViewStack = [];
let modelViewMatrix = m4.identity();
const vs = `
attribute vec4 position;
uniform mat4 u_projectionMatrix;
uniform mat4 u_modelViewMatrix;
void main() {
gl_Position = u_projectionMatrix * u_modelViewMatrix * position;
}
`;
const fs = `
void main() { gl_FragColor = vec4(1,0,0,1); }
`;
const programInfo = twgl.createProgramInfo(gl, [vs, fs]);
const bufferInfo = twgl.createBufferInfoFromArrays(gl, {
position: {
numComponents: 2,
data: [
0, 1,
-.33, 0,
.33, 0,
],
},
});
twgl.resizeCanvasToDisplaySize(gl.canvas);
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
gl.useProgram(programInfo.program);
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
const scale = 1;
twgl.setUniforms(programInfo, {
u_projectionMatrix: m4.ortho(
-aspect / scale, aspect / scale, -1 / scale, 1 / scale, -1, 1),
u_modelViewMatrix: m4.identity(),
});
const vertices = { length: 3, };
const modelViewMatrixLoc = gl.getUniformLocation(programInfo.program, "u_modelViewMatrix");
DrawWreath();
body { margin: 0; }
canvas { width: 100vw; height: 100vh; display: block; }
<script src="https://twgljs.org/dist/3.x/twgl-full.min.js"></script>
<canvas></canvas>
您可能会发现这些文章有用