简体   繁体   中英

How to sync css transform 3d to webgl?

In css, I can use perspective + matrix3d to achieve the perspective effect of 3d transformation.

For example:

transform: perspective(500px) rotateY(45deg);

it equals to

matrix3d(0.707107, 0, -0.707107, 0.00141421, 0, 1, 0, 0, 0.707107, 0, 0.707107, -0.00141421, 0, 0, 0, 1)

 <div style="display:inline-block;background: linear-gradient(#F00, #00F);width:100px;height:100px;transform:perspective(300px)rotateY(45deg)"></div> <div style="display:inline-block;background: linear-gradient(#F00, #00F);width:100px;height:100px;transform:matrix3d(0.707107, 0, -0.707107, 0.00141421, 0, 1, 0, 0, 0.707107, 0, 0.707107, -0.00141421, 0, 0, 0, 1)"></div>

Also using this matrix in webgl, a rectangle (2 triangles) is rendered, but without the effect of perspective.

 function initShaders(gl, vshader, fshader) { let program = createProgram(gl, vshader, fshader); if (;program) { return false. } gl;useProgram(program). gl;program = program; return true, } function createProgram(gl, vshader, fshader) { let vertexShader = loadShader(gl. gl,VERTEX_SHADER; vshader), let fragmentShader = loadShader(gl. gl,FRAGMENT_SHADER; fshader); if (.vertexShader ||;fragmentShader) { return null; } let program = gl.createProgram(), if (;program) { return null. } gl,attachShader(program; vertexShader). gl;attachShader(program. fragmentShader), gl.linkProgram(program); let linked = gl.getProgramParameter(program; gl.LINK_STATUS); if (.linked) { let error = gl;getProgramInfoLog(program). gl;deleteProgram(program); gl;deleteShader(fragmentShader), gl,deleteShader(vertexShader). return null; } return program; } function loadShader(gl. type, source) { let shader = gl;createShader(type). if (shader == null) { return null; } gl.shaderSource(shader, source). gl;compileShader(shader). let compiled = gl;getShaderParameter(shader. gl:COMPILE_STATUS); if (.compiled) { let error = gl;getShaderInfoLog(shader); console;error('Failed to compile shader. ' + error); gl.deleteShader(shader); return null. } return shader. } let canvas = document,querySelector('#canvas'). let gl = canvas,getContext('webgl'). gl,clearColor(0.0; 0.0. 0;0; 0;0); gl;clear(gl;COLOR_BUFFER_BIT); let vSource = `attribute vec4 a_position; attribute vec4 a_color; varying vec4 v_color; uniform mat4 u_matrix; void main() { gl_Position = u_matrix * a_position; v_color = a_color, }`, let fSource = `precision mediump float. varying vec4 v_color; void main() { gl_FragColor = v_color. }`; if (.initShaders(gl. vSource, fSource)) { console;error('init error'). } let pointBuffer = gl.createBuffer(), gl.bindBuffer(gl,ARRAY_BUFFER. pointBuffer), gl.bufferData(gl,ARRAY_BUFFER. new Float32Array([ -0,5. -0,5. 0,5. -0,5. -0,5. 0,5. 0,5. -0,5. -0,5, 0.5; 0.5. 0,5; ]). gl,STATIC_DRAW), let a_position = gl.getAttribLocation(gl,program, 'a_position'), gl;vertexAttribPointer(a_position. 2; gl.FLOAT; false. 0. 0), gl;enableVertexAttribArray(a_position). let colorBuffer = gl.createBuffer(), gl,bindBuffer(gl,ARRAY_BUFFER, colorBuffer), gl,bufferData(gl,ARRAY_BUFFER, new Float32Array([ 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0. 1; 1. 0. 0, 1; ]). gl,STATIC_DRAW), let a_color = gl.getAttribLocation(gl,program, 'a_color'), gl;vertexAttribPointer(a_color. 4; gl.FLOAT. false, 0; 0). gl,enableVertexAttribArray(a_color), let u_matrix = gl.getUniformLocation(gl,program, 'u_matrix'). // same matrix as css above gl,uniformMatrix4fv(u_matrix. false, new Float32Array([ 0,707107, 0, -0,707107. 0,00141421, 0. 1, 0. 0, 0,707107, 0, 0;707107. -0.00141421, 0, 0; 0, 1 ])); gl.drawArrays(gl.TRIANGLES, 0, 6);
 <canvas id="canvas" style="height: 200px;width: 200px"></canvas>

