#javascript #html #webgl
#javascript #HTML #webgl
Вопрос:
Я новичок в webgl, и я пытался создать два куба, которые вращаются вокруг своей оси, но прямо сейчас они вращаются только по одной оси. Я хотел бы знать, что я делаю не так, (я думаю, это потому, что мне нужно создать новую матрицу модели для поворота, но я не уверен, как это сделать). Спасибо!
// Application info.
var app = app || {};
function initGL()
{
var gl = app.gl;
gl.enable(gl.DEPTH_TEST);
gl.depthFunc(gl.LEQUAL);
gl.viewport(0,0,app.can.width, app.can.height);
gl.clearColor(0.,0.,0., 1.0);
gl.clear(app.gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
var vs = createShaderFromElement(app.gl, "vs");
var fs = createShaderFromElement(app.gl, "fs");
app.progObject = buildProgram(app.gl, vs, fs);
gl.useProgram(app.progObject);
}
function initScene()
{
var gl = app.gl;
// Creer le buffer de geometrie (vertex)
//
var positions = [
// Front face
-1.0, -1.0, 1.0,
1.0, -1.0, 1.0,
1.0, 1.0, 1.0,
1.0, 1.0, 1.0,
-1.0, 1.0, 1.0,
-1.0, -1.0, 1.0,
// Back face
-1.0, -1.0, -1.0,
-1.0, 1.0, -1.0,
1.0, 1.0, -1.0,
1.0, 1.0, -1.0,
1.0, -1.0, -1.0,
-1.0, -1.0, -1.0,
// Top face
-1.0, 1.0, -1.0,
-1.0, 1.0, 1.0,
1.0, 1.0, 1.0,
1.0, 1.0, 1.0,
1.0, 1.0, -1.0,
-1.0, 1.0, -1.0,
// Bottom face
-1.0, -1.0, -1.0,
1.0, -1.0, -1.0,
1.0, -1.0, 1.0,
1.0, -1.0, 1.0,
-1.0, -1.0, 1.0,
-1.0, -1.0, -1.0,
// Right face
1.0, -1.0, -1.0,
1.0, 1.0, -1.0,
1.0, 1.0, 1.0,
1.0, 1.0, 1.0,
1.0, -1.0, 1.0,
1.0, -1.0, -1.0,
// Left face
-1.0, -1.0, -1.0,
-1.0, -1.0, 1.0,
-1.0, 1.0, 1.0,
-1.0, 1.0, 1.0,
-1.0, 1.0, -1.0,
-1.0, -1.0, -1.0
];
app.nPoints = positions.length / 3;
var colors = [
1,1,1, 1,1,1, 1,1,1, 1,1,1, 1,1,1, 1,1,1,
1,0,0, 1,0,0, 1,0,0, 1,0,0, 1,0,0, 1,0,0,
0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0,
0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1,
1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1
];
var loc, buffer;
// Create and copy position buffer.
loc = gl.getAttribLocation(app.progObject, "pos");
buffer = gl.createBuffer();
gl.enableVertexAttribArray(loc);
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.vertexAttribPointer(loc, 3, gl.FLOAT, false /*no normalization*/, 0 /*stride*/, 0 /*offset*/);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
// Create and copy color buffer.
loc = gl.getAttribLocation(app.progObject, "color");
buffer = gl.createBuffer();
gl.enableVertexAttribArray(loc);
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.vertexAttribPointer(loc, 3, gl.FLOAT, false /*no normalization*/, 0 /*stride*/, 0 /*offset*/);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
// Look for uniforms.
app.pmLocation = gl.getUniformLocation(app.progObject, "projMatrix");
app.mmLocation = gl.getUniformLocation(app.progObject, "modelMatrix");
app.vmLocation = gl.getUniformLocation(app.progObject, "viewMatrix");
var mat4 = glMatrix.mat4;
app.projMatrix = mat4.create();
app.modelMatrix = mat4.create();
app.viewMatrix = mat4.create();
mat4.perspective(app.projMatrix, Math.PI / 4.0 /*45 degrees*/, 1, 0.1, 100);
mat4.lookAt(app.viewMatrix, [0, 0, -10], [0, 0, 0], [0, 1, 0]);
}
function animate(time)
{
var gl = app.gl;
var mat4 = glMatrix.mat4;
// converts to seconds.
var seconds = time * 1E-3;
var dtime = time - app.oldTime;
var angle = dtime * 0.001;
mat4.rotateY(app.modelMatrix, app.modelMatrix, angle);
var mm1 = mat4.create();
mat4.translate(mm1, app.modelMatrix, [2, 0, 0]);
app.oldTime = time;
gl.clear(app.gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.uniformMatrix4fv(app.pmLocation, false, app.projMatrix );
gl.uniformMatrix4fv(app.mmLocation, false, mm1 );
gl.uniformMatrix4fv(app.vmLocation, false, app.viewMatrix );
gl.drawArrays(gl.TRIANGLES, 0, app.nPoints);
// Pour dessiner autre cube, calculer autre model matrix
// et redessiner ... gl.drawArrays(gl.TRIANGLES, 0, app.nPoints);
mat4.rotateY( app.modelMatrix, app.modelMatrix, angle)
var mm2 = mat4.create();
mat4.translate(mm2, app.modelMatrix, [-2, 0, 0]);
gl.uniformMatrix4fv(app.pmLocation, false, app.projMatrix);
gl.uniformMatrix4fv(app.mmLocation, false, mm2);
gl.uniformMatrix4fv(app.vmLocation, false, app.viewMatrix);
gl.drawArrays(gl.TRIANGLES, 0, app.nPoints);
window.requestAnimationFrame(animate);
}
function fovChanged(id, value)
{
console.log("FOV Angle: ", value);
var label = document.getElementById( 'output-fov' );
label.innerHTML = value;
}
function farChanged(id, value)
{
console.log("Far Plane: ", value);
var label = document.getElementById( 'output-far' );
label.innerHTML = value;
}
function init()
{
[app.can, app.gl] = getContextGL('can');
if (app.can == null || app.gl == null)
{
alert("Can't init canvas or context");
return;
}
app.can.width = app.can.height * (app.can.clientWidth / app.can.clientHeight);
var rect = app.can.getBoundingClientRect();
app.scaleX = app.can.width / rect.width;
app.scaleY = app.can.height / rect.height;
initGL();
initScene();
app.oldTime = 0;
animate(0);
}
div
{
}
#main-div
{
display:inline-block;
}
#viewport, #manager
{
float: left;
margin: auto;
}
.color
{
width:100px;
height:50px;
}
.blue{
background:#0f0;
}
#viewport
{
width: 600px;
height:700px;
}
#can
{
width: 600px;
height: 500px;
border:1px solid orange;
}
#manager
{
width: 200px;
height:300px;
padding: 0 0 0 5px;
}
#obj-list
{
width: 200px;
}
<!DOCTYPE html>
<html>
<head>
<title>Cube Transform</title>
<link rel="stylesheet" type="text/css" href="style.css">
<script src="transforms.js"></script>
<script src="utils.js"></script>
<script src="gl-matrix-min.js"></script>
<script id="vs" type="x-shader/x-vertex">
precision mediump float;
uniform mat4 projMatrix;
uniform mat4 viewMatrix;
uniform mat4 modelMatrix;
attribute vec3 pos;
attribute vec3 color;
varying vec3 fColor;
void main()
{
fColor = color;
vec4 pt = vec4(pos, 1.0);
gl_Position = projMatrix * viewMatrix * modelMatrix * pt;
}
</script>
<script id="fs" type="x-shader/x-fragment">
precision mediump float;
varying vec3 fColor;
void main()
{
gl_FragColor = vec4(fColor,1);
}
</script>
</head>
<body onload="init();">
<div id="main-div">
<div id="viewport">
<canvas id="can" >Your browser doesn't seem to support canvas!</canvas>
<div class="slider">
<span class="slider-label">FOV cam</span>
<input id="fov" class="slider-input" type="range" min="20" max="90" step="1" value="0" onClick="fovChanged(this.id, this.value)" />
<span id="output-fov" class="slider-value">20</span>
</div>
<div class="slider">
<span class="slider-label">Far Plane</span>
<input id="far" class="slider-input" type="range" min="5" max="30" step="0.1" value="0" onClick="farChanged(this.id, this.value)" />
<span id="output-far" class="slider-value">5</span>
</div>
</div>
</div>
</body>
</html>
Ответ №1:
Я не совсем уверен, что пытается сделать ваш код.
В любом случае, в общем, чтобы повернуть на месте, чтобы перевести, а затем повернуть
mat = idenity
mat = mat * translation
mat = mat * rotation
или в зависимости от библиотеки
mat = identity
translate(mat, ...)
rotate(mat, ...)
или
mat = translation(...);
rotate(mat, ...);
и т.д.
// Application info.
var app = app || {};
function initGL() {
var gl = app.gl;
gl.enable(gl.DEPTH_TEST);
gl.depthFunc(gl.LEQUAL);
gl.viewport(0, 0, app.can.width, app.can.height);
gl.clearColor(0., 0., 0., 1.0);
gl.clear(app.gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
var vs = createShaderFromElement(app.gl, "vs");
var fs = createShaderFromElement(app.gl, "fs");
app.progObject = buildProgram(app.gl, vs, fs);
gl.useProgram(app.progObject);
}
function initScene() {
var gl = app.gl;
// Creer le buffer de geometrie (vertex)
//
var positions = [
// Front face
-1.0, -1.0, 1.0,
1.0, -1.0, 1.0,
1.0, 1.0, 1.0,
1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0,
// Back face
-1.0, -1.0, -1.0, -1.0, 1.0, -1.0,
1.0, 1.0, -1.0,
1.0, 1.0, -1.0,
1.0, -1.0, -1.0, -1.0, -1.0, -1.0,
// Top face
-1.0, 1.0, -1.0, -1.0, 1.0, 1.0,
1.0, 1.0, 1.0,
1.0, 1.0, 1.0,
1.0, 1.0, -1.0, -1.0, 1.0, -1.0,
// Bottom face
-1.0, -1.0, -1.0,
1.0, -1.0, -1.0,
1.0, -1.0, 1.0,
1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0,
// Right face
1.0, -1.0, -1.0,
1.0, 1.0, -1.0,
1.0, 1.0, 1.0,
1.0, 1.0, 1.0,
1.0, -1.0, 1.0,
1.0, -1.0, -1.0,
// Left face
-1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0
];
app.nPoints = positions.length / 3;
var colors = [
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0,
0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0,
0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1,
1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0,
1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1
];
var loc, buffer;
// Create and copy position buffer.
loc = gl.getAttribLocation(app.progObject, "pos");
buffer = gl.createBuffer();
gl.enableVertexAttribArray(loc);
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.vertexAttribPointer(loc, 3, gl.FLOAT, false /*no normalization*/ , 0 /*stride*/ , 0 /*offset*/ );
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
// Create and copy color buffer.
loc = gl.getAttribLocation(app.progObject, "color");
buffer = gl.createBuffer();
gl.enableVertexAttribArray(loc);
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.vertexAttribPointer(loc, 3, gl.FLOAT, false /*no normalization*/ , 0 /*stride*/ , 0 /*offset*/ );
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
// Look for uniforms.
app.pmLocation = gl.getUniformLocation(app.progObject, "projMatrix");
app.mmLocation = gl.getUniformLocation(app.progObject, "modelMatrix");
app.vmLocation = gl.getUniformLocation(app.progObject, "viewMatrix");
var mat4 = glMatrix.mat4;
app.projMatrix = mat4.create();
app.modelMatrix = mat4.create();
app.viewMatrix = mat4.create();
mat4.perspective(app.projMatrix, Math.PI / 4.0 /*45 degrees*/ , 1, 0.1, 100);
mat4.lookAt(app.viewMatrix, [0, 0, -10], [0, 0, 0], [0, 1, 0]);
}
function animate(time) {
var gl = app.gl;
var mat4 = glMatrix.mat4;
// converts to seconds.
var seconds = time * 1E-3;
var dtime = time - app.oldTime;
var mm1 = mat4.create();
mat4.translate(mm1, app.modelMatrix, [2, 0, 0]);
var angle = time * 0.001;
mat4.rotateY(mm1, mm1, angle);
app.oldTime = time;
gl.clear(app.gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.uniformMatrix4fv(app.pmLocation, false, app.projMatrix);
gl.uniformMatrix4fv(app.mmLocation, false, mm1);
gl.uniformMatrix4fv(app.vmLocation, false, app.viewMatrix);
gl.drawArrays(gl.TRIANGLES, 0, app.nPoints);
// Pour dessiner autre cube, calculer autre model matrix
// et redessiner ... gl.drawArrays(gl.TRIANGLES, 0, app.nPoints);
var mm2 = mat4.create();
mat4.translate(mm2, app.modelMatrix, [-2, 0, 0]);
mat4.rotateY(mm2, mm2, angle)
gl.uniformMatrix4fv(app.pmLocation, false, app.projMatrix);
gl.uniformMatrix4fv(app.mmLocation, false, mm2);
gl.uniformMatrix4fv(app.vmLocation, false, app.viewMatrix);
gl.drawArrays(gl.TRIANGLES, 0, app.nPoints);
window.requestAnimationFrame(animate);
}
function fovChanged(id, value) {
console.log("FOV Angle: ", value);
var label = document.getElementById('output-fov');
label.innerHTML = value;
}
function farChanged(id, value) {
console.log("Far Plane: ", value);
var label = document.getElementById('output-far');
label.innerHTML = value;
}
function init() {
[app.can, app.gl] = getContextGL('can');
if (app.can == null || app.gl == null) {
alert("Can't init canvas or context");
return;
}
app.can.width = app.can.height * (app.can.clientWidth / app.can.clientHeight);
var rect = app.can.getBoundingClientRect();
app.scaleX = app.can.width / rect.width;
app.scaleY = app.can.height / rect.height;
initGL();
initScene();
app.oldTime = 0;
animate(0);
}
init();
// -----
function getContextGL(id) {
const can = document.getElementById(id);
const gl = can.getContext('webgl');
return [can, gl];
}
function createShaderFromElement(gl, id) {
const e = document.getElementById(id);
const s = gl.createShader(e.type.indexOf('vertex') >= 0 ? gl.VERTEX_SHADER : gl.FRAGMENT_SHADER);
gl.shaderSource(s, e.text);
gl.compileShader(s);
return s;
}
function buildProgram(gl, vs, fs) {
const p = gl.createProgram();
gl.attachShader(p, vs);
gl.attachShader(p, fs);
gl.linkProgram(p);
return p;
}
div {}
#main-div {
display: inline-block;
}
#viewport,
#manager {
float: left;
margin: auto;
}
.color {
width: 100px;
height: 50px;
}
.blue {
background: #0f0;
}
#viewport {
width: 600px;
height: 700px;
}
#can {
width: 600px;
height: 500px;
border: 1px solid orange;
}
#manager {
width: 200px;
height: 300px;
padding: 0 0 0 5px;
}
#obj-list {
width: 200px;
}
<script src="https://cdn.jsdelivr.net/npm/gl-matrix@3.3.0/gl-matrix-min.js"></script>
<script id="vs" type="x-shader/x-vertex">
precision mediump float;
uniform mat4 projMatrix;
uniform mat4 viewMatrix;
uniform mat4 modelMatrix;
attribute vec3 pos;
attribute vec3 color;
varying vec3 fColor;
void main()
{
fColor = color;
vec4 pt = vec4(pos, 1.0);
gl_Position = projMatrix * viewMatrix * modelMatrix * pt;
}
</script>
<script id="fs" type="x-shader/x-fragment">
precision mediump float;
varying vec3 fColor;
void main()
{
gl_FragColor = vec4(fColor,1);
}
</script>
</head>
<div id="main-div">
<div id="viewport">
<canvas id="can" >Your browser doesn't seem to support canvas!</canvas>
<div class="slider">
<span class="slider-label">FOV cam</span>
<input id="fov" class="slider-input" type="range" min="20" max="90" step="1" value="0" onClick="fovChanged(this.id, this.value)" />
<span id="output-fov" class="slider-value">20</span>
</div>
<div class="slider">
<span class="slider-label">Far Plane</span>
<input id="far" class="slider-input" type="range" min="5" max="30" step="0.1" value="0" onClick="farChanged(this.id, this.value)" />
<span id="output-far" class="slider-value">5</span>
</div>
</div>
</div>
Я бы предложил эти статьи о матрицах в WebGL
Кроме того, пожалуйста, взгляните на то, как сделать ваш фрагмент доступным для выполнения, поскольку доступный для выполнения фрагмент намного полезнее.