morph.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  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 geometry
  5. import (
  6. "github.com/g3n/engine/gls"
  7. "github.com/g3n/engine/math32"
  8. "strconv"
  9. "sort"
  10. )
  11. // MorphGeometry represents a base geometry and its morph targets.
  12. type MorphGeometry struct {
  13. baseGeometry *Geometry // The base geometry
  14. targets []*Geometry // The morph target geometries
  15. activeTargets []*Geometry // The morph target geometries
  16. weights []float32 // The weights for each morph target
  17. uniWeights gls.Uniform // Texture unit uniform location cache
  18. morphGeom *Geometry // Cache of the last CPU-morphed geometry
  19. }
  20. // NumMorphInfluencers is the maximum number of active morph targets.
  21. const NumMorphTargets = 8
  22. // NewMorphGeometry creates and returns a pointer to a new MorphGeometry.
  23. func NewMorphGeometry(baseGeometry *Geometry) *MorphGeometry {
  24. mg := new(MorphGeometry)
  25. mg.baseGeometry = baseGeometry
  26. mg.targets = make([]*Geometry, 0)
  27. mg.activeTargets = make([]*Geometry, 0)
  28. mg.weights = make([]float32, NumMorphTargets)
  29. mg.baseGeometry.ShaderDefines.Set("MORPHTARGETS", strconv.Itoa(NumMorphTargets))
  30. mg.uniWeights.Init("morphTargetInfluences")
  31. return mg
  32. }
  33. // GetGeometry satisfies the IGeometry interface.
  34. func (mg *MorphGeometry) GetGeometry() *Geometry {
  35. return mg.baseGeometry
  36. }
  37. // SetWeights sets the morph target weights.
  38. func (mg *MorphGeometry) SetWeights(weights []float32) {
  39. mg.weights = weights
  40. }
  41. // Weights returns the morph target weights.
  42. func (mg *MorphGeometry) Weights() []float32 {
  43. return mg.weights
  44. }
  45. // Weights returns the morph target weights.
  46. func (mg *MorphGeometry) AddMorphTargets(morphTargets ...*Geometry) {
  47. log.Error("ADD morph targets")
  48. mg.targets = append(mg.targets, morphTargets...)
  49. }
  50. // ActiveMorphTargets sorts the morph targets by weight and returns the top n morph targets with largest weight.
  51. func (mg *MorphGeometry) ActiveMorphTargets() []*Geometry {
  52. numTargets := len(mg.targets)
  53. if numTargets == 0 {
  54. return nil
  55. }
  56. sortedMorphTargets := make([]*Geometry, numTargets)
  57. copy(sortedMorphTargets, mg.targets)
  58. sort.Slice(sortedMorphTargets, func(i, j int) bool {
  59. return mg.weights[i] > mg.weights[j]
  60. })
  61. // TODO check current 0 weights
  62. //if len(mg.targets) < NumMorphTargets-1 {
  63. return sortedMorphTargets
  64. //} else {
  65. // return sortedMorphTargets[:NumMorphTargets-1]
  66. //}
  67. }
  68. // SetIndices sets the indices array for this geometry.
  69. func (mg *MorphGeometry) SetIndices(indices math32.ArrayU32) {
  70. mg.baseGeometry.SetIndices(indices)
  71. for i := range mg.targets {
  72. mg.targets[i].SetIndices(indices)
  73. }
  74. }
  75. // ComputeMorphed computes a morphed geometry from the provided morph target weights.
  76. // Note that morphing is usually computed by the GPU in shaders.
  77. // This CPU implementation allows users to obtain an instance of a morphed geometry
  78. // if so desired (loosing morphing ability).
  79. func (mg *MorphGeometry) ComputeMorphed(weights []float32) *Geometry {
  80. morphed := NewGeometry()
  81. // TODO
  82. return morphed
  83. }
  84. // Dispose releases, if possible, OpenGL resources, C memory
  85. // and VBOs associated with the base geometry and morph targets.
  86. func (mg *MorphGeometry) Dispose() {
  87. mg.baseGeometry.Dispose()
  88. for i := range mg.targets {
  89. mg.targets[i].Dispose()
  90. }
  91. }
  92. // RenderSetup is called by the renderer before drawing the geometry.
  93. func (mg *MorphGeometry) RenderSetup(gs *gls.GLS) {
  94. mg.baseGeometry.RenderSetup(gs)
  95. // Sort weights and find top 8 morph targets with largest current weight (8 is the max sent to shader)
  96. activeMorphTargets := mg.ActiveMorphTargets()
  97. for i, mt := range activeMorphTargets {
  98. mt.SetAttributeName(gls.VertexPosition, "MorphPosition"+strconv.Itoa(i))
  99. mt.SetAttributeName(gls.VertexNormal, "MorphNormal"+strconv.Itoa(i))
  100. //mt.SetAttributeName(vTangent, fmt.Sprintf("MorphTangent[%d]", i))
  101. // Transfer morphed geometry VBOs
  102. for _, vbo := range mt.VBOs() {
  103. vbo.Transfer(gs)
  104. }
  105. }
  106. // Transfer texture info combined uniform
  107. location := mg.uniWeights.Location(gs)
  108. gs.Uniform1fv(location, int32(len(activeMorphTargets)), mg.weights)
  109. }