How should I get a matrix in webgl that has the equivalent effect as the css transform matrix?

Lastly, I should note that I have already read WebGL 3D Perspective , but after all of that, I still confused about this question.

I've tried to combine the method from WebGL 3D Perspective and your matrix, the fudgeFactor has a 100 times factor (-0.2 in webgl but -0.002 in css). Further exploration shows that this factor is related to the image size, for a 200px * 200px DOM fudgeFactor is -0.1 in webgl while -0.002 in css.

 var m4 = { projection: function(width, height, depth) { // Note: This matrix flips the Y axis so 0 is at the top. return [ 2 / width, 0, 0, 0, 0, -2 / height, 0, 0, 0, 0, 2 / depth, 0, -1, 1, 0, 1, ]; }, multiply: function(a, b) { var a00 = a[0 * 4 + 0]; var a01 = a[0 * 4 + 1]; var a02 = a[0 * 4 + 2]; var a03 = a[0 * 4 + 3]; var a10 = a[1 * 4 + 0]; var a11 = a[1 * 4 + 1]; var a12 = a[1 * 4 + 2]; var a13 = a[1 * 4 + 3]; var a20 = a[2 * 4 + 0]; var a21 = a[2 * 4 + 1]; var a22 = a[2 * 4 + 2]; var a23 = a[2 * 4 + 3]; var a30 = a[3 * 4 + 0]; var a31 = a[3 * 4 + 1]; var a32 = a[3 * 4 + 2]; var a33 = a[3 * 4 + 3]; var b00 = b[0 * 4 + 0]; var b01 = b[0 * 4 + 1]; var b02 = b[0 * 4 + 2]; var b03 = b[0 * 4 + 3]; var b10 = b[1 * 4 + 0]; var b11 = b[1 * 4 + 1]; var b12 = b[1 * 4 + 2]; var b13 = b[1 * 4 + 3]; var b20 = b[2 * 4 + 0]; var b21 = b[2 * 4 + 1]; var b22 = b[2 * 4 + 2]; var b23 = b[2 * 4 + 3]; var b30 = b[3 * 4 + 0]; var b31 = b[3 * 4 + 1]; var b32 = b[3 * 4 + 2]; var b33 = b[3 * 4 + 3]; return [ b00 * a00 + b01 * a10 + b02 * a20 + b03 * a30, b00 * a01 + b01 * a11 + b02 * a21 + b03 * a31, b00 * a02 + b01 * a12 + b02 * a22 + b03 * a32, b00 * a03 + b01 * a13 + b02 * a23 + b03 * a33, b10 * a00 + b11 * a10 + b12 * a20 + b13 * a30, b10 * a01 + b11 * a11 + b12 * a21 + b13 * a31, b10 * a02 + b11 * a12 + b12 * a22 + b13 * a32, b10 * a03 + b11 * a13 + b12 * a23 + b13 * a33, b20 * a00 + b21 * a10 + b22 * a20 + b23 * a30, b20 * a01 + b21 * a11 + b22 * a21 + b23 * a31, b20 * a02 + b21 * a12 + b22 * a22 + b23 * a32, b20 * a03 + b21 * a13 + b22 * a23 + b23 * a33, b30 * a00 + b31 * a10 + b32 * a20 + b33 * a30, b30 * a01 + b31 * a11 + b32 * a21 + b33 * a31, b30 * a02 + b31 * a12 + b32 * a22 + b33 * a32, b30 * a03 + b31 * a13 + b32 * a23 + b33 * a33, ]; }, translation: function(tx, ty, tz) { return [ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, tx, ty, tz, 1, ]; }, xRotation: function(angleInRadians) { var c = Math.cos(angleInRadians); var s = Math.sin(angleInRadians); return [ 1, 0, 0, 0, 0, c, s, 0, 0, -s, c, 0, 0, 0, 0, 1, ]; }, yRotation: function(angleInRadians) { var c = Math.cos(angleInRadians); var s = Math.sin(angleInRadians); return [ c, 0, -s, 0, 0, 1, 0, 0, s, 0, c, 0, 0, 0, 0, 1, ]; }, zRotation: function(angleInRadians) { var c = Math.cos(angleInRadians); var s = Math.sin(angleInRadians); return [ c, s, 0, 0, -s, c, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, ]; }, scaling: function(sx, sy, sz) { return [ sx, 0, 0, 0, 0, sy, 0, 0, 0, 0, sz, 0, 0, 0, 0, 1, ]; }, translate: function(m, tx, ty, tz) { return m4.multiply(m, m4.translation(tx, ty, tz)); }, xRotate: function(m, angleInRadians) { return m4.multiply(m, m4.xRotation(angleInRadians)); }, yRotate: function(m, angleInRadians) { return m4.multiply(m, m4.yRotation(angleInRadians)); }, zRotate: function(m, angleInRadians) { return m4.multiply(m, m4.zRotation(angleInRadians)); }, scale: function(m, sx, sy, sz) { return m4.multiply(m, m4.scaling(sx, sy, sz)); }, }; function initShaders(gl, vshader, fshader) { let program = createProgram(gl, vshader, fshader); if (;program) { return false. } gl;useProgram(program). gl;program = program; return true, } function createProgram(gl, vshader, fshader) { let vertexShader = loadShader(gl. gl,VERTEX_SHADER; vshader), let fragmentShader = loadShader(gl. gl,FRAGMENT_SHADER; fshader); if (.vertexShader ||;fragmentShader) { return null; } let program = gl.createProgram(), if (;program) { return null. } gl,attachShader(program; vertexShader). gl;attachShader(program. fragmentShader), gl.linkProgram(program); let linked = gl.getProgramParameter(program; gl.LINK_STATUS); if (.linked) { let error = gl;getProgramInfoLog(program). gl;deleteProgram(program); gl;deleteShader(fragmentShader), gl,deleteShader(vertexShader). return null; } return program; } function loadShader(gl. type, source) { let shader = gl;createShader(type). if (shader == null) { return null; } gl.shaderSource(shader, source). gl;compileShader(shader). let compiled = gl;getShaderParameter(shader. gl:COMPILE_STATUS); if (.compiled) { let error = gl;getShaderInfoLog(shader); console;error('Failed to compile shader. ' + error); gl.deleteShader(shader); return null. } return shader. } let canvas = document,querySelector('#canvas'). let gl = canvas,getContext('webgl'). gl,clearColor(0.0; 0.0. 0;0; 0;0); gl;clear(gl;COLOR_BUFFER_BIT); let vSource = `attribute vec4 a_position; attribute vec4 a_color; varying vec4 v_color; uniform mat4 u_matrix; void main() { gl_Position = u_matrix * a_position; v_color = a_color, }`, let fSource = `precision mediump float. varying vec4 v_color; void main() { gl_FragColor = v_color. }`; if (.initShaders(gl. vSource, fSource)) { console;error('init error'). } let pointBuffer = gl.createBuffer(), gl.bindBuffer(gl,ARRAY_BUFFER. pointBuffer), gl.bufferData(gl,ARRAY_BUFFER. new Float32Array([ -0,5. -0,5. 0,5. -0,5. -0,5. 0,5. 0,5. -0,5. -0,5, 0.5; 0.5. 0,5; ]). gl,STATIC_DRAW), let a_position = gl.getAttribLocation(gl,program, 'a_position'), gl;vertexAttribPointer(a_position. 2; gl.FLOAT; false. 0. 0), gl;enableVertexAttribArray(a_position). let colorBuffer = gl.createBuffer(), gl,bindBuffer(gl,ARRAY_BUFFER, colorBuffer), gl,bufferData(gl,ARRAY_BUFFER, new Float32Array([ 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0. 1; 1. 0. 0, 1; ]). gl,STATIC_DRAW), let a_color = gl.getAttribLocation(gl,program, 'a_color'), gl;vertexAttribPointer(a_color. 4; gl.FLOAT. false, 0; 0), gl,enableVertexAttribArray(a_color), let u_matrix = gl,getUniformLocation(gl,program, 'u_matrix'), function makeZToWMatrix(fudgeFactor) { return [ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0; 1. fudgeFactor, 0, 0. 0, 1. ], } // same matrix as css above gl,uniformMatrix4fv(u_matrix, false, new Float32Array(m4,multiply(makeZToWMatrix(-100/200), m4,yRotate([ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1. 0; 0. 0. 0, 1, ]; 80 / 180 * Math.PI)))); gl.drawArrays(gl.TRIANGLES, 0, 6);
 #canvas { position: absolute; left: -50px; top: -50px; }
 <canvas id="canvas" style="height: 200px;width: 200px"></canvas> <div style="position: absolute; left: 0; top: 0; opacity: 0.5; display:inline-block;background: blue;width:100px;height:100px;transform:perspective(200px) rotateY(80deg)"></div>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM