我正在尝试用 JavaScript 制作一个 3D 物理引擎,只是为了好玩。
唯一的问题是 3D 渲染,因为我不知道它是如何完成的,所以任何人都可以解释 3D 渲染的想法。
这是一个 3D 透视立方体旋转的示例。
<style>
*{
margin: 0;
}
canvas {
background: black;
}
</style>
<canvas></canvas>
<script>
var canvas = document.querySelector("canvas")
var fov = [120 * Math.PI / 180, 90 * Math.PI / 180]
canvas.width = innerWidth
var dist = (canvas.width / 2) / Math.tan(fov[0] / 2)
canvas.height = (Math.tan(fov[1] / 2) * dist) * 2
if (canvas.height > innerHeight) {
canvas.height = innerHeight
var dist = (canvas.height / 2) / Math.tan(fov[1] / 2)
canvas.width = (Math.tan(fov[0] / 2) * dist) * 2
}
var c = canvas.getContext("2d")
c.fillStyle = "red"
c.strokeStyle = "white"
var solids = []
function rotateX(vector, angle) {
angle = angle * Math.PI / 180
var l = Math.hypot(vector.y, vector.z)
var cAngle = Math.atan2(vector.z, vector.y)
cAngle += angle
vector.y = Math.cos(cAngle) * l
vector.z = Math.sin(cAngle) * l
}
function rotateY(vector, angle) {
angle = angle * Math.PI / 180
var l = Math.hypot(vector.x, vector.z)
var cAngle = Math.atan2(vector.z, vector.x)
cAngle += angle
vector.x = Math.cos(cAngle) * l
vector.z = Math.sin(cAngle) * l
}
function rotateZ(vector, angle) {
angle = angle * Math.PI / 180
var l = Math.hypot(vector.x, vector.y)
var cAngle = Math.atan2(vector.y, vector.x)
cAngle += angle
vector.x = Math.cos(cAngle) * l
vector.y = Math.sin(cAngle) * l
}
class Vertex {
constructor(x, y, z) {
this.x = x,
this.y = y,
this.z = z
}
}
class Cube {
constructor(pos, size) {
this.size = size
this.pos = pos
this.angleX = 0
this.angleY = 0
this.angleZ = 30
this.vertices = []
this.vertices.push(new Vertex(0, 0, 0))
this.vertices.push(new Vertex(size, 0, 0))
this.vertices.push(new Vertex(0, size, 0))
this.vertices.push(new Vertex(0, 0, size))
this.vertices.push(new Vertex(size, size, 0))
this.vertices.push(new Vertex(size, 0, size))
this.vertices.push(new Vertex(0, size, size))
this.vertices.push(new Vertex(size, size, size))
}
draw() {
this.vertices.forEach(v => {
rotateX(v, 1)
rotateY(v, 1)
rotateZ(v, 1)
var d = v.z + this.pos.z
var width = (Math.tan(fov[0] / 2) * d) * 2
var height = (Math.tan(fov[1] / 2) * d) * 2
var x = (width / 2 - v.x - this.pos.x) * canvas.width / width
var y = (height / 2 - v.y - this.pos.y) * canvas.height / height
this.vertices.forEach(v2 => {
var d2 = v2.z + this.pos.z
var width2 = (Math.tan(fov[0] / 2) * d2) * 2
var height2 = (Math.tan(fov[1] / 2) * d2) * 2
var x2 = (width2 / 2 - v2.x - this.pos.x) * canvas.width / width2
var y2 = (height2 / 2 - v2.y - this.pos.y) * canvas.height / height2
this.vertices.forEach(v3 => {
if (v != v2 && v2 != v3) {
var d3 = v3.z + this.pos.z
var width3 = (Math.tan(fov[0] / 2) * d3) * 2
var height3 = (Math.tan(fov[1] / 2) * d3) * 2
var x3 = (width3 / 2 - v3.x - this.pos.x) * canvas.width / width3
var y3 = (height3 / 2 - v3.y - this.pos.y) * canvas.height / height3
c.beginPath()
c.moveTo(x, y)
c.lineTo(x2, y2)
c.lineTo(x3, y3)
c.lineTo(x, y)
c.fillStyle = "red"
c.fill()
}
})
})
})
this.vertices.forEach(v => {
var d = v.z + this.pos.z
var width = (Math.tan(fov[0] / 2) * d) * 2
var height = (Math.tan(fov[1] / 2) * d) * 2
var x = (width / 2 - v.x - this.pos.x) * canvas.width / width
var y = (height / 2 - v.y - this.pos.y) * canvas.height / height
this.vertices.forEach(v2 => {
var d2 = v2.z + this.pos.z
var width2 = (Math.tan(fov[0] / 2) * d2) * 2
var height2 = (Math.tan(fov[1] / 2) * d2) * 2
var x2 = (width2 / 2 - v2.x - this.pos.x) * canvas.width / width2
var y2 = (height2 / 2 - v2.y - this.pos.y) * canvas.height / height2
if (Math.round(Math.hypot(v.x - v2.x, v.y - v2.y, v.z - v2.z)) == this.size) {
var d2 = v2.z + this.pos.z
var width2 = (Math.tan(fov[0] / 2) * d2) * 2
var height2 = (Math.tan(fov[1] / 2) * d2) * 2
var x2 = (width2 / 2 - v2.x - this.pos.x) * canvas.width / width2
var y2 = (height2 / 2 - v2.y - this.pos.y) * canvas.height / height2
c.beginPath()
c.moveTo(x, y)
c.lineTo(x2, y2)
c.stroke()
}
})
c.beginPath()
c.arc(x, y, 3, 0, Math.PI * 2, false)
c.fillStyle = "blue"
//c.fill()
//c.stroke()
})
}
}
solids.push(new Cube({x: 0, y: 0, z: 300}, 50))
function animate() {
requestAnimationFrame(animate)
c.clearRect(0, 0, canvas.width, canvas.height)
solids.forEach(solid => {
solid.draw()
})
}
animate()
我搜索了很多关于解释这一点的文章,但我没有找到任何有用的东西
WebGL 是实现 3D 的方式,所以而不是通常的...
var Cx = C.getContext('2d');
现在变成了...
var Gl = C.getContext('webgl');
if(Gl){
// WebGL is supported so proceed...
}
WebGL 是一个庞大而复杂的世界,您可以在这里开始研究......
https://devdoc.net/web/developer.mozilla.org/en-US/docs/Web/WebGL/Getting_started_with_WebGL.html