Simple Real-Time lighting (example code) - Page 3

Simple Real-Time lighting (example code)

Discuss Lua based Spring scripts (LuaUI widgets, mission scripts, gaia scripts, mod-rules scripts, scripted keybindings, etc...)

Moderator: Moderators

dizekat
Posts: 438
Joined: 07 Dec 2007, 12:10

Re: Simple Real-Time lighting (example code)

Post by dizekat »

I did some testing. It indeed did not work as it should work, because of this:

Code: Select all

	else if (args == 6) {
		GLfloat array[4];
		const GLenum pname = (GLenum)luaL_checknumber(L, 2);
		array[0] = (GLfloat)luaL_checknumber(L, 3);
		array[1] = (GLfloat)luaL_checknumber(L, 4);
		array[2] = (GLfloat)luaL_checknumber(L, 5);
		array[3] = (GLfloat)luaL_checknumber(L, 5);
		glLightfv(light, pname, array);
	}
(piece of lua opengl wrapper. note the 5 appearing 2 times...)
Recompiling spring with fix and checking.
dizekat
Posts: 438
Joined: 07 Dec 2007, 12:10

Re: Simple Real-Time lighting (example code)

Post by dizekat »

Code: Select all

function widget:GetInfo()
  return {
    name      = "Lighting Test",
    desc      = "Test of point lights.",
    author    = "dizekat, Argh",
    date      = "November 6, 2008",
    license   = "Public Domain, or the least-restrictive rights in your country of residence",
    layer     = 0,
    --handler   = true,
    enabled  = true -- loaded by default?
  }
end

function widget:DrawWorld()   
   local myIDList = Spring.GetVisibleUnits(-1,3000,false)
      if myIDList[1] ~= nil then
	 gl.PushMatrix()
	 gl.Translate(0,50,0)--- just draw ghosts above regular units, to see whats going wrong
         local t=Spring.GetGameSeconds()   
  	 local offset_x,offset_y=150*math.sin(t*math.pi),150*math.cos(t*math.pi) --- make lights circle around units, one revolution every 2 game seconds.
         for _,myID in ipairs(myIDList) do
               local x,y,z = Spring.GetUnitPosition(myID)
		x=x+offset_x
		y=y+offset_y

		gl.Lighting(false)-- draw a white square at light source's position.
		gl.PushMatrix()
		gl.Translate(x,y,z)
		gl.Color(1,1,1,1)
		gl.Culling(false)
		gl.Shape(GL.QUADS,{{v={-5,0,-5}},{v={5,0,-5}},{v={5,0,5}},{v={-5,0,5}}})
		gl.PopMatrix()	

               gl.DepthTest(GL.LEQUAL)
               gl.Culling(GL.FRONT)--- argh, you're pure gold. setting it to GL.BACK . LMAO
               gl.Lighting(true)
	       --gl.Enable(GL.LIGHT0) --- damn it. I prefer more plain wrappers
	       gl.Light(0,true) --- enable light 0
	       gl.Light(1,false) --- disable light 1, spring apparently uses light 1 for something
	
               gl.Light(0,GL.POSITION, x, y, z ,1)--- set point light's position
	       gl.Light(0,GL.DIFFUSE, 1,1,1 ,1)-- set light color to white
               --gl.Color(1, 0, 0, 1.0)
               --gl.PolygonOffset(-2,-2)       
	       
               gl.Unit(myID,true)
                     
               gl.Light(0,false)
               --gl.PolygonOffset(0,0)
               gl.ResetState()
               gl.Lighting(false)
      end
      gl.PopMatrix()
   end   
end
-----------------------------------------------------------------------------------

There ya go. It works, but only with custom build where
int LuaOpenGL::Light(lua_State* L) function is fixed in rts/Lua/LuaOpenGL.cpp

Code: Select all

