-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathdemo.js
148 lines (125 loc) Β· 3.45 KB
/
demo.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
const canvas = document.body.appendChild(document.createElement('canvas'))
const gl = canvas.getContext('webgl')
const perspective = require('gl-mat4/perspective')
const Component = require('kindred-component')
const Camera = require('canvas-orbit-camera')
const Geometry = require('kindred-geometry')
const Shader = require('kindred-shader')
const pressed = require('key-pressed')
const icosphere = require('icosphere')
const Fit = require('canvas-fit')
const bunny = require('bunny')
const Node = require('./')
var prevShader = null
class RenderComponent extends Component('render') {
init (node, props) {
this.node = node
this.geometry = props.geometry
this.shader = props.shader
}
stop () {
this.geometry = null
this.shader = null
this.node = null
}
draw (props) {
var gl = props.gl
if (this.shader !== prevShader) {
this.shader.bind(gl)
this.shader.uniforms.uProj = props.proj
this.shader.uniforms.uView = props.view
prevShader = this.shader
}
this.shader.uniforms.uModel = this.node.modelMatrix
this.geometry.bind(gl, this.shader.attributes)
this.geometry.draw(gl)
}
}
class ControlComponent extends Component('control') {
init (node, props) {
this.node = node
this.speed = props && ('speed' in props) ? props.speed : 1
}
stop () {
this.node = null
}
step () {
var offsetX = pressed('<right>') - pressed('<left>')
var offsetY = pressed('<down>') - pressed('<up>')
this.node.setPosition(
this.node.data.position[0] + offsetX * this.speed,
this.node.data.position[1],
this.node.data.position[2] + offsetY * this.speed
)
}
}
class FollowComponent extends Component('follow') {
init (node, props) {
this.camera = props.camera
this.node = node
}
step () {
this.camera.center[0] += (this.node.data.position[0] - this.camera.center[0]) * 0.1
this.camera.center[1] += (this.node.data.position[1] - this.camera.center[1]) * 0.1
this.camera.center[2] += (this.node.data.position[2] - this.camera.center[2]) * 0.1
}
}
const camera = Camera(canvas)
const view = new Float32Array(16)
const proj = new Float32Array(16)
const root = Node.Scene()
const node = Node({ scale: 0.25 })
const normalShader = Shader`
uniform mat4 uProj;
uniform mat4 uView;
uniform mat4 uModel;
attribute vec3 position;
attribute vec3 normal;
varying vec3 vNorm;
void vert() {
vNorm = normalize(normal);
gl_Position = uProj * uView * uModel * vec4(position, 1);
}
void frag() {
gl_FragColor = vec4(vNorm * 0.5 + 0.5, 1);
}
`
root.add(node)
node.use(ControlComponent, {
speed: 0.25
}).use(RenderComponent, {
geometry: Geometry(bunny).attrFaceNormals('normal'),
shader: normalShader
}).use(FollowComponent, {
camera: camera
})
root.add(Node({
scale: 2
}).use(RenderComponent, {
geometry: Geometry(icosphere(2)).attrFaceNormals('normal'),
shader: normalShader
}))
const state = {
gl: gl,
proj: proj,
view: view
}
render()
function render () {
const width = canvas.width
const height = canvas.height
gl.viewport(0, 0, width, height)
gl.clearColor(0, 0, 0, 1)
gl.clear(gl.COLOR_BUFFER_BIT)
gl.enable(gl.DEPTH_TEST)
gl.enable(gl.CULL_FACE)
camera.view(view)
camera.tick()
perspective(proj, Math.PI / 4, width / height, 0.1, 100)
root._eachStep(state)
root.tick()
root._eachDraw(state)
prevShader = null
window.requestAnimationFrame(render)
}
window.addEventListener('resize', Fit(canvas), false)