Drawing Order - Page 3

Drawing Order

Discuss the source code and development of Spring Engine in general from a technical point of view. Patches go here too.

Moderator: Moderators

User avatar
jK
Spring Developer
Posts: 2299
Joined: 28 Jun 2007, 07:30

Re: Drawing Order

Post by jK »

Argh wrote:I just showed you that, depending on the order in which translucent objects are called vs. opaque ones, you get different results when culling occurs.
How can you read so many papers and still not knowing the difference between culling, alphatest, stencil buffer and depth buffer?
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Re: Drawing Order

Post by Argh »

How can you see the fucking screenshots, and yet still not know what you're talking about?

Seriously... somebody, write the goddamn basic sort... not even the secondary... and I will show you, via screenshots, that it all works, as fucking described. It will not take more than 20 minutes to write that sort, dammit, and I will test it and show the results.
Last edited by Argh on 13 Aug 2009, 00:14, edited 1 time in total.
User avatar
Peet
Malcontent
Posts: 4384
Joined: 27 Feb 2006, 22:04

Re: Drawing Order

Post by Peet »

Argh wrote:How can you see the fucking screenshots, and yet still not know what you're talking about?
brilliant. 10/10
User avatar
aegis
Posts: 2456
Joined: 11 Jul 2007, 17:47

Re: Drawing Order

Post by aegis »

argh, Imma have to ask you to calm down a bit.

also, screenshots aren't the source of ultimate wisdom, and tests *can* be misinterpreted if you don't completely understand the underlying technology.
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Re: Drawing Order

Post by Argh »

argh, Imma have to ask you to calm down a bit.
Fine, fine, I'll take deep breaths and stuff. Tell jK that he needs to show some proof, though, this is ridiculous. I'll give him the entire GLSL so that he can test it.
tests *can* be misinterpreted if you don't completely understand the underlying technology.
Fair enough. That's why I reversed the test conditions and showed that the results were what I predicted. That's science.

Here's the code.

Code: Select all

function gadget:GetInfo()
   return {
      name      = "unit_normalmap_shader_tst.lua",
      desc      = "adds normal-mapping to S3O models",
      author    = "Kloot",
      date      = "31-1-2009",
      license   = "GPL v2",
      layer     =  0,
      enabled   = true
   }
end

if (gadgetHandler:IsSyncedCode()) then
	function gadget:Initialize()
		-- desc      = "adds normal-mapping to S3O models (gadgetized)",
		-- author    = "Kloot",
		-- date      = "April 6, 2009",
		-- license   = "GPL v2",
	end

	function gadget:UnitGiven(unitID)
		SendToUnsynced("MyUnitCrea", unitID)
		return true
	end

	function gadget:UnitCreated(unitID)
		SendToUnsynced("MyUnitCrea", unitID)
		return true
	end

	function gadget:UnitDestroyed(unitID)
		SendToUnsynced("MyUnitDest", unitID)
		return true
	end

