mesh.go 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  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. uniMm gls.Uniform // Model matrix uniform location cache
  16. uniMVm gls.Uniform // Model view matrix uniform location cache
  17. uniMVPm gls.Uniform // Model view projection matrix uniform cache
  18. uniNm gls.Uniform // Normal matrix uniform cache
  19. }
  20. // NewMesh creates and returns a pointer to a mesh with the specified geometry and material.
  21. // If the mesh has multi materials, the material specified here must be nil and the
  22. // individual materials must be add using "AddMaterial" or AddGroupMaterial".
  23. func NewMesh(igeom geometry.IGeometry, imat material.IMaterial) *Mesh {
  24. m := new(Mesh)
  25. m.Init(igeom, imat)
  26. return m
  27. }
  28. // Init initializes the Mesh and its uniforms.
  29. func (m *Mesh) Init(igeom geometry.IGeometry, imat material.IMaterial) {
  30. m.Graphic.Init(m, igeom, gls.TRIANGLES)
  31. // Initialize uniforms
  32. m.uniMm.Init("ModelMatrix")
  33. m.uniMVm.Init("ModelViewMatrix")
  34. m.uniMVPm.Init("MVP")
  35. m.uniNm.Init("NormalMatrix")
  36. // Adds single material if not nil
  37. if imat != nil {
  38. m.AddMaterial(imat, 0, 0)
  39. }
  40. }
  41. // SetMaterial clears all materials and adds the specified material for all vertices.
  42. func (m *Mesh) SetMaterial(imat material.IMaterial) {
  43. m.Graphic.ClearMaterials()
  44. m.Graphic.AddMaterial(m, imat, 0, 0)
  45. }
  46. // AddMaterial adds a material for the specified subset of vertices.
  47. func (m *Mesh) AddMaterial(imat material.IMaterial, start, count int) {
  48. m.Graphic.AddMaterial(m, imat, start, count)
  49. }
  50. // AddGroupMaterial adds a material for the specified geometry group.
  51. func (m *Mesh) AddGroupMaterial(imat material.IMaterial, gindex int) {
  52. m.Graphic.AddGroupMaterial(m, imat, gindex)
  53. }
  54. // Clone clones the mesh and satisfies the INode interface.
  55. func (m *Mesh) Clone() core.INode {
  56. clone := new(Mesh)
  57. clone.Graphic = *m.Graphic.Clone().(*Graphic)
  58. clone.SetIGraphic(clone)
  59. // Initialize uniforms
  60. clone.uniMm.Init("ModelMatrix")
  61. clone.uniMVm.Init("ModelViewMatrix")
  62. clone.uniMVPm.Init("MVP")
  63. clone.uniNm.Init("NormalMatrix")
  64. return clone
  65. }
  66. // RenderSetup is called by the engine before drawing the mesh geometry
  67. // It is responsible to updating the current shader uniforms with
  68. // the model matrices.
  69. func (m *Mesh) RenderSetup(gs *gls.GLS, rinfo *core.RenderInfo) {
  70. // Transfer uniform for model matrix
  71. mm := m.ModelMatrix()
  72. location := m.uniMm.Location(gs)
  73. gs.UniformMatrix4fv(location, 1, false, &mm[0])
  74. // Transfer uniform for model view matrix
  75. mvm := m.ModelViewMatrix()
  76. location = m.uniMVm.Location(gs)
  77. gs.UniformMatrix4fv(location, 1, false, &mvm[0])
  78. // Transfer uniform for model view projection matrix
  79. mvpm := m.ModelViewProjectionMatrix()
  80. location = m.uniMVPm.Location(gs)
  81. gs.UniformMatrix4fv(location, 1, false, &mvpm[0])
  82. // Calculates normal matrix and transfer uniform
  83. var nm math32.Matrix3
  84. nm.GetNormalMatrix(mvm)
  85. location = m.uniNm.Location(gs)
  86. gs.UniformMatrix3fv(location, 1, false, &nm[0])
  87. }
  88. // Raycast checks intersections between this geometry and the specified raycaster
  89. // and if any found appends it to the specified intersects array.
  90. func (m *Mesh) Raycast(rc *core.Raycaster, intersects *[]core.Intersect) {
  91. // Transform this mesh geometry bounding sphere from model
  92. // to world coordinates and checks intersection with raycaster
  93. geom := m.GetGeometry()
  94. sphere := geom.BoundingSphere()
  95. matrixWorld := m.MatrixWorld()
  96. sphere.ApplyMatrix4(&matrixWorld)
  97. if !rc.IsIntersectionSphere(&sphere) {
  98. return
  99. }
  100. // Copy ray and transform to model coordinates
  101. // This ray will will also be used to check intersects with
  102. // the geometry, as is much less expensive to transform the
  103. // ray to model coordinates than the geometry to world coordinates.
  104. var inverseMatrix math32.Matrix4
  105. inverseMatrix.GetInverse(&matrixWorld)
  106. var ray math32.Ray
  107. ray.Copy(&rc.Ray).ApplyMatrix4(&inverseMatrix)
  108. bbox := geom.BoundingBox()
  109. if !ray.IsIntersectionBox(&bbox) {
  110. return
  111. }
  112. // Local function to check the intersection of the ray from the raycaster with
  113. // the specified face defined by three poins.
  114. checkIntersection := func(mat *material.Material, pA, pB, pC, point *math32.Vector3) *core.Intersect {
  115. var intersect bool
  116. switch mat.Side() {
  117. case material.SideBack:
  118. intersect = ray.IntersectTriangle(pC, pB, pA, true, point)
  119. case material.SideFront:
  120. intersect = ray.IntersectTriangle(pA, pB, pC, true, point)
  121. case material.SideDouble:
  122. intersect = ray.IntersectTriangle(pA, pB, pC, false, point)
  123. }
  124. if !intersect {
  125. return nil
  126. }
  127. // Transform intersection point from model to world coordinates
  128. var intersectionPointWorld = *point
  129. intersectionPointWorld.ApplyMatrix4(&matrixWorld)
  130. // Calculates the distance from the ray origin to intersection point
  131. origin := rc.Ray.Origin()
  132. distance := origin.DistanceTo(&intersectionPointWorld)
  133. // Checks if distance is between the bounds of the raycaster
  134. if distance < rc.Near || distance > rc.Far {
  135. return nil
  136. }
  137. return &core.Intersect{
  138. Distance: distance,
  139. Point: intersectionPointWorld,
  140. Object: m,
  141. }
  142. }
  143. i := 0
  144. geom.ReadFaces(func(vA, vB, vC math32.Vector3) bool {
  145. // Checks intersection of the ray with this face
  146. mat := m.GetMaterial(i).GetMaterial()
  147. var point math32.Vector3
  148. intersect := checkIntersection(mat, &vA, &vB, &vC, &point)
  149. if intersect != nil {
  150. intersect.Index = uint32(i)
  151. *intersects = append(*intersects, *intersect)
  152. }
  153. i += 3
  154. return false
  155. })
  156. }