Pas2JS_WebGL_OBJ.pas 3.8 KB

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