Pas2JS_WebGL_OBJ.pas 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. program Pas2JS_WebGL_OBJ;
  2. uses
  3. Types, Mat4, MemoryBuffer, GLUtils, GLTypes, SysUtils,
  4. BrowserConsole, Web, WebGL, WebGL2, JS, Math;
  5. var
  6. gl: TJSWebGLRenderingContext;
  7. shader: TShader;
  8. projTransform: TMat4;
  9. viewTransform: TMat4;
  10. modelTransform: TMat4;
  11. var
  12. dragonModel: TModel = nil;
  13. rotateAngle: double = 0;
  14. deltaTime: single = 0;
  15. nextTime: single = 0;
  16. procedure DrawCanvas;
  17. begin
  18. gl.clear(gl.COLOR_BUFFER_BIT + gl.DEPTH_BUFFER_BIT);
  19. if dragonModel <> nil then
  20. begin
  21. modelTransform := TMat4.Identity;
  22. modelTransform := modelTransform.Multiply(TMat4.RotateY(DegToRad(rotateAngle)));
  23. shader.SetUniformMat4('modelTransform', modelTransform);
  24. dragonModel.Draw;
  25. end;
  26. end;
  27. procedure AnimateCanvas(time: TDOMHighResTimeStamp);
  28. var
  29. now: single;
  30. list: TScalarArray;
  31. begin
  32. now := time * 0.001;
  33. deltaTime := now - nextTime;
  34. nextTime := now;
  35. rotateAngle := rotateAngle + (20 * deltaTime);
  36. DrawCanvas;
  37. window.requestAnimationFrame(@AnimateCanvas);
  38. end;
  39. procedure StartAnimatingCanvas;
  40. begin
  41. window.requestAnimationFrame(@AnimateCanvas);
  42. end;
  43. type
  44. TModelLoader = class
  45. public
  46. constructor Create (context: TJSWebGLRenderingContext; path: string);
  47. private
  48. gl: TJSWebGLRenderingContext;
  49. request: TJSXMLHttpRequest;
  50. procedure HandleLoaded;
  51. end;
  52. procedure TModelLoader.HandleLoaded;
  53. var
  54. data: TModelData;
  55. begin
  56. if (request.readyState = 4) and (request.status = 200) and (length(request.responseText) > 0) then
  57. begin
  58. data := LoadOBJFile(TJSString(request.responseText));
  59. dragonModel := TModel.Create(gl, data);
  60. StartAnimatingCanvas;
  61. end;
  62. end;
  63. constructor TModelLoader.Create (context: TJSWebGLRenderingContext; path: string);
  64. begin
  65. gl := context;
  66. request := TJSXMLHttpRequest.new;
  67. request.open('GET', path);
  68. request.overrideMimeType('application/text');
  69. request.onreadystatechange := TJSOnReadyStateChangeHandler(@HandleLoaded);
  70. request.send;
  71. end;
  72. var
  73. canvas: TJSHTMLCanvasElement;
  74. i: integer;
  75. stride: integer;
  76. offset: integer;
  77. vertexShaderSource: string;
  78. fragmentShaderSource: string;
  79. buffer: TJSWebGLBuffer;
  80. begin
  81. // make webgl context
  82. canvas := TJSHTMLCanvasElement(document.createElement('canvas'));
  83. canvas.width := 600;
  84. canvas.height := 600;
  85. document.body.appendChild(canvas);
  86. gl := TJSWebGLRenderingContext(canvas.getContext('webgl'));
  87. if gl = nil then
  88. begin
  89. writeln('failed to load webgl!');
  90. exit;
  91. end;
  92. // create shaders from source in html
  93. // TODO: move these to .glsl files so error messages make more sense
  94. // and give valid line numbers
  95. vertexShaderSource := document.getElementById('vertex.glsl').textContent;
  96. fragmentShaderSource := document.getElementById('fragment.glsl').textContent;
  97. shader := TShader.Create(gl, vertexShaderSource, fragmentShaderSource);
  98. shader.Compile;
  99. shader.BindAttribLocation(0, 'in_position');
  100. shader.BindAttribLocation(1, 'in_texCoord');
  101. shader.BindAttribLocation(2, 'in_normal');
  102. shader.Link;
  103. shader.Use;
  104. // prepare context
  105. gl.clearColor(0.9, 0.9, 0.9, 1);
  106. gl.viewport(0, 0, canvas.width, canvas.height);
  107. gl.clear(gl.COLOR_BUFFER_BIT);
  108. gl.enable(gl.DEPTH_TEST);
  109. gl.enable(gl.BLEND);
  110. gl.Enable(gl.CULL_FACE);
  111. gl.CullFace(gl.BACK);
  112. // set projection transform
  113. projTransform := TMat4.Perspective(60.0, canvas.width / canvas.height, 0.1, 2000);
  114. shader.SetUniformMat4('projTransform', projTransform);
  115. // set view transform
  116. viewTransform := TMat4.Identity;
  117. viewTransform := viewTransform.Multiply(TMat4.Translate(0, -3, -20));
  118. shader.SetUniformMat4('viewTransform', viewTransform);
  119. // NOTE: webgl glsl doesn't have the inverse function
  120. // so we need to do this here
  121. shader.SetUniformMat4('inverseViewTransform', viewTransform.Inverse);
  122. // lighting
  123. shader.SetUniformVec3('lightPosition', V3(0, 0, 25));
  124. shader.SetUniformVec3('lightColor', V3(1, 1, 1));
  125. // model material
  126. shader.SetUniformFloat('shineDamper', 10);
  127. shader.SetUniformFloat('reflectivity', 1);
  128. // load obj file
  129. TModelLoader.Create(gl, 'res/dragon.obj');
  130. end.