else

	local glLoadIdentity       = gl.LoadIdentity
	local glPushMatrix         = gl.PushMatrix
	local glPopMatrix          = gl.PopMatrix
	local glTranslate          = gl.Translate
	local glBeginEnd           = gl.BeginEnd
	local glNormal             = gl.Normal
	local glVertex             = gl.Vertex
	local glColor              = gl.Color
	local glLight              = gl.Light
	local glLighting           = gl.Lighting
	local glBlending           = gl.Blending
	local glPushAttrib         = gl.PushAttrib
	local glPopAttrib          = gl.PopAttrib

	local glCulling            = gl.Culling
	local glDepthMask          = gl.DepthMask
	local glDepthTest          = gl.DepthTest
	local glAlphaTest 	= gl.AlphaTest

	local glCreateList         = gl.CreateList
	local glDeleteList         = gl.DeleteList

	local glUnit               = gl.Unit
	local glUnitRaw            = gl.UnitRaw
	local glTexture            = gl.Texture
	local glTexCoord           = gl.TexCoord
	local glMultiTexCoord      = gl.MultiTexCoord
	local glUnitMultMatrix     = gl.UnitMultMatrix

	local glGetSun             = gl.GetSun
	local glGetShadowMapParams = gl.GetShadowMapParams
	local glGetMatrixData      = gl.GetMatrixData

	local glGetShaderLog       = gl.GetShaderLog
	local glCreateShader       = gl.CreateShader
	local glDeleteShader       = gl.DeleteShader
	local glUseShader          = gl.UseShader

	local glUniformMatrix      = gl.UniformMatrix
	local glUniformInt         = gl.UniformInt
	local glUniform            = gl.Uniform
	local glGetUniformLocation = gl.GetUniformLocation
	local glGetActiveUniforms  = gl.GetActiveUniforms

	local normalMapNames      = {}
	local textureNames        = {}
	local preDisplayLists     = {}
	local pstDisplayLists     = {}
	local luaShader           = nil

	local luaShaderLocs = {
		cameraMatrixLoc     = -1,
		cameraInvMatrixLoc  = -1,
		shadowMatrixLoc     = -1,
		shadowParamsLoc     = -1,
		shadowDensityLoc    = -1,

		unitAmbientLightLoc = -1,
		unitDiffuseLightLoc = -1,

		shadowMapLoc        = -1,
		textureS3O1Loc      = -1,
		textureS3O2Loc      = -1,
		--specularMapLoc      = -1,
		reflectMapLoc       = -1,
		normalMapLoc        = -1,
	}

	local sprGetGameFrame           = Spring.GetGameFrame
	local sprGetUnitDefID           = Spring.GetUnitDefID
	local sprGetAllUnits            = Spring.GetAllUnits
	local sprGetVisibleUnits        = Spring.GetVisibleUnits
	local sprIsUnitVisible          = Spring.IsUnitVisible
	local sprGetUnitTeam            = Spring.GetUnitTeam
	local sprGetCameraPosition      = Spring.GetCameraPosition
	local sprGetTeamColor           = Spring.GetTeamColor
	local sprSetUnitNoDraw          = Spring.SetUnitNoDraw
	local sprHaveShadows            = Spring.HaveShadows
	local sprGetUnitTransformMatrix = Spring.GetUnitTransformMatrix
	local SUR                       = Spring.UnitRendering





	local function GetPreDisplayList(unitID)
		local unitTeam = sprGetUnitTeam(unitID)
		local unitDefID = sprGetUnitDefID(unitID)

		if (preDisplayLists[unitDefID] == nil) then
			preDisplayLists[unitDefID] = {}
		end

		if (preDisplayLists[unitDefID][unitTeam] == nil) then
			local sdx, sdy, sdz = glGetSun("pos")
			local tcr, tcg, tcb, tca = sprGetTeamColor(unitTeam)

			preDisplayLists[unitDefID][unitTeam] = glCreateList(
				function()
					glPushAttrib(GL_ALL_ATTRIB_BITS)
					glAlphaTest(GL.GREATER,0.01)
					glBlending(GL.SRC_ALPHA, GL.ONE_MINUS_SRC_ALPHA)
					glDepthMask(true)
					glDepthTest(GL.LEQUAL)
					glCulling(GL.BACK)

					glLighting(true)
					glLight(0, true)
					glLight(1, false)
					glLight(0, GL.POSITION, sdx, sdy, sdz, 0)

					glPushMatrix()
					glColor(tcr, tcg, tcb, tca)
					glTexture(4, normalMapNames[unitDefID][1])
				end)
		end

		return preDisplayLists[unitDefID][unitTeam]
	end

	local function GetPostDisplayList(unitID)
		local unitTeam = sprGetUnitTeam(unitID)
		local unitDefID = sprGetUnitDefID(unitID)

		if (pstDisplayLists[unitDefID] == nil) then
			pstDisplayLists[unitDefID] = {}
		end

		if (pstDisplayLists[unitDefID][unitTeam] == nil) then
			pstDisplayLists[unitDefID][unitTeam] = glCreateList(
				function()
					glTexture(4, false)
					glColor(1.0, 1.0, 1.0, 1.0)
					glPopMatrix()

					glLight(0, false)
					glLighting(false)

					glCulling(GL.FRONT)
					glDepthTest(false)
					glDepthMask(false)
					glBlending(true)
					glPopAttrib()
				end)
		end

		return pstDisplayLists[unitDefID][unitTeam]
	end

	local function GetUnitDefMaterial(unitDefID, preDL, pstDL)
		local matTbl = {
			texunits = {
				[0] = {tex = textureNames[unitDefID][1],   enable = true},
				[1] = {tex = textureNames[unitDefID][2],   enable = true},
				[2] = {tex = "$reflection",                enable = true},
				[3] = {tex = normalMapNames[unitDefID][1], enable = true},
				[4] = {tex = "$shadow",                    enable = true}
			},

			culling         = GL.BACK,
			shader          = luaShader,
			cameraloc       = luaShaderLocs.cameraMatrixLoc,
		--	camerainvloc    = luaShaderLocs.cameraInvMatrixLoc, -- Spring 0.79
			shadowloc       = luaShaderLocs.shadowMatrixLoc,
			shadowparamsloc = luaShaderLocs.shadowParamsLoc,
			prelist         = preDL,
			postlist        = pstDL
		}
		return matTbl
	end


	local function MyUnitCrea(unitID)
		local unitDefID = sprGetUnitDefID(unitID)

		if (normalMapNames[unitDefID] ~= nil) then
			if (textureNames[unitDefID] == nil) then
				textureNames[unitDefID] = {
					[1] = '%' .. unitDefID .. ":0",
					[2] = '%' .. unitDefID .. ":1"
				}
			end

			--Spring.Echo("Found Unit",unitID)

			local preDL = GetPreDisplayList(unitID)
			local pstDL = GetPostDisplayList(unitID)

			SUR.SetLODCount(unitID, 1)
			SUR.SetMaterial(unitID, 1, "opaque", GetUnitDefMaterial(unitDefID, preDL, pstDL))
			SUR.SetUnitLuaDraw(unitID, true)

			for pieceID, pieceName in pairs(Spring.GetUnitPieceList(unitID) or {}) do
				if (pieceID ~= "n") then
					SUR.SetPieceList(unitID, 1, pieceID)
				end
			end
		end
	end

	local function MyUnitDest(unitID)
		local unitDefID = sprGetUnitDefID(unitID)

		if (normalMapNames[unitDefID] ~= nil) then
			SUR.SetUnitLuaDraw(unitID, false)
			SUR.SetLODCount(unitID, 0)
		end
	end



	local function SetShaderUniformLocations(s)
		luaShaderLocs.cameraMatrixLoc     = glGetUniformLocation(s, "cameraMatrix")
		luaShaderLocs.cameraInvMatrixLoc  = glGetUniformLocation(s, "cameraInvMatrix")
		luaShaderLocs.shadowMatrixLoc     = glGetUniformLocation(s, "shadowMatrix")

		luaShaderLocs.haveShadowsLoc      = glGetUniformLocation(luaShader, "haveShadows")
		luaShaderLocs.shadowParamsLoc     = glGetUniformLocation(luaShader, "shadowParams")
		luaShaderLocs.shadowDensityLoc    = glGetUniformLocation(luaShader, "shadowDensity")
	end

