Procházet zdrojové kódy

implemented z-sorting

danaugrs před 7 roky
rodič
revize
b642a38829
4 změnil soubory, kde provedl 114 přidání a 78 odebrání
  1. 1 1
      README.md
  2. 6 12
      core/raycaster.go
  3. 7 14
      gui/root.go
  4. 100 51
      renderer/renderer.go

+ 1 - 1
README.md

@@ -48,7 +48,7 @@ In all cases it is necessary to have a gcc compatible C compiler installed.
   your are using [Homebrew](https://brew.sh/) as your package manager, run:
   `brew install libvorbis openal-soft`
 
-G3N was only tested with Go1.7.4+
+G3N requires Go 1.8+
 
 ## Installation
 

+ 6 - 12
core/raycaster.go

@@ -73,7 +73,9 @@ func (rc *Raycaster) IntersectObject(inode INode, recursive bool) []Intersect {
 
 	intersects := []Intersect{}
 	rc.intersectObject(inode, &intersects, recursive)
-	sort.Sort(Intersects(intersects))
+	sort.Slice(intersects, func(i, j int) bool {
+		return intersects[i].Distance < intersects[j].Distance
+	})
 	return intersects
 }
 
@@ -87,7 +89,9 @@ func (rc *Raycaster) IntersectObjects(inodes []INode, recursive bool) []Intersec
 	for _, inode := range inodes {
 		rc.intersectObject(inode, &intersects, recursive)
 	}
-	sort.Sort(Intersects(intersects))
+	sort.Slice(intersects, func(i, j int) bool {
+		return intersects[i].Distance < intersects[j].Distance
+	})
 	return intersects
 }
 
@@ -105,13 +109,3 @@ func (rc *Raycaster) intersectObject(inode INode, intersects *[]Intersect, recur
 	}
 	return
 }
-
-// Intersects is the array type for Intersect objects. It's used for sorting intersects by distance.
-type Intersects []Intersect
-
-func (is Intersects) Len() int      { return len(is) }
-func (is Intersects) Swap(i, j int) { is[i], is[j] = is[j], is[i] }
-func (is Intersects) Less(i, j int) bool {
-
-	return is[i].Distance < is[j].Distance
-}

+ 7 - 14
gui/root.go

