mesh.go 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. // Copyright 2016 The G3N Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package graphic
  5. import (
  6. "github.com/g3n/engine/core"
  7. "github.com/g3n/engine/geometry"
  8. "github.com/g3n/engine/gls"
  9. "github.com/g3n/engine/material"
  10. "github.com/g3n/engine/math32"
  11. )
  12. // Mesh is a Graphic with uniforms for the model, view, projection, and normal matrices.
  13. type Mesh struct {
  14. Graphic // Embedded graphic
  15. uniMVM gls.Uniform // Model view matrix uniform location cache
  16. uniMVPM gls.Uniform // Model view projection matrix uniform cache
  17. uniNM gls.Uniform // Normal matrix uniform cache
  18. }
  19. // NewMesh creates and returns a pointer to a mesh with the specified geometry and material.
  20. // If the mesh has multi materials, the material specified here must be nil and the
  21. // individual materials must be add using "AddMaterial" or AddGroupMaterial".
  22. func NewMesh(igeom geometry.IGeometry, imat material.IMaterial) *Mesh {
  23. m := new(Mesh)
  24. m.Init(igeom, imat)
  25. return m
  26. }
  27. // Init initializes the Mesh and its uniforms
  28. func (m *Mesh) Init(igeom geometry.IGeometry, imat material.IMaterial) {
  29. m.Graphic.Init(igeom, gls.TRIANGLES)
  30. // Initialize uniforms
  31. m.uniMVM.Init("ModelViewMatrix")
  32. m.uniMVPM.Init("MVP")
  33. m.uniNM.Init("NormalMatrix")
  34. // Adds single material if not nil
  35. if imat != nil {
  36. m.AddMaterial(imat, 0, 0)
  37. }
  38. }
  39. // AddMaterial adds a material for the specified subset of vertices
  40. func (m *Mesh) AddMaterial(imat material.IMaterial, start, count int) {
  41. m.Graphic.AddMaterial(m, imat, start, count)
  42. }
  43. // AddGroupMaterial adds a material for the specified geometry group
  44. func (m *Mesh) AddGroupMaterial(imat material.IMaterial, gindex int) {
  45. m.Graphic.AddGroupMaterial(m, imat, gindex)
  46. }
  47. // RenderSetup is called by the engine before drawing the mesh geometry
  48. // It is responsible to updating the current shader uniforms with
  49. // the model matrices.
  50. func (m *Mesh) RenderSetup(gs *gls.GLS, rinfo *core.RenderInfo) {
  51. // Calculates model view matrix and transfer uniform
  52. mw := m.MatrixWorld()
  53. var mvm math32.Matrix4
  54. mvm.MultiplyMatrices(&rinfo.ViewMatrix, &mw)
  55. location := m.uniMVM.Location(gs)
  56. gs.UniformMatrix4fv(location, 1, false, &mvm[0])
  57. // Calculates model view projection matrix and updates uniform
  58. var mvpm math32.Matrix4
  59. mvpm.MultiplyMatrices(&rinfo.ProjMatrix, &mvm)
  60. location = m.uniMVPM.Location(gs)
  61. gs.UniformMatrix4fv(location, 1, false, &mvpm[0])
  62. // Calculates normal matrix and updates uniform
  63. var nm math32.Matrix3
  64. nm.GetNormalMatrix(&mvm)
  65. location = m.uniNM.Location(gs)
  66. gs.UniformMatrix3fv(location, 1, false, &nm[0])
  67. }
  68. // Raycast checks intersections between this geometry and the specified raycaster
  69. // and if any found appends it to the specified intersects array.
  70. func (m *Mesh) Raycast(rc *core.Raycaster, intersects *[]core.Intersect) {
  71. // Transform this mesh geometry bounding sphere from model
  72. // to world coordinates and checks intersection with raycaster
  73. geom := m.GetGeometry()
  74. sphere := geom.BoundingSphere()
  75. matrixWorld := m.MatrixWorld()
  76. sphere.ApplyMatrix4(&matrixWorld)
  77. if !rc.IsIntersectionSphere(&sphere) {
  78. return
  79. }
  80. // Copy ray and transform to model coordinates
  81. // This ray will will also be used to check intersects with
  82. // the geometry, as is much less expensive to transform the
  83. // ray to model coordinates than the geometry to world coordinates.
  84. var inverseMatrix math32.Matrix4
  85. inverseMatrix.GetInverse(&matrixWorld)
  86. var ray math32.Ray
  87. ray.Copy(&rc.Ray).ApplyMatrix4(&inverseMatrix)
  88. bbox := geom.BoundingBox()
  89. if !ray.IsIntersectionBox(&bbox) {
  90. return
  91. }
  92. // Local function to check the intersection of the ray from the raycaster with
  93. // the specified face defined by three poins.
  94. checkIntersection := func(mat *material.Material, pA, pB, pC, point *math32.Vector3) *core.Intersect {
  95. var intersect bool
  96. switch mat.Side() {
  97. case material.SideBack:
  98. intersect = ray.IntersectTriangle(pC, pB, pA, true, point)
  99. case material.SideFront:
  100. intersect = ray.IntersectTriangle(pA, pB, pC, true, point)
  101. case material.SideDouble:
  102. intersect = ray.IntersectTriangle(pA, pB, pC, false, point)
  103. }
  104. if !intersect {
  105. return nil
  106. }
  107. // Transform intersection point from model to world coordinates
  108. var intersectionPointWorld = *point
  109. intersectionPointWorld.ApplyMatrix4(&matrixWorld)
  110. // Calculates the distance from the ray origin to intersection point
  111. origin := rc.Ray.Origin()
  112. distance := origin.DistanceTo(&intersectionPointWorld)
  113. // Checks if distance is between the bounds of the raycaster
  114. if distance < rc.Near || distance > rc.Far {
  115. return nil
  116. }
  117. return &core.Intersect{
  118. Distance: distance,
  119. Point: intersectionPointWorld,
  120. Object: m,
  121. }
  122. }
  123. // Get buffer with position vertices
  124. vboPos := geom.VBO("VertexPosition")
  125. if vboPos == nil {
  126. panic("mesh.Raycast(): VertexPosition VBO not found")
  127. }
  128. positions := vboPos.Buffer()
  129. indices := geom.Indices()
  130. var vA, vB, vC math32.Vector3
  131. // Geometry has indexed vertices
  132. if indices.Size() > 0 {
  133. for i := 0; i < indices.Size(); i += 3 {
  134. // Get face indices
  135. a := indices[i]
  136. b := indices[i+1]
  137. c := indices[i+2]
  138. // Get face position vectors
  139. positions.GetVector3(int(3*a), &vA)
  140. positions.GetVector3(int(3*b), &vB)
  141. positions.GetVector3(int(3*c), &vC)
  142. // Checks intersection of the ray with this face
  143. mat := m.GetMaterial(i).GetMaterial()
  144. var point math32.Vector3
  145. intersect := checkIntersection(mat, &vA, &vB, &vC, &point)
  146. if intersect != nil {
  147. intersect.Index = uint32(i)
  148. *intersects = append(*intersects, *intersect)
  149. }
  150. }
  151. // Geometry has NO indexed vertices
  152. } else {
  153. stride := vboPos.Stride()
  154. offset := vboPos.AttribOffset("VertexPosition")
  155. for i := offset; i < positions.Size(); i += stride {
  156. // Get face indices
  157. a := i / 3
  158. b := a + 1
  159. c := a + 2
  160. // Set face position vectors
  161. positions.GetVector3(int(3*a), &vA)
  162. positions.GetVector3(int(3*b), &vB)
  163. positions.GetVector3(int(3*c), &vC)
  164. // Checks intersection of the ray with this face
  165. mat := m.GetMaterial(i).GetMaterial()
  166. var point math32.Vector3
  167. intersect := checkIntersection(mat, &vA, &vB, &vC, &point)
  168. if intersect != nil {
  169. intersect.Index = uint32(a)
  170. *intersects = append(*intersects, *intersect)
  171. }
  172. }
  173. }
  174. }