local function CreateShader1()
				local s = glCreateShader({
			vertex = [[
				varying vec3 lvES;
				varying vec3 hvES;
				varying vec3 nvES;

				varying mat3 tbnInvMatrix;
				varying vec3 cdES;
				//varying vec3 cdTS;

				uniform int haveShadows;
				uniform mat4 shadowMatrix;
				uniform vec4 shadowParams;
				uniform mat4 cameraMatrix;
				uniform mat4 cameraInvMatrix;

				void main(void) {

					mat4 modelMatrix = cameraInvMatrix * gl_ModelViewMatrix;
					mat4 modelInvMatrix = gl_ModelViewMatrixInverse * cameraMatrix;

					vec3 vpES = (gl_ModelViewMatrix * gl_Vertex).xyz;
					vec3 cpES = vec3(0.0, 0.0, 1.0);

					vec3 svOS = gl_MultiTexCoord5.xyz;
					vec3 tvOS = gl_MultiTexCoord6.xyz;
					
					//Manual transform of the matrix, for GLSL 1.X compatibility
					mat3 tbnMatrix = mat3(svOS, tvOS, gl_Normal);
					tbnInvMatrix[0].x = tbnMatrix[0].x;
					tbnInvMatrix[0].y = tbnMatrix[1].x;
					tbnInvMatrix[0].z = tbnMatrix[2].x;

					tbnInvMatrix[1].x = tbnMatrix[0].y;
					tbnInvMatrix[1].y = tbnMatrix[1].y;
					tbnInvMatrix[1].z = tbnMatrix[2].y;

					tbnInvMatrix[2].x = tbnMatrix[0].z;
					tbnInvMatrix[2].y = tbnMatrix[1].z;
					tbnInvMatrix[2].z = tbnMatrix[2].z;
						
					cdES = (vpES - cpES);
					//cdTS = (tbnInvMatrix * (gl_ModelViewMatrixInverse * vec4(cdES, gl_Vertex.w)).xyz);

					nvES = normalize(gl_NormalMatrix * gl_Normal);
					lvES = normalize(gl_LightSource[0].position.xyz);
					hvES = normalize(gl_LightSource[0].halfVector.xyz);


					gl_FrontColor = gl_Color;
					gl_TexCoord[0].st  = gl_MultiTexCoord0.st;
					gl_Position = gl_ProjectionMatrix * cameraMatrix * modelMatrix * gl_Vertex;

					if (haveShadows != 0) {
						vec4 vpWS = (modelMatrix * gl_Vertex);
						gl_TexCoord[3] = shadowMatrix * vpWS;
						
						gl_TexCoord[3].st *= (1 / sqrt(abs(gl_TexCoord[3].st) + shadowParams.z) + shadowParams.w);
						gl_TexCoord[3].st += shadowParams.xy;
					}
				}
			]],

			fragment = [[
				varying vec3 lvES;
				varying vec3 hvES;
				varying vec3 nvES;

				varying vec3 cdES;
				//varying vec3 cdTS;

				uniform sampler2D textureS3O1;
				uniform sampler2D textureS3O2;

				uniform samplerCube reflectMap;
				uniform sampler2D normalMap;

				uniform sampler2D shadowMap;
				uniform int haveShadows;

				uniform vec3 unitAmbientLight;
				uniform vec3 unitDiffuseLight;

				varying mat3 tbnInvMatrix;

				void main(void) {

						//Manual transform of the matrix, for GLSL 1.X compatibility
						mat3 tbnMatrix;

						tbnMatrix[0].x = tbnInvMatrix[0].x;
						tbnMatrix[0].y = tbnInvMatrix[1].x;
						tbnMatrix[0].z = tbnInvMatrix[2].x;

						tbnMatrix[1].x = tbnInvMatrix[0].y;
						tbnMatrix[1].y = tbnInvMatrix[1].y;
						tbnMatrix[1].z = tbnInvMatrix[2].y;

						tbnMatrix[2].x = tbnInvMatrix[0].z;
						tbnMatrix[2].y = tbnInvMatrix[1].z;
						tbnMatrix[2].z = tbnInvMatrix[2].z;

					vec2 tc = vec2(gl_TexCoord[0].s, gl_TexCoord[0].t);

/*vec4 normalColor = texture2D(normalMap, tc);

					vec3 cdTS = (tbnInvMatrix * (gl_ModelViewMatrixInverse * vec4(cdES,normalColor.a)).xyz);

						// parallax-mapping
						float s =  0.005;
						float b = -0.001;
						
						//float h; 
						float h = (float(texture2D(normalMap, tc)) * s) + b;
						//h = (h * s) + b;

						tc += (h * (normalize(cdTS)).xy);*/



					vec3 nvTS = ((texture2D(normalMap, tc) * 2.0) - 1.0);

					vec4 basicColor = texture2D(textureS3O1, tc);
					vec4 extraColor = texture2D(textureS3O2, tc);

					float nvDOTlv = 0.0;
					float nvDOThv = 0.0;
					vec3 reDirES;

					vec3 nv_OS = normalize(tbnMatrix * nvTS);
					vec3 nv_ES = normalize(gl_NormalMatrix * nv_OS);

					nvDOTlv = max(nvDOTlv, dot(nv_ES, lvES));
					nvDOThv = max(nvDOThv, dot(nv_ES, hvES));
					reDirES = reflect(normalize(cdES), nv_ES);

					float shininess = extraColor.g * 4.0;

					float specPow =
						(nvDOTlv > 0.0 && nvDOThv > 0.0)?
						max(0.0, pow(nvDOThv, shininess)):
						0.0;

					if (extraColor.b > 0.0)
					{
						specPow = specPow * extraColor.b;
					}

					vec3 specColor = textureCube(reflectMap, reDirES).rgb * specPow * extraColor.g;
					vec3 reflColor = textureCube(reflectMap, reDirES).rgb;
					vec3 diffColor = (unitDiffuseLight * nvDOTlv) + unitAmbientLight * 1.25;

					reflColor = mix(diffColor, reflColor, extraColor.g);
					reflColor += extraColor.r;

					gl_FragColor = basicColor;
					gl_FragColor.rgb = mix(gl_FragColor.rgb, gl_Color.rgb, gl_FragColor.a);
					gl_FragColor.rgb = gl_FragColor.rgb * reflColor + specColor;

					if(haveShadows != 0)
					{
						vec2 tc = vec2(gl_TexCoord[3].s, gl_TexCoord[3].t);
						float depth = texture2D(shadowMap, tc).z;
						if (depth <  0.05)
						{
							gl_FragColor.rgb = gl_FragColor.rgb * vec3(extraColor.r + unitAmbientLight.r + extraColor.g, extraColor.r + unitAmbientLight.g + extraColor.g, extraColor.r + unitAmbientLight.b + extraColor.g);

							if (basicColor.a > 0.0)
							{
								gl_FragColor.rgb = mix(gl_FragColor.rgb, gl_Color, basicColor.a);
							}
						}						
					}
					gl_FragColor.a   = extraColor.a;
				}
			]],

			uniformInt = {
				textureS3O1 = 0,
				textureS3O2 = 1,
				reflectMap  = 2,
				normalMap   = 3,
				shadowMap   = 4,
			},
			uniform = {
				unitAmbientLight = {glGetSun("ambient", "unit")},
				unitDiffuseLight = {glGetSun("diffuse", "unit")},
			},
			uniformMatrix = {
				shadowMatrix = {glGetMatrixData("shadow")},
			}
		})

		return s