@@ -22,7 +22,7 @@ type Root struct {
 	mouseFocus        IPanel         // current child panel with mouse focus
 	scrollFocus       IPanel         // current child panel with scroll focus
 	modalPanel        IPanel         // current modal panel
-	targets           listPanelZ     // preallocated list of target panels
+	targets           []IPanel       // preallocated list of target panels
 }
 
 const (
@@ -317,7 +317,12 @@ func (r *Root) sendPanels(x, y float32, evname string, ev interface{}) {
 
 	// Sorts panels by absolute Z with the most foreground panels first
 	// and sends event to all panels or until a stop is requested
-	sort.Sort(r.targets)
+	sort.Slice(r.targets, func(i, j int) bool {
+		iz := r.targets[i].GetPanel().Position().Z
+		jz := r.targets[j].GetPanel().Position().Z
+		return iz < jz
+	})
+
 	r.stopPropagation = 0
 
 	// Send events to panels
@@ -415,15 +420,3 @@ func (r *Root) canDispatch(ipan IPanel) bool {
 //	// TODO
 //	// This should probably be in Panel ?
 //}
-
-// For sorting panels by Z coordinate
-type listPanelZ []IPanel
-
-func (p listPanelZ) Len() int      { return len(p) }
-func (p listPanelZ) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
-func (p listPanelZ) Less(i, j int) bool {
-
-	iz := p[i].GetPanel().Position().Z
-	jz := p[j].GetPanel().Position().Z
-	return iz < jz
-}

+ 100 - 51
renderer/renderer.go

@@ -12,35 +12,38 @@ import (
 	"github.com/g3n/engine/gui"
 	"github.com/g3n/engine/light"
 	"github.com/g3n/engine/math32"
+	"sort"
 )
 
 // Renderer renders a 3D scene and/or a 2D GUI on the current window.
 type Renderer struct {
 	gs           *gls.GLS
-	shaman       Shaman                     // Internal shader manager
-	stats        Stats                      // Renderer statistics
-	prevStats    Stats                      // Renderer statistics for previous frame
-	scene        core.INode                 // Node containing 3D scene to render
-	panelGui     gui.IPanel                 // Panel containing GUI to render
-	panel3D      gui.IPanel                 // Panel which contains the 3D scene
-	ambLights    []*light.Ambient           // Array of ambient lights for last scene
-	dirLights    []*light.Directional       // Array of directional lights for last scene
-	pointLights  []*light.Point             // Array of point
-	spotLights   []*light.Spot              // Array of spot lights for the scene
-	others       []core.INode               // Other nodes (audio, players, etc)
-	grmats       []*graphic.GraphicMaterial // Array of rendered graphic materials for scene
-	cgrmats      []*graphic.GraphicMaterial // Array of culled graphic materials for scene
-	rinfo        core.RenderInfo            // Preallocated Render info
-	specs        ShaderSpecs                // Preallocated Shader specs
-	redrawGui    bool                       // Flag indicating the gui must be redrawn completely
-	rendered     bool                       // Flag indicating if anything was rendered
-	panList      []gui.IPanel               // list of panels to render
-	frameBuffers int                        // Number of frame buffers
-	frameCount   int                        // Current number of frame buffers to write
+	shaman       Shaman                    // Internal shader manager
+	stats        Stats                     // Renderer statistics
+	prevStats    Stats                     // Renderer statistics for previous frame
+	scene        core.INode                // Node containing 3D scene to render
+	panelGui     gui.IPanel                // Panel containing GUI to render
+	panel3D     gui.IPanel                 // Panel which contains the 3D scene
+	ambLights   []*light.Ambient           // Array of ambient lights for last scene
+	dirLights   []*light.Directional       // Array of directional lights for last scene
+	pointLights []*light.Point             // Array of point
+	spotLights  []*light.Spot              // Array of spot lights for the scene
+	others      []core.INode               // Other nodes (audio, players, etc)
+	rgraphics   []graphic.IGraphic         // Array of rendered graphics for scene
+	cgraphics   []graphic.IGraphic         // Array of culled graphics for scene
+	grmats      []*graphic.GraphicMaterial // Array of rendered graphic materials for scene
+	rinfo       core.RenderInfo            // Preallocated Render info
+	specs       ShaderSpecs                // Preallocated Shader specs
+	sortObjects bool                       // Flag indicating whether objects should be sorted before rendering
+	redrawGui   bool                       // Flag indicating the gui must be redrawn completely
+	rendered    bool                       // Flag indicating if anything was rendered
+	panList      []gui.IPanel              // list of panels to render
+	frameBuffers int                       // Number of frame buffers
+	frameCount   int                       // Current number of frame buffers to write
 }
 
-// Stats describes how many object types were rendered
-// It is cleared at the start of each render
+// Stats describes how many object types were rendered.
+// It is cleared at the start of each render.
 type Stats struct {
 	Graphics int // Number of graphic objects rendered
 	Lights   int // Number of lights rendered
@@ -48,7 +51,7 @@ type Stats struct {
 	Others   int // Number of other objects rendered
 }
 
-// NewRenderer creates and returns a pointer to a new Renderer
+// NewRenderer creates and returns a pointer to a new Renderer.
 func NewRenderer(gs *gls.GLS) *Renderer {
 
 	r := new(Renderer)
@@ -60,10 +63,12 @@ func NewRenderer(gs *gls.GLS) *Renderer {
 	r.pointLights = make([]*light.Point, 0)
 	r.spotLights = make([]*light.Spot, 0)
 	r.others = make([]core.INode, 0)
+	r.rgraphics = make([]graphic.IGraphic, 0)
+	r.cgraphics = make([]graphic.IGraphic, 0)
 	r.grmats = make([]*graphic.GraphicMaterial, 0)
-	r.cgrmats = make([]*graphic.GraphicMaterial, 0)
 	r.panList = make([]gui.IPanel, 0)
 	r.frameBuffers = 2
+	r.sortObjects = true
 	return r
 }
 
@@ -74,27 +79,27 @@ func (r *Renderer) AddDefaultShaders() error {
 	return r.shaman.AddDefaultShaders()
 }
 
-// AddChunk adds a shader chunk with the specified name and source code
+// AddChunk adds a shader chunk with the specified name and source code.
 func (r *Renderer) AddChunk(name, source string) {
 
 	r.shaman.AddChunk(name, source)
 }
 
-// AddShader adds a shader program with the specified name and source code
+// AddShader adds a shader program with the specified name and source code.
 func (r *Renderer) AddShader(name, source string) {
 
 	r.shaman.AddShader(name, source)
 }
 
-// AddProgram adds a program with the specified name and associated vertex
-// and fragment shaders names (previously registered)
+// AddProgram adds the program with the specified name,
+// with associated vertex and fragment shaders (previously registered).
 func (r *Renderer) AddProgram(name, vertex, frag string, others ...string) {
 
 	r.shaman.AddProgram(name, vertex, frag, others...)
 }
 
 // SetGui sets the gui panel which contains the Gui to render.
-// If set to nil, no Gui will be rendered
+// If set to nil, no Gui will be rendered.
 func (r *Renderer) SetGui(gui gui.IPanel) {
 
 	r.panelGui = gui
@@ -109,14 +114,14 @@ func (r *Renderer) SetGuiPanel3D(panel3D gui.IPanel) {
 	r.panel3D = panel3D
 }
 
-// Panel3D returns the current gui panel over the 3D scene
+// Panel3D returns the current gui panel over the 3D scene.
 func (r *Renderer) Panel3D() gui.IPanel {
 
 	return r.panel3D
 }
 
-// SetScene sets the 3D scene to render
-// If set to nil, no 3D scene will be rendered
+// SetScene sets the 3D scene to be rendered.
+// If set to nil, no 3D scene will be rendered.
 func (r *Renderer) SetScene(scene core.INode) {
 
 	r.scene = scene
@@ -129,8 +134,20 @@ func (r *Renderer) Stats() Stats {
 	return r.stats
 }
 
-// Render renders the previously set Scene and Gui using the specified camera
-// Returns an indication if anything was rendered and an error
+// SetSortObjects sets whether objects will be Z-sorted before rendering.
+func (r *Renderer) SetSortObjects(sort bool) {
+
+	r.sortObjects = sort
+}
+
+// SortObjects returns whether objects will be Z-sorted before rendering.
+func (r *Renderer) SortObjects() bool {
+
+	return r.sortObjects
+}
+
+// Render renders the previously set Scene and Gui using the specified camera.
+// Returns an indication if anything was rendered and an error.
 func (r *Renderer) Render(icam camera.ICamera) (bool, error) {
 
 	r.redrawGui = false
@@ -155,7 +172,7 @@ func (r *Renderer) Render(icam camera.ICamera) (bool, error) {
 	return r.rendered, nil
 }
 
-// renderScene renders the 3D scene using the specified camera
+// renderScene renders the 3D scene using the specified camera.
 func (r *Renderer) renderScene(iscene core.INode, icam camera.ICamera) error {
 
 	// Updates world matrices of all scene nodes
@@ -172,8 +189,9 @@ func (r *Renderer) renderScene(iscene core.INode, icam camera.ICamera) error {
 	r.pointLights = r.pointLights[0:0]
 	r.spotLights = r.spotLights[0:0]
 	r.others = r.others[0:0]
+	r.rgraphics = r.rgraphics[0:0]
+	r.cgraphics = r.cgraphics[0:0]
 	r.grmats = r.grmats[0:0]
-	r.cgrmats = r.cgrmats[0:0]
 
 	// Prepare for frustum culling
 	var proj math32.Matrix4
@@ -195,27 +213,23 @@ func (r *Renderer) renderScene(iscene core.INode, icam camera.ICamera) error {
 		if ok {
 			if igr.Renderable() {
 
-				gr := igr.GetGraphic()
-				materials := gr.Materials()
-
 				// Frustum culling
 				if igr.Cullable() {
+					gr := igr.GetGraphic()
 					mw := gr.MatrixWorld()
 					geom := igr.GetGeometry()
 					bb := geom.BoundingBox()
 					bb.ApplyMatrix4(&mw)
-					if !frustum.IntersectsBox(&bb) {
-						for i := 0; i < len(materials); i++ {
-							// Record any culled materials
-							r.cgrmats = append(r.cgrmats, &materials[i])
-						}
-						return
+					if frustum.IntersectsBox(&bb) {
+						// Append graphic to list of graphics to be rendered
+						r.rgraphics = append(r.rgraphics, igr)
+					} else {
+						// Append graphic to list of culled graphics
+						r.cgraphics = append(r.cgraphics, igr)
 					}
-				}
-
-				// Appends to list each graphic material for this graphic
-				for i := 0; i < len(materials); i++ {
-					r.grmats = append(r.grmats, &materials[i])
+				} else {
+					// Append graphic to list of graphics to be rendered
+					r.rgraphics = append(r.rgraphics, igr)
 				}
 			}
 			// Node is not a Graphic
@@ -258,6 +272,41 @@ func (r *Renderer) renderScene(iscene core.INode, icam camera.ICamera) error {
 	r.specs.PointLightsMax = len(r.pointLights)
 	r.specs.SpotLightsMax = len(r.spotLights)
 
+	// Z-sort graphics
+	if r.sortObjects {
+		sort.Slice(r.rgraphics, func(i, j int) bool {
+
+			gr1 := r.rgraphics[i].GetGraphic()
+			gr2 := r.rgraphics[j].GetGraphic()
+
+			mw1 := gr1.MatrixWorld()
+			mw2 := gr2.MatrixWorld()
+
+			// TODO OPTIMIZATION - this calculation is already done in IGraphic.RenderSetup, should cache results in Graphic.
+			var mvm1, mvm2 math32.Matrix4
+			mvm1.MultiplyMatrices(&r.rinfo.ViewMatrix, &mw1)
+			mvm2.MultiplyMatrices(&r.rinfo.ViewMatrix, &mw2)
+
+			g1pos := gr1.Position()
+			g2pos := gr2.Position()
+
+			g1pos.ApplyMatrix4(&mvm1)
+			g2pos.ApplyMatrix4(&mvm2)
+
+			return g1pos.Z < g2pos.Z
+		})
+	}
+
+	// Compile list of all graphic materials to be rendered
+	for i := 0; i < len(r.rgraphics); i++ {
+		gr := r.rgraphics[i].GetGraphic()
+		materials := gr.Materials()
+		// Appends to list each graphic material for this graphic
+		for j := 0; j < len(materials); j++ {
+			r.grmats = append(r.grmats, &materials[j])
+		}
+	}
+
 	// Render other nodes (audio players, etc)
 	for i := 0; i < len(r.others); i++ {
 		inode := r.others[i]
@@ -332,7 +381,7 @@ func (r *Renderer) renderGui() error {
 
 	// If no 3D scene was rendered sets Gui panels as renderable for background
 	// User must define the colors
-	if (len(r.grmats) == 0) && (len(r.cgrmats) == 0) {
+	if (len(r.grmats) == 0) && (len(r.cgraphics) == 0) {
 		r.panelGui.SetRenderable(true)
 		if r.panel3D != nil {
 			r.panel3D.SetRenderable(true)