webgl2_ubo.html 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <title>three.js WebGL 2 - Uniform Buffer Objects</title>
  5. <meta charset="utf-8">
  6. <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
  7. <link type="text/css" rel="stylesheet" href="main.css">
  8. </head>
  9. <body>
  10. <div id="info">
  11. <a href="http://threejs.org" target="_blank" rel="noopener">three.js</a> - Uniform Buffer Objects
  12. </div>
  13. <div id="container"></div>
  14. <script id="vertexShader1" type="x-shader/x-vertex">
  15. uniform ViewData {
  16. mat4 projectionMatrix;
  17. mat4 viewMatrix;
  18. };
  19. uniform mat4 modelMatrix;
  20. uniform mat3 normalMatrix;
  21. in vec3 position;
  22. in vec3 normal;
  23. out vec3 vPositionEye;
  24. out vec3 vNormalEye;
  25. void main() {
  26. vec4 vertexPositionEye = viewMatrix * modelMatrix * vec4( position, 1.0 );
  27. vPositionEye = vertexPositionEye.xyz;
  28. vNormalEye = normalMatrix * normal;
  29. gl_Position = projectionMatrix * vertexPositionEye;
  30. }
  31. </script>
  32. <script id="fragmentShader1" type="x-shader/x-fragment">
  33. precision highp float;
  34. uniform LightingData {
  35. vec3 position;
  36. vec3 ambientColor;
  37. vec3 diffuseColor;
  38. vec3 specularColor;
  39. float shininess;
  40. } Light;
  41. uniform vec3 color;
  42. in vec3 vPositionEye;
  43. in vec3 vNormalEye;
  44. out vec4 fragColor;
  45. void main() {
  46. // a very basic lighting equation (Phong reflection model) for testing
  47. vec3 l = normalize( Light.position - vPositionEye );
  48. vec3 n = normalize( vNormalEye );
  49. vec3 e = - normalize( vPositionEye );
  50. vec3 r = normalize( reflect( - l, n ) );
  51. float diffuseLightWeighting = max( dot( n, l ), 0.0 );
  52. float specularLightWeighting = max( dot( r, e ), 0.0 );
  53. specularLightWeighting = pow( specularLightWeighting, Light.shininess );
  54. vec3 lightWeighting = Light.ambientColor +
  55. Light.diffuseColor * diffuseLightWeighting +
  56. Light.specularColor * specularLightWeighting;
  57. fragColor = vec4( color.rgb * lightWeighting.rgb, 1.0 );
  58. }
  59. </script>
  60. <script id="vertexShader2" type="x-shader/x-vertex">
  61. uniform ViewData {
  62. mat4 projectionMatrix;
  63. mat4 viewMatrix;
  64. };
  65. uniform mat4 modelMatrix;
  66. in vec3 position;
  67. in vec2 uv;
  68. out vec2 vUv;
  69. void main() {
  70. vUv = uv;
  71. gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4( position, 1.0 );
  72. }
  73. </script>
  74. <script id="fragmentShader2" type="x-shader/x-fragment">
  75. precision highp float;
  76. uniform sampler2D diffuseMap;
  77. in vec2 vUv;
  78. out vec4 fragColor;
  79. void main() {
  80. fragColor = texture( diffuseMap, vUv );
  81. }
  82. </script>
  83. <!-- Import maps polyfill -->
  84. <!-- Remove this when import maps will be widely supported -->
  85. <script async src="https://unpkg.com/[email protected]/dist/es-module-shims.js"></script>
  86. <script type="importmap">
  87. {
  88. "imports": {
  89. "three": "../build/three.module.js"
  90. }
  91. }
  92. </script>
  93. <script type="module">
  94. import * as THREE from 'three';
  95. import WebGL from './jsm/capabilities/WebGL.js';
  96. let camera, scene, renderer, clock;
  97. init();
  98. animate();
  99. function init() {
  100. if ( WebGL.isWebGL2Available() === false ) {
  101. document.body.appendChild( WebGL.getWebGL2ErrorMessage() );
  102. return;
  103. }
  104. const container = document.getElementById( 'container' );
  105. camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.1, 100 );
  106. camera.position.set( 0, 0, 25 );
  107. scene = new THREE.Scene();
  108. camera.lookAt( scene.position );
  109. clock = new THREE.Clock();
  110. // geometry
  111. const geometry1 = new THREE.TetrahedronGeometry();
  112. const geometry2 = new THREE.BoxGeometry();
  113. // texture
  114. const texture = new THREE.TextureLoader().load( 'textures/crate.gif' );
  115. // uniforms groups
  116. // Camera and lighting related data are perfect examples of using UBOs since you have to store these
  117. // data just once. They can be shared across all shader programs.
  118. const cameraUniformsGroup = new THREE.UniformsGroup();
  119. cameraUniformsGroup.setName( 'ViewData' );
  120. cameraUniformsGroup.add( new THREE.Uniform( camera.projectionMatrix ) ); // projection matrix
  121. cameraUniformsGroup.add( new THREE.Uniform( camera.matrixWorldInverse ) ); // view matrix
  122. const lightingUniformsGroup = new THREE.UniformsGroup();
  123. lightingUniformsGroup.setName( 'LightingData' );
  124. lightingUniformsGroup.add( new THREE.Uniform( new THREE.Vector3( 0, 0, 10 ) ) ); // light position
  125. lightingUniformsGroup.add( new THREE.Uniform( new THREE.Color( 0x333333 ) ) ); // ambient color
  126. lightingUniformsGroup.add( new THREE.Uniform( new THREE.Color( 0xaaaaaa ) ) ); // diffuse color
  127. lightingUniformsGroup.add( new THREE.Uniform( new THREE.Color( 0xcccccc ) ) ); // specular color
  128. lightingUniformsGroup.add( new THREE.Uniform( 64 ) ); // shininess
  129. // materials
  130. const material1 = new THREE.RawShaderMaterial( {
  131. uniforms: {
  132. modelMatrix: { value: null },
  133. normalMatrix: { value: null },
  134. color: { value: null }
  135. },
  136. vertexShader: document.getElementById( 'vertexShader1' ).textContent,
  137. fragmentShader: document.getElementById( 'fragmentShader1' ).textContent,
  138. glslVersion: THREE.GLSL3
  139. } );
  140. const material2 = new THREE.RawShaderMaterial( {
  141. uniforms: {
  142. modelMatrix: { value: null },
  143. diffuseMap: { value: null },
  144. },
  145. vertexShader: document.getElementById( 'vertexShader2' ).textContent,
  146. fragmentShader: document.getElementById( 'fragmentShader2' ).textContent,
  147. glslVersion: THREE.GLSL3
  148. } );
  149. // meshes
  150. for ( let i = 0; i < 200; i ++ ) {
  151. let mesh;
  152. if ( i % 2 === 0 ) {
  153. mesh = new THREE.Mesh( geometry1, material1.clone() );
  154. mesh.material.uniformsGroups = [ cameraUniformsGroup, lightingUniformsGroup ];
  155. mesh.material.uniforms.modelMatrix.value = mesh.matrixWorld;
  156. mesh.material.uniforms.normalMatrix.value = mesh.normalMatrix;
  157. mesh.material.uniforms.color.value = new THREE.Color( 0xffffff * Math.random() );
  158. } else {
  159. mesh = new THREE.Mesh( geometry2, material2.clone() );
  160. mesh.material.uniformsGroups = [ cameraUniformsGroup ];
  161. mesh.material.uniforms.modelMatrix.value = mesh.matrixWorld;
  162. mesh.material.uniforms.diffuseMap.value = texture;
  163. }
  164. scene.add( mesh );
  165. const s = 1 + Math.random() * 0.5;
  166. mesh.scale.x = s;
  167. mesh.scale.y = s;
  168. mesh.scale.z = s;
  169. mesh.rotation.x = Math.random() * Math.PI;
  170. mesh.rotation.y = Math.random() * Math.PI;
  171. mesh.rotation.z = Math.random() * Math.PI;
  172. mesh.position.x = Math.random() * 40 - 20;
  173. mesh.position.y = Math.random() * 40 - 20;
  174. mesh.position.z = Math.random() * 20 - 10;
  175. }
  176. //
  177. renderer = new THREE.WebGLRenderer( { antialias: true } );
  178. renderer.setPixelRatio( window.devicePixelRatio );
  179. renderer.setSize( window.innerWidth, window.innerHeight );
  180. container.appendChild( renderer.domElement );
  181. window.addEventListener( 'resize', onWindowResize, false );
  182. }
  183. function onWindowResize() {
  184. camera.aspect = window.innerWidth / window.innerHeight;
  185. camera.updateProjectionMatrix();
  186. renderer.setSize( window.innerWidth, window.innerHeight );
  187. }
  188. //
  189. function animate() {
  190. requestAnimationFrame( animate );
  191. const delta = clock.getDelta();
  192. scene.traverse( function ( child ) {
  193. if ( child.isMesh ) {
  194. child.rotation.x += delta * 0.5;
  195. child.rotation.y += delta * 0.3;
  196. }
  197. } );
  198. renderer.render( scene, camera );
  199. }
  200. </script>
  201. </body>
  202. </html>