end



	function gadget:Initialize()
		if (glCreateShader == nil) then
			Spring.Echo("[unit_normalmap_shader:Initialize] no shader support")
			gadgetHandler:RemoveGadget()
			return
		end

		luaShader = CreateShader1()


		if (luaShader == nil) then
			Spring.Echo("[unit_normalmap_shader:Initialize] shader1 compilation failed")
			Spring.Echo(glGetShaderLog())
			gadgetHandler:RemoveGadget()
			return
		end

		SetShaderUniformLocations(luaShader)

		for unitDefID, unitDef in pairs(UnitDefs) do
			if (unitDef.customParams.normalmaps == "yes") then
				--Spring.Echo("Found Normalmap",unitDefID)
				normalMapNames[unitDefID] = {"unittextures/" .. unitDef.customParams.normalmap_name, true, true}
				--Spring.Echo(normalMapNames[unitDefID])
			end
		end
	end

	function gadget:Shutdown()
		for unitDefID, _ in pairs(UnitDefs) do
			if (preDisplayLists[unitDefID] ~= nil) then
				for i = 0, 1024 do
					if (preDisplayLists[unitDefID][i] ~= nil) then glDeleteList(preDisplayLists[unitDefID][i]) end
					if (pstDisplayLists[unitDefID][i] ~= nil) then glDeleteList(pstDisplayLists[unitDefID][i]) end
				end
			end
		end
		--glDeleteShader(luaShader or 0)
	end

	function gadget:RecvFromSynced(fun, unitID)
		if (fun == "MyUnitCrea") then MyUnitCrea(unitID) return true end
		if (fun == "MyUnitDest") then MyUnitDest(unitID) return true end
		return false
	end

	function gadget:DrawUnit(unitID, gameDrawMode)
		glUniformMatrix(luaShaderLocs.cameraInvMatrixLoc, glGetMatrixData("caminv")) -- Spring 0.78.2.*
		glUniformInt(luaShaderLocs.haveShadowsLoc, ((sprHaveShadows() and 1) or 0))

		if (sprHaveShadows()) then
			glUniform(luaShaderLocs.shadowParamsLoc, glGetShadowMapParams())
			glUniform(luaShaderLocs.shadowDensityLoc, glGetSun("shadowDensity", "unit"))
		end

		glUnitRaw(unitID, true)
		return true
	end
end


Last edited by Argh on 13 Aug 2009, 00:27, edited 1 time in total.
User avatar
koshi
Lobby Developer
Posts: 1059
Joined: 14 Aug 2007, 16:15

Re: Drawing Order

Post by koshi »

sounds to me like all sheep in scotland are black
User avatar
AF
AI Developer
Posts: 20687
Joined: 14 Sep 2004, 11:32

Re: Drawing Order

Post by AF »

Peet its quite simple, your point stands, but the execution of this thread has proven you right and then gone further unnecessarily. It's this furtherness that I am commenting on.

The developers have already stated why they think Argh is wrong and explained their point.

Yet argh continues to post in response, argh, if you are right then your results speak for themselves, every post you make arguing that you are correc tis not benefiting you or the community but actually damaging it.

Every developer who continues to respond to these arguements and repeat the same arguments and try to persuade argh are also demeaning themselves and perpetuate the thread.

This is a thread whose context is a flame war over who is right and wrong regardless of results. You've already made your points so why are you still reiterating them over and over again? If argh si wrong then anybody who follows his wisdom will also eb wrong and will get incorrect results and learn from the mistakes. Anyone who sees the wisdom of argh will also see the developers response, and only a fool would do something despite a set fo well reasoned good explanations of why it is wrong.

More time is spent here explainign why argh is wrong than is taken to actually explain the correct way of doing it before argh posts anything.

Argh spends more time arguing that he did it right than he does actually doing things.

Aegis speaks sense
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Re: Drawing Order

Post by Argh »

A simple depth-sort of the visible UnitIDs is not that big of a deal, AF. If jK hadn't decided that his ego rides on whether I'm right about anything, Lurker would have gotten it done and I'd be happily testing it.

20 minutes of coding. One test compile. That's all I'm asking for.
User avatar
lurker
Posts: 3842
Joined: 08 Jan 2007, 06:13

Re: Drawing Order

Post by lurker »

Because I am a motivated person that cares what people think.
User avatar
momfreeek
Posts: 625
Joined: 29 Apr 2008, 16:50

Re: Drawing Order

Post by momfreeek »

you borked at this:
Argh wrote:
KDR_11k wrote:Generally translucent surfaces are rendered last but not sorted. Just make sure you draw yours after everything else is drawn.
Then they'll just draw through mountains, etc., and what if you have transparent stuff on the underside of something? lol.
but then wrote this:
Argh wrote:I don't think that most professional engines bother depth-sorting the pieces. They're just doing what I did. They just draw the translucent stuff last and hope for the best, and 99% of the time, nobody can tell..
Is it me or is it you thats missing something obvious here?
Last edited by momfreeek on 13 Aug 2009, 04:21, edited 2 times in total.
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Re: Drawing Order

Post by Argh »

Is it me or is it you thats missing something obvious here?
No, I'm just mangling terminology, as usual. Makes it hard to make myself understood sometimes, I don't speak Graphic Engine Development.

I think that professional engines draw using a depth sort, per Unit-equivalent (or brush). They defer the objects that need alpha testing until the end of the drawing process per Unit-equivalent. I.E., they draw Unit-equivalent objects in depth order, then draw the Piece-equivelants in that Unit-equivalent in order of whether they're opaque or translucent.

They do this with a material system. Go look at a Fallout 3 GameBryo model. It's obvious that each sub-mesh has a material assigned. MD5? Same thing. Freelancer's engine? Same thing. They wouldn't do all be doing that, if there wasn't some agreement that that's the right way to do things.

In Freelancer's engine, for example, it's obvious that it works that way, because two translucent objects may be in the wrong order, leading to geometry being culled. Not only that, but you have to assign a "glass" material to objects for them to be translucent at all, since they use a shader per material. Since they didn't depth-sort the Piece equivalents, if you put a transparent dome inside another transparent dome, the second one is frequently totally culled. If they'd added an integer to the end of each Piece-equivalent's mesh specification, artists could have manually set up the drawing order for the best results under most circumstances, but they didn't, so it frequently borks.