int LuaOpenGL::Light(lua_State* L)
{
	CheckDrawingEnabled(L, __FUNCTION__);

	const GLenum light = GL_LIGHT0 + (GLint)luaL_checknumber(L, 1);
	if ((light < GL_LIGHT0) || (light > GL_LIGHT7)) {
		luaL_error(L, "Bad light number in gl.Light");
	}

	if (lua_isboolean(L, 2)) {
		if (lua_toboolean(L, 2)) {
			glEnable(light);
		} else {
			glDisable(light);
		}
		return 0;
	}

	const int args = lua_gettop(L); // number of arguments
	if (args == 3) {
		const GLenum pname = (GLenum)luaL_checknumber(L, 2);
		const GLenum param = (GLenum)luaL_checknumber(L, 3);
		glLightf(light, pname, param);
	}
	else if (args == 5) {
		GLfloat array[4]; // NOTE: 4 instead of 3  (to be safe)
		const GLenum pname = (GLenum)luaL_checknumber(L, 2);
		array[0] = (GLfloat)luaL_checknumber(L, 3);
		array[1] = (GLfloat)luaL_checknumber(L, 4);
		array[2] = (GLfloat)luaL_checknumber(L, 5);
		array[3] = 0;
		glLightfv(light, pname, array);
	}
	else if (args == 6) {
		GLfloat array[4];
		const GLenum pname = (GLenum)luaL_checknumber(L, 2);
		array[0] = (GLfloat)luaL_checknumber(L, 3);
		array[1] = (GLfloat)luaL_checknumber(L, 4);
		array[2] = (GLfloat)luaL_checknumber(L, 5);
		array[3] = (GLfloat)luaL_checknumber(L, 6);
		glLightfv(light, pname, array);
	}
	else {
		luaL_error(L, "Incorrect arguments to gl.Light");
	}

	return 0;
}
jK, can you apply fix in SVN?
edit: changed initialization, just using array[3]=0;
Last edited by dizekat on 07 Nov 2008, 15:56, edited 1 time in total.
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Re: Simple Real-Time lighting (example code)

Post by Argh »

