sprite.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  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. // Sprite is a potentially animated image positioned in space that always faces the camera.
  13. type Sprite struct {
  14. Graphic // Embedded graphic
  15. uniMVPM gls.Uniform // Model view projection matrix uniform location cache
  16. }
  17. // NewSprite creates and returns a pointer to a sprite with the specified dimensions and material
  18. func NewSprite(width, height float32, imat material.IMaterial) *Sprite {
  19. s := new(Sprite)
  20. // Creates geometry
  21. geom := geometry.NewGeometry()
  22. w := width / 2
  23. h := height / 2
  24. // Builds array with vertex positions and texture coordinates
  25. positions := math32.NewArrayF32(0, 12)
  26. positions.Append(
  27. -w, -h, 0, 0, 0,
  28. w, -h, 0, 1, 0,
  29. w, h, 0, 1, 1,
  30. -w, h, 0, 0, 1,
  31. )
  32. // Builds array of indices
  33. indices := math32.NewArrayU32(0, 6)
  34. indices.Append(0, 1, 2, 0, 2, 3)
  35. // Set geometry buffers
  36. geom.SetIndices(indices)
  37. geom.AddVBO(
  38. gls.NewVBO().
  39. AddAttrib("VertexPosition", 3).
  40. AddAttrib("VertexTexcoord", 2).
  41. SetBuffer(positions),
  42. )
  43. s.Graphic.Init(geom, gls.TRIANGLES)
  44. s.AddMaterial(s, imat, 0, 0)
  45. s.uniMVPM.Init("MVP")
  46. return s
  47. }
  48. // RenderSetup sets up the rendering of the sprite.
  49. func (s *Sprite) RenderSetup(gs *gls.GLS, rinfo *core.RenderInfo) {
  50. // Calculates model view matrix
  51. mw := s.MatrixWorld()
  52. var mvm math32.Matrix4
  53. mvm.MultiplyMatrices(&rinfo.ViewMatrix, &mw)
  54. // Decomposes model view matrix
  55. var position math32.Vector3
  56. var quaternion math32.Quaternion
  57. var scale math32.Vector3
  58. mvm.Decompose(&position, &quaternion, &scale)
  59. // Removes any rotation in X and Y axes and compose new model view matrix
  60. rotation := s.Rotation()
  61. rotation.X = 0
  62. rotation.Y = 0
  63. quaternion.SetFromEuler(&rotation)
  64. var mvmNew math32.Matrix4
  65. mvmNew.Compose(&position, &quaternion, &scale)
  66. // Calculates final MVP and updates uniform
  67. var mvpm math32.Matrix4
  68. mvpm.MultiplyMatrices(&rinfo.ProjMatrix, &mvmNew)
  69. location := s.uniMVPM.Location(gs)
  70. gs.UniformMatrix4fv(location, 1, false, &mvpm[0])
  71. }
  72. // Raycast checks intersections between this geometry and the specified raycaster
  73. // and if any found appends it to the specified intersects array.
  74. func (s *Sprite) Raycast(rc *core.Raycaster, intersects *[]core.Intersect) {
  75. // Copy and convert ray to camera coordinates
  76. var ray math32.Ray
  77. ray.Copy(&rc.Ray).ApplyMatrix4(&rc.ViewMatrix)
  78. // Calculates ViewMatrix * MatrixWorld
  79. var mv math32.Matrix4
  80. matrixWorld := s.MatrixWorld()
  81. mv.MultiplyMatrices(&rc.ViewMatrix, &matrixWorld)
  82. // Decompose transformation matrix in its components
  83. var position math32.Vector3
  84. var quaternion math32.Quaternion
  85. var scale math32.Vector3
  86. mv.Decompose(&position, &quaternion, &scale)
  87. // Remove any rotation in X and Y axis and
  88. // compose new transformation matrix
  89. rotation := s.Rotation()
  90. rotation.X = 0
  91. rotation.Y = 0
  92. quaternion.SetFromEuler(&rotation)
  93. mv.Compose(&position, &quaternion, &scale)
  94. // Get buffer with vertices and uvs
  95. geom := s.GetGeometry()
  96. vboPos := geom.VBO("VertexPosition")
  97. if vboPos == nil {
  98. panic("sprite.Raycast(): VertexPosition VBO not found")
  99. }
  100. // Get vertex positions, transform to camera coordinates and
  101. // checks intersection with ray
  102. buffer := vboPos.Buffer()
  103. indices := geom.Indices()
  104. var v1 math32.Vector3
  105. var v2 math32.Vector3
  106. var v3 math32.Vector3
  107. var point math32.Vector3
  108. intersect := false
  109. for i := 0; i < indices.Size(); i += 3 {
  110. pos := indices[i]
  111. buffer.GetVector3(int(pos*5), &v1)
  112. v1.ApplyMatrix4(&mv)
  113. pos = indices[i+1]
  114. buffer.GetVector3(int(pos*5), &v2)
  115. v2.ApplyMatrix4(&mv)
  116. pos = indices[i+2]
  117. buffer.GetVector3(int(pos*5), &v3)
  118. v3.ApplyMatrix4(&mv)
  119. if ray.IntersectTriangle(&v1, &v2, &v3, false, &point) {
  120. intersect = true
  121. break
  122. }
  123. }
  124. if !intersect {
  125. return
  126. }
  127. // Get distance from intersection point
  128. origin := ray.Origin()
  129. distance := origin.DistanceTo(&point)
  130. // Checks if distance is between the bounds of the raycaster
  131. if distance < rc.Near || distance > rc.Far {
  132. return
  133. }
  134. // Appends intersection to received parameter.
  135. *intersects = append(*intersects, core.Intersect{
  136. Distance: distance,
  137. Point: point,
  138. Object: s,
  139. })
  140. }