Now, there may be new-fangled, more advanced ways to do it. I have no clue about that stuff, that's Deep Graphics Development of the CryEngine sort. But, short of doing a depth-sort of every triangle first, then doing alpha-tests, it's probably just a smarter, sleeker variation of the material system, where the real optimization is in the sorting procedures, not the basic process.

I faked the material system, by taking advantage of a funky element of S3O, which is that it draws strictly in the numerical order of the Pieces. I discovered this by accident, after I did the simple stuff. It works, and that's pretty much why all I need is a depth-sort of the UnitIDs, because then I have a chain of rendering order- farthest Unit first, then the next one draws, and probably won't have culling issues during the alpha test, because it's probably not behind the other unit's geometry at any point.

This will not result in a perfect result every time, as AF pointed out and I elaborated upon. The giant, transparent dome scenario will probably cause borks. I'm just not feeling like building one, just to prove this, though.

So, a secondary sort based on a boolean translucence UnitDef tag is probably necessary, to get the best sort with the lowest overhead and the fewest final errors.

Will it be 100% error-free? No. Does that matter a lot? No. Can I use what I have now, regardless of the outcome of this discussion? Yes. Does it look cooler than anything else on this engine atm? Yes.

So, given that... screw it, I surrender. I'm right, but if I can't get to prove it beyond all doubt, who cares.

I'll just accept that nobody will do this simple test setup, so that I can finish showing why jK's statements are erroneous, and move on. I don't need this level of hassle for what was such a minor request.

But, for the record, t's really lame that people can see screens of something working this well already and then choose to argue instead of cooperating to make it fully functional, especially after providing so much proof.
Last edited by Argh on 13 Aug 2009, 01:36, edited 1 time in total.
souledge
Posts: 23
Joined: 15 Jun 2008, 07:31

Re: Drawing Order

Post by souledge »

Argh wrote:Wish granted, the entire object, translucency 128:

Before:
http://www.wolfegames.com/TA_Section/gl ... rency8.jpg

After
http://www.wolfegames.com/TA_Section/gl ... rency9.jpgSo... eh... I guess you didn't get that whole thing about drawing order within the geometry. Are we all on the same page now?
...I have no idea what you're talking about, there are so many rendering problems with that picture and it's not even translucent!
The Arc on the top is clearly not translucent, I'm not even going to begin going through anything else. I asked for something colourful so rendering errors would be obvious.

For reference, this is an example of translucency correctly rendered (though the rendering technique is useless for spring): Image
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Re: Drawing Order

Post by Argh »

...I have no idea what you're talking about, there are so many rendering problems with that picture and it's not even translucent!
Wow... OK.. you're blind, eh? Maybe that's the problem here.

Here... lowered overall translucency to 15%.

Now, even if you're blind, you can see the shadowmap through the Unit geometry and the map's texture as well.
Image
ImageClick to zoom and see it.

Here, for the ultra-blind... I'll raise it off the ground, so that we can see things a bit clearer:

ImageSatisfied? Looks like translucency to me. Everything here is using the same setting, so it won't look like the tooth, nor am I drawing backfaces, so it won't look like the tooth, but the concept is exactly the same.
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Re: Drawing Order

Post by Argh »

Oh, wait... here. With backfaces on the inner curve of the domes...

ImageTotally massive overkill, for a game played from a mainly overhead perspective, but since apparently it takes a lot of screenshots to demonstrate the obvious...
souledge
Posts: 23
Joined: 15 Jun 2008, 07:31

Re: Drawing Order

Post by souledge »

....I give up....Maybe you'll wake up tomorrow and realise...
User avatar
momfreeek
Posts: 625
Joined: 29 Apr 2008, 16:50

Re: Drawing Order

Post by momfreeek »

ok, even shorter quotes:

this was the solution that you borked at:
KDR_11k wrote:translucent surfaces are rendered last
this is how you fixed your problem internally:
Argh wrote:draw the translucent stuff last
where's the mix up in terminology?

from what i understand there's one obvious, massive optimisation to your proposed solution: you don't need to include fully opaque models in the sort.. just draw them all first.
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Re: Drawing Order

Post by Argh »

Ok... I've moved everything to DrawWorld, where it probably should have been in the first place, because that lets us do arbitrary crap like what I want, let alone what other people will want.

It's not working perfectly yet. There are some hideous flaws that I haven't addressed yet. But it's back to this point:

Image

I'll post the code when it works in a halfway-decent fashion, it's still really nasty.
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Re: Drawing Order

Post by Argh »

Big, fat, edit:

It was almost there, but one minor bork remained. Now it's there, other than writing the actual depth-sort, and figuring out where this can be optimized a lot better.

Fixed the matrix issue. Camerainv was commented out in the SUR section for some reason. Oh well. Now I really have to get a nap. Here's updated (correctly-working) sourcecode of the DrawWorld implementation:

Code: Select all

function gadget:GetInfo()
   return {
      name      = "unit_normalmap_shader_tst.lua",
      desc      = "adds normal-mapping to S3O models",
      author    = "Kloot",
      date      = "31-1-2009",
      license   = "GPL v2",
      layer     =  0,
      enabled   = true
   }
end

if (gadgetHandler:IsSyncedCode()) then
	function gadget:Initialize()
		-- desc      = "adds normal-mapping to S3O models (gadgetized)",
		-- author    = "Kloot",
		-- date      = "April 6, 2009",
		-- license   = "GPL v2",
	end

	function gadget:UnitGiven(unitID)
		SendToUnsynced("MyUnitCrea", unitID)
		return true
	end

	function gadget:UnitCreated(unitID)
		SendToUnsynced("MyUnitCrea", unitID)
		return true
	end

	function gadget:UnitDestroyed(unitID)
		SendToUnsynced("MyUnitDest", unitID)
		return true
	end