@Dizekat: So, it was actually broken, as I was starting to suspect. Figures, nobody's used this before me. I guess I'll give it another go (and implement a more complex lighting model, since that's starting to make some sense, finally) here in a bit, if the fix is committed.

@Andrej: if it makes you feel any better, I've been failing at making shaders for a month ;)
dizekat
Posts: 438
Joined: 07 Dec 2007, 12:10

Re: Simple Real-Time lighting (example code)

Post by dizekat »

Argh wrote:@Dizekat: So, it was actually broken, as I was starting to suspect. Figures, nobody's used this before me. I guess I'll give it another go (and implement a more complex lighting model, since that's starting to make some sense, finally) here in a bit, if the fix is committed.
Well the way you did it, it wouldn't have worked correctly even if spring code was correct. Even culling, you did set so it did draw the bits on *back side of the unit*.
When that fix's applied, you can use my code for setting light position, and use that shader that has (gl_ModelView*gl_Vertex).xyz for the vertex position, in that specific order.edit: but dont forget that you'd have to provide attenuation parameters to that point light shader. Thing is, the problems you're getting are, for most part, not with shader per se. Shader isnt like texture image, its a bit of program code that takes some input and gives some output, and for it to give you the image you need, the input must be what shader needs.
User avatar
jK
Spring Developer
Posts: 2299
Joined: 28 Jun 2007, 07:30

Re: Simple Real-Time lighting (example code)

Post by jK »

changed initialization, just using array[3]=0;
The "to be safe" note doesn't mean it tries to fix the user input, it just prevent an opengl overflow (-> crashes). So I don't really think it is needed.
But I will commit the bugfix (thx for spotting, even if trepan wrote it ^^).
dizekat wrote:Even culling, you did set so it did draw the bits on *back side of the unit*.
s3o uses inverted normals or rather clockwise vertex order than opengl's default GL_CCW. (3do doesn't use any culling)
Argh wrote:@Dizekat: So, it was actually broken, as I was starting to suspect. Figures, nobody's used this before me. I guess I'll give it another go (and implement a more complex lighting model, since that's starting to make some sense, finally) here in a bit, if the fix is committed.
If you have read any OpenGL3.0 news, all that lighting stuff is deprecated. So it is redundant when you use a shader.
dizekat
Posts: 438
Joined: 07 Dec 2007, 12:10

Re: Simple Real-Time lighting (example code)

Post by dizekat »

jK wrote:
changed initialization, just using array[3]=0;
The "to be safe" note doesn't mean it tries to fix the user input, it just prevent an opengl overflow (-> crashes).
crashes? it couldn't possibly segfault even with 3. Just would read outside the array, which is on stack. So this is still valid memory, no segfault here.
It could read NAN, though, dunno what would be implications (driver freaking out and rendering real slowly?). But that is the same regardless if you use array of size 3 or array of size 4 with fourth element uninitialized.
dizekat wrote:Even culling, you did set so it did draw the bits on *back side of the unit*.
s3o uses inverted normals or rather clockwise vertex order than opengl's default GL_CCW. (3do doesn't use any culling)
Hmm. Quite odd. That code with culling, it did just draw the back side of units in BA.

Wouldn't it be sane thing to process models on load to make triangles in some consistent ordering, and use some same culling for all formats.
Argh wrote:@Dizekat: So, it was actually broken, as I was starting to suspect. Figures, nobody's used this before me. I guess I'll give it another go (and implement a more complex lighting model, since that's starting to make some sense, finally) here in a bit, if the fix is committed.
If you have read any OpenGL3.0 news, all that lighting stuff is deprecated. So it is redundant when you use a shader.
You mean glLight(0,GL_POSITION,x,y,z,w) is deprecated?
http://www.opengl.org/sdk/docs/man/xhtml/glLight.xml
until official docs say its deprecated in 3.0, it is not.
edit:
http://www.khronos.org/opengl/
see chapter 2.19.2
edit: nvm. Whatever people made that documentation, they definitely sux. List of features first, without any (deprecated) tags besides name. Then list of deprecated functions, separately. Lol, everything is deprecated except barest minimum, yet it still sux for driver manufacturers because crap like texture handle lookups is still needed.
Last edited by dizekat on 07 Nov 2008, 19:43, edited 1 time in total.
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Re: Simple Real-Time lighting (example code)

Post by Argh »

I'll give this one more go on Sunday, if the fix has been committed by then. Can't spend more time on this until then, and I really shouldn't then, but a small delay that includes it, fixed, is probably worth the wait, compared to just running with what I've got- the basic setups for everything other than some specific stuff that I didn't want to mess with until I had the matrix issues straightened out is done already.
User avatar
jK
Spring Developer
Posts: 2299
Joined: 28 Jun 2007, 07:30

Re: Simple Real-Time lighting (example code)

Post by jK »

dizekat wrote:
jK wrote:The "to be safe" note doesn't mean it tries to fix the user input, it just prevent an opengl overflow (-> crashes).
crashes? it couldn't possibly segfault even with 3. Just would read outside the array, which is on stack. So this is still valid memory, no segfault here.
What if the program isn't allowed to read that memory data (new processors allow you to seal specific memory, etc.)?
dizekat wrote:
dizekat wrote:Even culling, you did set so it did draw the bits on *back side of the unit*.
s3o uses inverted normals or rather clockwise vertex order than opengl's default GL_CCW. (3do doesn't use any culling)
Hmm. Quite odd. That code with culling, it did just draw the back side of units in BA.
Wouldn't it be sane thing to process models on load to make triangles in some consistent ordering, and use some same culling for all formats.
Hmm sorry, it is the opposite, s3o use default orientation and 3do is clockwise. But still 3do don't use any culling, so it is not an orientation issue why both formats needs different settings.
dizekat
Posts: 438
Joined: 07 Dec 2007, 12:10

Re: Simple Real-Time lighting (example code)

Post by dizekat »

jK wrote: What if the program isn't allowed to read that memory data (new processors allow you to seal specific memory, etc.)?
It is on stack. Think a little. Assuming no alignment:
float a[3];
SomeFunction(a); /// here return address is written to the exact memory place pointed by a[4] , and is read when returning from function, or when exception happens, or when stack walker makes stacktrace, or whatever else.
and assuming theres alignment, its just some unused memory. There's no reason why read of this would ever be forbidden, especially considering that you can read as much stack as you want by just reading from uninitialized array.
Thats why i thought the "safe" remark was quite a bit lulz, when not initializing anyway.
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Re: Simple Real-Time lighting (example code)

Post by Argh »

Ok, folks. In SVN 6991, it is now possible to use this shader properly, with a minor change (I found that I have to multiply the normals by the normal matrix before the results are right).

Here is the resulting source. Tested, seems to be working well, and I've corrected the efficiency problems, I think:

Code: Select all

function gadget:GetInfo()
  return {
    name      = "GLSL Lighting",
    desc      = "The P.U.R.E. GLSL Realtime lighting implementation.",
    author    = "Argh",
    date      = "November 7, 2008",
    license   = "Public Domain, or the least-restrictive rights in your country of residence",
    layer     = 0,
    enabled  = true -- loaded by default?
  }
end

if (gadgetHandler:IsSyncedCode()) then
----------------------------------------------------------------------------------------------------------SYNCED
local function CreateLightMe(u, ud, team, p, r, g, b, a)
	p = Spring.GetUnitScriptPiece(u,p)
	r = r / 255
	g = g / 255
	b = b / 255
	a = a / 255
	SendToUnsynced("CreateLight",u, ud, team, p, r, g, b, a)
end

local function DestroyLightMe(u, ud, team)
	SendToUnsynced("DestroyLight",u, ud, team)
end

function gadget:Initialize()
	gadgetHandler:RegisterGlobal("CreateLightMe", CreateLightMe)
	gadgetHandler:RegisterGlobal("DestroyLightMe", DestroyLightMe)
end

function gadget:UnitDestroyed(u,ud,team)
	SendToUnsynced("DestroyLight",u, ud, team)
end

----------------------------------------------------------------------------------------------------------END SYNCED
else
----------------------------------------------------------------------------------------------------------UNSYNCED
local UseShader = 0
local LP

function gadget:Initialize()
GLSL_LIGHT_Shader = gl.CreateShader({
    vertex = [[
varying vec4 diffuse;
void main()
{
   gl_Position = ftransform();
   vec3 normal = gl_NormalMatrix * gl_Normal;
	vec3 lightVector = gl_LightSource[1].position.xyz - (gl_ModelViewMatrix * gl_Vertex);
	float dist = length(lightVector);
	float attenuation = 1.0 / (gl_LightSource[1].constantAttenuation +
		gl_LightSource[1].linearAttenuation * dist +
		gl_LightSource[1].quadraticAttenuation * dist * dist);
	lightVector = normalize(lightVector);
	float nxDir = max(0.0, dot(normal, lightVector));
	diffuse = gl_FrontMaterial.diffuse * nxDir * attenuation;
}

]],
   fragment = [[
	varying vec4 diffuse;
	void main()
	{
		gl_FragColor = (gl_LightSource[1].ambient + diffuse);
	}
    ]],
})

	if (GLSL_LIGHT_Shader == nil) then
		Spring.Echo("GLSL Light Shader Failed"..gl.GetShaderLog())
		return false
	else
		Spring.Echo("GLSL Light Shader Succeeded")

		UseShader = 1;
	end
end

local tinsert = table.insert
local tremove = table.remove
local LightList = {piece, red, green, blue, alpha}
local GetUnitPiecePosDir = Spring.GetUnitPiecePosDir

function gadget:RecvFromSynced(name, u, ud, team, p, r, g, b, a)
	if name == "CreateLight" then
		if LightList[u] ~= nil then 
			LightList[u] = nil
			Spring.Echo("table removed")
		end
		tinsert(LightList,u,{piece = p, red = r, green = g, blue = b, alpha = a})
	end
	if name == "DestroyLight" then
		if LightList[u] ~= nil then 
			LightList[u] = nil
			Spring.Echo("table removed by Destroy")
		end
	end
end

function gadget:DrawWorld()
	if UseShader == 1 then
	local myIDList = Spring.GetVisibleUnits(-1,3000,false)
		if myIDList[1] ~= nil then
			for _,myID in ipairs(myIDList) do
				if (Spring.IsUnitVisible(myID)) then
					if LightList[myID] ~= nil then
						gl.DepthTest(GL.LEQUAL)
						gl.Culling(GL.BACK)
						gl.Blending(true)
						gl.Lighting(true)
						
						local x,y,z = Spring.GetUnitPiecePosDir(myID,LightList[myID].piece)

						gl.Light(1,GL.POSITION,x,y,z,1)
						gl.Material ({
						ambient   = {0, 0, 0, 0},
						diffuse   = {LightList[myID].red,LightList[myID].green,LightList[myID].blue,LightList[myID].alpha},
						ambidiff  = {0, 0, 0, 0},
						emission  = {0, 0, 0, 0},
						specular  = {0, 0, 0, 0},
						shininess = 10
						})
						gl.UseShader(GLSL_LIGHT_Shader)
						gl.PolygonOffset(-3,-3)
						gl.Unit(myID,true)
						
						gl.Light(0,false)
						gl.PolygonOffset(0,0)
						gl.ResetState()
						gl.Lighting(false)
					end
				end
			end
		end
	end	
end
----------------------------------------------------------------------------------------------------------END
end
To test and implement on the BOS side, just add lua_CreateLightMe and lua_DestroyLightMe, and then feed it arguments like this:

Code: Select all

call-script lua_CreateLightMe(flare, 255, 255, 128, 160);
sleep 200;
call-script lua_DestroyLightMe();
Will create a point-light source with RGBA values (255,255,128,160) then destroy that point-light source after 200ms. Have fun, it's finally working in all respects :-)
dizekat
Posts: 438
Joined: 07 Dec 2007, 12:10

Re: Simple Real-Time lighting (example code)

Post by dizekat »

By the way, note that shader itself is doing attenuation... just provide the parameters (constantAttenuation, linearAttenuation, quadraticAttenuation) to make use of that. See http://www.opengl.org/sdk/docs/man/xhtml/glLight.xml for info. Just use
gl.Light(1,GL.CONSTANT_ATTENUATION,a);
gl.Light(1,GL.LINEAR_ATTENUATION,b);
gl.Light(1,GL.QUADRATIC_ATTENUATION,c);
you can try a=1 b=0.05 c=0
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Re: Simple Real-Time lighting (example code)

Post by Argh »

Right. Sorry, I haven't added that, or a conversion factor from COB integers to floats (for those variables), could be handy for even-more-dynamic light sources.
Post Reply

Return to “Lua Scripts”