else

	local glLoadIdentity       = gl.LoadIdentity
	local glPushMatrix         = gl.PushMatrix
	local glPopMatrix          = gl.PopMatrix
	local glTranslate          = gl.Translate
	local glBeginEnd           = gl.BeginEnd
	local glNormal             = gl.Normal
	local glVertex             = gl.Vertex
	local glColor              = gl.Color
	local glLight              = gl.Light
	local glLighting           = gl.Lighting
	local glBlending           = gl.Blending
	local glPushAttrib         = gl.PushAttrib
	local glPopAttrib          = gl.PopAttrib

	local glCulling            = gl.Culling
	local glDepthMask          = gl.DepthMask
	local glDepthTest          = gl.DepthTest
	local glAlphaTest 	= gl.AlphaTest

	local glCreateList         = gl.CreateList
	local glDeleteList         = gl.DeleteList

	local glUnit               = gl.Unit
	local glUnitRaw            = gl.UnitRaw
	local glTexture            = gl.Texture
	local glTexCoord           = gl.TexCoord
	local glMultiTexCoord      = gl.MultiTexCoord
	local glUnitMultMatrix     = gl.UnitMultMatrix

	local glGetSun             = gl.GetSun
	local glGetShadowMapParams = gl.GetShadowMapParams
	local glGetMatrixData      = gl.GetMatrixData

	local glGetShaderLog       = gl.GetShaderLog
	local glCreateShader       = gl.CreateShader
	local glDeleteShader       = gl.DeleteShader
	local glUseShader          = gl.UseShader

	local glUniformMatrix      = gl.UniformMatrix
	local glUniformInt         = gl.UniformInt
	local glUniform            = gl.Uniform
	local glGetUniformLocation = gl.GetUniformLocation
	local glGetActiveUniforms  = gl.GetActiveUniforms

	local normalMapList = {}
	local normalMapNames      = {}
	local textureNames        = {}
	local preDisplayLists     = {}
	local pstDisplayLists     = {}
	local luaShader           = nil

	local luaShaderLocs = {
		cameraMatrixLoc     = -1,
		cameraInvMatrixLoc  = -1,
		shadowMatrixLoc     = -1,
		shadowParamsLoc     = -1,
		shadowDensityLoc    = -1,

		unitAmbientLightLoc = -1,
		unitDiffuseLightLoc = -1,

		shadowMapLoc        = -1,
		textureS3O1Loc      = -1,
		textureS3O2Loc      = -1,
		--specularMapLoc      = -1,
		reflectMapLoc       = -1,
		normalMapLoc        = -1,
	}

	local sprGetGameFrame           = Spring.GetGameFrame
	local sprGetUnitDefID           = Spring.GetUnitDefID
	local sprGetAllUnits            = Spring.GetAllUnits
	local sprGetVisibleUnits        = Spring.GetVisibleUnits
	local sprIsUnitVisible          = Spring.IsUnitVisible
	local sprGetUnitTeam            = Spring.GetUnitTeam
	local sprGetCameraPosition      = Spring.GetCameraPosition
	local sprGetTeamColor           = Spring.GetTeamColor
	local sprSetUnitNoDraw          = Spring.SetUnitNoDraw
	local sprHaveShadows            = Spring.HaveShadows
	local sprGetUnitTransformMatrix = Spring.GetUnitTransformMatrix
	local SUR                       = Spring.UnitRendering





	local function GetPreDisplayList(unitID)
		local unitTeam = sprGetUnitTeam(unitID)
		local unitDefID = sprGetUnitDefID(unitID)

		if (preDisplayLists[unitDefID] == nil) then
			preDisplayLists[unitDefID] = {}
		end

		if (preDisplayLists[unitDefID][unitTeam] == nil) then
			local sdx, sdy, sdz = glGetSun("pos")
			local tcr, tcg, tcb, tca = sprGetTeamColor(unitTeam)

			preDisplayLists[unitDefID][unitTeam] = glCreateList(
				function()
					glPushAttrib(GL_ALL_ATTRIB_BITS)
					glAlphaTest(GL.GREATER,0.01)
					glBlending(GL.SRC_ALPHA, GL.ONE_MINUS_SRC_ALPHA)
					glDepthMask(true)
					glDepthTest(GL.LEQUAL)
					glCulling(GL.BACK)

					glLighting(true)
					glLight(0, true)
					glLight(1, false)
					glLight(0, GL.POSITION, sdx, sdy, sdz, 0)

					glPushMatrix()
					glColor(tcr, tcg, tcb, tca)
					glTexture(3, "unittextures/" .. UnitDefs[unitDefID].customParams.normalmap_name)
				end)
		end

		return preDisplayLists[unitDefID][unitTeam]
	end

	local function GetPostDisplayList(unitID)
		local unitTeam = sprGetUnitTeam(unitID)
		local unitDefID = sprGetUnitDefID(unitID)

		if (pstDisplayLists[unitDefID] == nil) then
			pstDisplayLists[unitDefID] = {}
		end

		if (pstDisplayLists[unitDefID][unitTeam] == nil) then
			pstDisplayLists[unitDefID][unitTeam] = glCreateList(
				function()
               glTexture(3, false)
               glColor(1.0, 1.0, 1.0, 1.0)
               glPopMatrix()

               glLight(0, false)
               glLighting(false)

               glCulling(GL.FRONT)
               glDepthTest(false)
               glDepthMask(false)
               glBlending(true)
               glPopAttrib()
				end)
		end

		return pstDisplayLists[unitDefID][unitTeam]
	end

	local function GetUnitDefMaterial(unitDefID, preDL, pstDL)
		local matTbl = {
			texunits = {
				[0] = {tex = textureNames[unitDefID][1],   enable = true},
				[1] = {tex = textureNames[unitDefID][2],   enable = true},
				[2] = {tex = "$reflection",                enable = true},
				[3] = {tex = "unittextures/" .. UnitDefs[unitDefID].customParams.normalmap_name, enable = true},
				[4] = {tex = "$shadow",                    enable = true}
			},

			culling         = GL.BACK,
			shader          = luaShader,
			cameraloc       = luaShaderLocs.cameraMatrixLoc,
			camerainvloc    = luaShaderLocs.cameraInvMatrixLoc, -- Spring 0.79
			shadowloc       = luaShaderLocs.shadowMatrixLoc,
			shadowparamsloc = luaShaderLocs.shadowParamsLoc,
			prelist         = preDL,
			postlist        = pstDL
		}
		return matTbl
	end


	local function MyUnitCrea(unitID)
		local unitDefID = sprGetUnitDefID(unitID)

		if (normalMapNames[unitDefID] ~= nil) then
			if (textureNames[unitDefID] == nil) then
				textureNames[unitDefID] = {
					[1] = '%' .. unitDefID .. ":0",
					[2] = '%' .. unitDefID .. ":1"
				}
			end

			--Spring.Echo("Found Unit",unitID)

			local preDL = GetPreDisplayList(unitID)
			local pstDL = GetPostDisplayList(unitID)

			SUR.SetLODCount(unitID, 1)
			SUR.SetMaterial(unitID, 1, "opaque", GetUnitDefMaterial(unitDefID, preDL, pstDL))
			SUR.SetUnitLuaDraw(unitID, true)

			for pieceID, pieceName in pairs(Spring.GetUnitPieceList(unitID) or {}) do
				if (pieceID ~= "n") then
					SUR.SetPieceList(unitID, 1, pieceID)
				end
			end
		end
	end

	local function MyUnitDest(unitID)
		local unitDefID = sprGetUnitDefID(unitID)

		if (normalMapNames[unitDefID] ~= nil) then
			SUR.SetUnitLuaDraw(unitID, false)
			SUR.SetLODCount(unitID, 0)
		end
	end





local function CreateShader1()
				local s = glCreateShader({
			vertex = [[

				varying vec3 lvES;
				varying vec3 hvES;
				varying vec3 nvES;

				varying mat3 tbnInvMatrix;
				varying vec3 cdES;

				uniform int haveShadows;
				uniform mat4 shadowMatrix;
				uniform vec4 shadowParams;
				uniform mat4 cameraMatrix;
				uniform mat4 cameraInvMatrix;

				void main(void) {
					mat4 modelMatrix = cameraInvMatrix * gl_ModelViewMatrix;
					mat4 modelInvMatrix = gl_ModelViewMatrixInverse * cameraMatrix;

					vec3 vpES = (gl_ModelViewMatrix * gl_Vertex).xyz;
					vec3 cpES = vec3(0.0, 0.0, 1.0);

					vec3 svOS = gl_MultiTexCoord5.xyz;
					vec3 tvOS = gl_MultiTexCoord6.xyz;
					
					//Manual transform of the matrix, for GLSL 1.X compatibility
					mat3 tbnMatrix = mat3(svOS, tvOS, gl_Normal);
					tbnInvMatrix[0].x = tbnMatrix[0].x;
					tbnInvMatrix[0].y = tbnMatrix[1].x;
					tbnInvMatrix[0].z = tbnMatrix[2].x;

					tbnInvMatrix[1].x = tbnMatrix[0].y;
					tbnInvMatrix[1].y = tbnMatrix[1].y;
					tbnInvMatrix[1].z = tbnMatrix[2].y;

					tbnInvMatrix[2].x = tbnMatrix[0].z;
					tbnInvMatrix[2].y = tbnMatrix[1].z;
					tbnInvMatrix[2].z = tbnMatrix[2].z;
						
					cdES = (vpES - cpES);

					nvES = normalize(gl_NormalMatrix * gl_Normal);
					lvES = normalize(gl_LightSource[0].position.xyz);
					hvES = normalize(gl_LightSource[0].halfVector.xyz);


					gl_FrontColor = gl_Color;
					gl_TexCoord[0].st  = gl_MultiTexCoord0.st;
					gl_Position = gl_ProjectionMatrix * cameraMatrix * modelMatrix * gl_Vertex;


					if (haveShadows != 0) {
						vec4 vpWS = (modelMatrix * gl_Vertex);
						gl_TexCoord[3] = shadowMatrix * vpWS;
						
						gl_TexCoord[3].st *= (1 / sqrt(abs(gl_TexCoord[3].st) + shadowParams.z) + shadowParams.w);
						gl_TexCoord[3].st += shadowParams.xy;
					}
				}
			]],

			fragment = [[

				varying vec3 lvES;
				varying vec3 hvES;
				varying vec3 nvES;

				varying vec3 cdES;

				uniform sampler2D textureS3O1;
				uniform sampler2D textureS3O2;

				uniform samplerCube reflectMap;
				uniform sampler2D normalMap;

				uniform sampler2D shadowMap;
				uniform int haveShadows;

				uniform vec3 unitAmbientLight;
				uniform vec3 unitDiffuseLight;

				varying mat3 tbnInvMatrix;

				void main(void) {

						//Manual transform of the matrix, for GLSL 1.X compatibility
						mat3 tbnMatrix;

						tbnMatrix[0].x = tbnInvMatrix[0].x;
						tbnMatrix[0].y = tbnInvMatrix[1].x;
						tbnMatrix[0].z = tbnInvMatrix[2].x;

						tbnMatrix[1].x = tbnInvMatrix[0].y;
						tbnMatrix[1].y = tbnInvMatrix[1].y;
						tbnMatrix[1].z = tbnInvMatrix[2].y;

						tbnMatrix[2].x = tbnInvMatrix[0].z;
						tbnMatrix[2].y = tbnInvMatrix[1].z;
						tbnMatrix[2].z = tbnInvMatrix[2].z;

					vec2 tc = vec2(gl_TexCoord[0].s, gl_TexCoord[0].t);

					vec3 nvTS = ((texture2D(normalMap, tc) * 2.0) - 1.0);

					vec4 basicColor = texture2D(textureS3O1, tc);
					vec4 extraColor = texture2D(textureS3O2, tc);

					float nvDOTlv = 0.0;
					float nvDOThv = 0.0;
					vec3 reDirES;

					vec3 nv_OS = normalize(tbnMatrix * nvTS);
					vec3 nv_ES = normalize(gl_NormalMatrix * nv_OS);

					nvDOTlv = max(nvDOTlv, dot(nv_ES, lvES));
					nvDOThv = max(nvDOThv, dot(nv_ES, hvES));
					reDirES = reflect(normalize(cdES), nv_ES);

					float shininess = extraColor.g * 4.0;

					float specPow =
						(nvDOTlv > 0.0 && nvDOThv > 0.0)?
						max(0.0, pow(nvDOThv, shininess)):
						0.0;

					if (extraColor.b > 0.0)
					{
						specPow = specPow * extraColor.b;
					}

					vec3 specColor = textureCube(reflectMap, reDirES).rgb * specPow * extraColor.g;
					vec3 reflColor = textureCube(reflectMap, reDirES).rgb;
					vec3 diffColor = (unitDiffuseLight * nvDOTlv) + unitAmbientLight * 1.25;

					reflColor = mix(diffColor, reflColor, extraColor.g);
					reflColor += extraColor.r;

					gl_FragColor = basicColor;
					gl_FragColor.rgb = mix(gl_FragColor.rgb, gl_Color.rgb, gl_FragColor.a);
					gl_FragColor.rgb = gl_FragColor.rgb * reflColor + specColor;

					if(haveShadows != 0)
					{
						vec2 tc = vec2(gl_TexCoord[3].s, gl_TexCoord[3].t);
						float depth = texture2D(shadowMap, tc).z;
						if (depth <  0.05)
						{
							gl_FragColor.rgb = gl_FragColor.rgb * vec3(extraColor.r + unitAmbientLight.r + extraColor.g, 

extraColor.r + unitAmbientLight.g + extraColor.g, extraColor.r + unitAmbientLight.b + extraColor.g);

							if (basicColor.a > 0.0)
							{
								gl_FragColor.rgb = mix(gl_FragColor.rgb, gl_Color, basicColor.a);
							}
						}						
					}

					gl_FragColor.a   = extraColor.a;
				}
			]],

			uniformInt = {
				textureS3O1 = 0,
				textureS3O2 = 1,
				reflectMap  = 2,
				normalMap   = 3,
				shadowMap   = 4,
			},
			uniform = {
				unitAmbientLight = {glGetSun("ambient", "unit")},
				unitDiffuseLight = {glGetSun("diffuse", "unit")},
			},
			uniformMatrix = {
				shadowMatrix = {glGetMatrixData("shadow")},
			}
		})

		return s
end


	local function SetShaderUniformLocations(s)
		luaShaderLocs.cameraMatrixLoc     = glGetUniformLocation(s, "cameraMatrix")
		luaShaderLocs.cameraInvMatrixLoc  = glGetUniformLocation(s, "cameraInvMatrix")
		luaShaderLocs.shadowMatrixLoc     = glGetUniformLocation(s, "shadowMatrix")

		luaShaderLocs.haveShadowsLoc      = glGetUniformLocation(luaShader, "haveShadows")
		luaShaderLocs.shadowParamsLoc     = glGetUniformLocation(luaShader, "shadowParams")
		luaShaderLocs.shadowDensityLoc    = glGetUniformLocation(luaShader, "shadowDensity")
	end


	function gadget:Initialize()
		if (glCreateShader == nil) then
			Spring.Echo("[unit_normalmap_shader:Initialize] no shader support")
			gadgetHandler:RemoveGadget()
			return
		end

		luaShader = CreateShader1()


		if (luaShader == nil) then
			Spring.Echo("[unit_normalmap_shader:Initialize] shader1 compilation failed")
			Spring.Echo(glGetShaderLog())
			gadgetHandler:RemoveGadget()
			return
		end

		SetShaderUniformLocations(luaShader)

		for unitDefID, unitDef in pairs(UnitDefs) do
			if (unitDef.customParams.normalmaps == "yes") then
				--Spring.Echo("Found Normalmap",unitDefID)
				normalMapNames[unitDefID] = {"unittextures/" .. unitDef.customParams.normalmap_name, true, true}
				--Spring.Echo(normalMapNames[unitDefID])
				table.insert(normalMapList,unitDefID,1)
			end
		end
	end

	function gadget:Shutdown()

	end

   function gadget:RecvFromSynced(fun, unitID)
      if (fun == "MyUnitCrea") then MyUnitCrea(unitID) return true end
      if (fun == "MyUnitDest") then MyUnitDest(unitID) return true end
      return false
   end


	function gadget:DrawUnit(unitID, gameDrawMode)
		ud = Spring.GetUnitDefID(unitID)
		if normalMapList[ud] then
			return false
		else
			return true
		end
	end


	local unitIDList = {}
	local renderPassList = {}
	function gadget:DrawWorld()

	local frame = Spring.GetGameFrame()
	if (((frame + 5) % 15) < 0.1) then
		Spring.Echo("updating list")
		unitIDList = Spring.GetVisibleUnits(-1,5000,false)

		for _,unitID in ipairs(unitIDList) do
			id = Spring.GetUnitDefID(unitID)
			if normalMapList[id] == nil then
				table.remove(unitIDList,unitID)
			end
		end
			
	end

	if unitIDList[1] ~= nil then
		for i,unitID in ipairs(unitIDList) do
			glUniformMatrix(luaShaderLocs.cameraInvMatrixLoc, glGetMatrixData("caminv")) -- Spring 0.78.2.*
			glUniformInt(luaShaderLocs.haveShadowsLoc, ((sprHaveShadows() and 1) or 0))

			if (sprHaveShadows()) then
				glUniform(luaShaderLocs.shadowParamsLoc, glGetShadowMapParams())
				glUniform(luaShaderLocs.shadowDensityLoc, glGetSun("shadowDensity", "unit"))
			end
			glUseShader(luaShader)
		end
	end


	end
end


User avatar
hoijui
Former Engine Dev
Posts: 4344
Joined: 22 Sep 2007, 09:51

Re: Drawing Order

Post by hoijui »

what about this:
Argh writes the dept sort of units for spring himself.
He does it very simple, using one point per unit, eg the center of hte model or something. As i get it, this is simple map, and can be done fast, right?
so he does that, and if it does not hurt performance at all, in BA eg, we include it, and possibly make it a mod option.
Then we have no work, Argh has what he wants, and if he falsly thinks it is benefitial, nobody else has to pay for it.
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Re: Drawing Order

Post by Argh »

I built the sort in Lua already. It works just fine, and costs practically nothing, even in Lua, and even with a couple of hundred Units on the screen. I run it every SlowUpdate or so, and that's fine.

It doesn't solve my problem, though.

All Units we want to render must go through the UnitRendering pathway, which is locked to UnitID order. Or you can do gl.Unit, but then you don't have a TBN matrix.

This absolutely must get done through the engine, basically.
Post Reply

Return to “Engine”