3D Licht auf 2D Sprite durch Nutzung einer HeightMap

Previous topic - Next topic

nabz32

Ich versuche grade sowas ähnliches wie Sprite Lamp
in GLBasic hinzubekommen.

Leider bekomme ich bei den Höhenwerten hLU , hRU , hLD , hRD in
der Funktion drawLitSprite immer Null heraus, sodass ich nichtmal anfangen kann überlegungen
bezüglich der X und Z Winkel anX und anZ in Relation zur Lichtquellen Position anzustellen.

Code (glbasic) Select
CONSTANT LightsMax = 10
CONSTANT SpriteMax = 100

TYPE vRGB
r% ; g% ; b%
ENDTYPE

TYPE light
color AS vRGB
range% // range of light ( Radius! )
kind% // kind of light ( other light reduction kinds till the end of the light range
exist%
x%
y%
ENDTYPE

TYPE sprite
srcTex$
srcH$
srcS$
iD%
x% ; y%
ENDTYPE

GLOBAL LightMap[] AS vRGB
GLOBAL Ambient AS vRGB
GLOBAL Lights[] AS light


main()


FUNCTION newSprite AS sprite: any AS sprite , iDG , sT$ , sH$ , sS$ , x , y
any.srcTex$ = sT$ ; any.srcH$ = sH$ ; any.srcS$ = sS$ ; any.iD = iDG ; any.x = x ; any.y = y
ENDFUNCTION



FUNCTION main:
LOCAL width% , height% , white AS vRGB , blue AS vRGB , red AS vRGB , ball AS sprite
LOCAL mX% , mY% , b1% , b2%
width = 320 ; height = 240
Ambient.r = 40 ; Ambient.g = 40 ; Ambient.b = 40
white.r = 255 ; white.g = 255 ; white.b = 255
blue.r = 120 ; blue.g = 120 ; blue.b = 255
red.r = 60 ; red.g = 255 ; red.b = 60
newSprite( ball , 100 , "bBall.bmp" , "bBallH.bmp" , "bBallS.bmp" , 160 , 120 )
SETCURRENTDIR("Media/Sprites") // go to media files
DIM LightMap[width][height] ; DIM Lights[LightsMax]
Lights[0].exist = TRUE ; Lights[0].x = 160 ; Lights[0].y = 120 ; Lights[0].range = 250 ; Lights[0].color = red
// Lights[1].exist = TRUE ; Lights[1].x = 160 ; Lights[1].y = 120 ; Lights[1].range = 50 ; Lights[1].color = blue
// Lights[2].exist = TRUE ; Lights[2].x = 60 ; Lights[2].y = 60 ; Lights[2].range = 50 ; Lights[2].color = white
WHILE NOT KEY( 30 )
MOUSESTATE mX , mY , b1 , b2
Lights[0].x = mX ; Lights[0].y = mY
// updateLightMap( width , height , Ambient )
X_MAKE2D
// drawLightMap( width , height )
drawLitSprite( ball )
SHOWSCREEN
WEND
ENDFUNCTION

FUNCTION drawLitSprite: spr AS sprite
LOCAL w% , h% , w2% , h2% ,  tMap%[] , hMap%[] , x% , y%
LOCAL hLD# , hRD# , hLU# , hRU# , hU# , hD# , hL# , hR# , anX# , anZ#
LOCAL lAllow% , rAllow% , dAllow% , uAllow% , dist# , clr AS vRGB , ok%
ok = LOADSPRITEMEM( spr.srcTex$ , w2 , h2 , hMap[] )
IF NOT ok THEN RETURN FALSE
ok = LOADSPRITEMEM( spr.srcTex$ , w , h , tMap[] )
IF NOT ok THEN RETURN FALSE
IF w2 <> w OR h2 <> h THEN RETURN FALSE // hMap has to be the same size as the texture size for this to work...
clr.r = Ambient.r ; clr.g = Ambient.g ; clr.b = Ambient.b
FOR i = 0 TO BOUNDS( hMap[] , 0 ) - 1
x = MOD( i , w ) ; y = i / w ;
IF bAND(ASR( hMap[ i ],24), 0xff) <> 0x00 // not pink "alpha" color...
hLD = ( bAND( hMap[ i ], 0x00ff00) / 255.0 ) * 100.0
hRD = ( bAND( hMap[ cB( ( x + 1 ) , 0 , ( w - 1 ) ) + ( y * w ) ] , 0xff ) / 255.0 ) * 100.0 // in debug I always get zero for those heights, also when I try to look at the value of hMap[ i ] I allways get the same value...
hLU = ( bAND( hMap[ x + ( cB( ( y + 1 ) , 0 , ( h - 1 ) ) * w ) ] , 0xff ) / 255.0 ) * 100.0
hRU = ( bAND( hMap[ cB( ( x + 1 ) , 0 , ( w - 1 ) ) + ( cB( ( y + 1 ) , 0 , ( h - 1 ) ) * w ) ] , 0xff ) / 255.0 ) * 100.0
hU = hLU + ( hRU - hLU ) / 2.0 ; hD = hLD + ( hRD - hLD ) / 2.0 ; hL = hLD + ( hLU - hLD ) / 2.0 ; hR = hRD + ( hRU - hRD ) / 2.0 // mean values
anZ = ATAN( ( hD - hU ) , 10.0 ) ; anX = ATAN( ( hL - hR ) , 10.0 ) // getting angles of steepness in right and up direction
lAllow = FALSE ; rAllow = FALSE ; dAllow = FALSE ; uAllow = FALSE
IF anX <= 0 THEN lAllow = TRUE ; IF anX >= 0 THEN rAllow = TRUE // light affecting this angle at all ?
IF anZ <= 0 THEN dAllow = TRUE ; IF anZ >= 0 THEN uAllow = TRUE // light affecting this angle at all ?
FOR i2 = 0 TO LightsMax - 1
IF Lights[i2].exist
IF ( Lights[i2].x > spr.x + x AND rAllow ) OR ( Lights[i2].x < spr.x + x AND lAllow ) OR ( Lights[i2].y > spr.y + y AND uAllow ) OR ( Lights[i2].y < spr.y + y AND dAllow ) // light affecting this angle at all ?
dist = SQR( POW( ( ( spr.x + x ) - Lights[i2].x ) , 2 ) + POW( ( ( spr.y + y ) - Lights[i2].y ) , 2 ) )
dist = Lights[i2].range - dist
IF dist > 0
dist = dist / ( Lights[i2].range / 2.0 )
dist = cBR( dist , 0 , 0.5 )
clr.r = clr.r + ( Lights[i2].color.r - clr.r ) *dist ; clr.g = clr.g + ( Lights[i2].color.g - clr.g ) * dist ; clr.b = clr.b + ( Lights[i2].color.b - clr.b ) * dist
ENDIF
ENDIF
ENDIF
NEXT
ENDIF
IF bAND(ASR(tMap[ i ],24), 0xff) <> 0x00
clr.r = clr.r - ( bAND( tMap[ i ], 0xff ) - clr.r ) / 2.0
clr.g = clr.g - ( bAND( ASR( tMap[ i ] , 8 ) , 0xff ) - clr.g ) / 2.0
clr.b = clr.b - ( bAND( ASR( tMap[ i ] , 16 ) , 0xff ) - clr.b ) / 2.0
SETPIXEL spr.x + x , spr.y + y , RGB( clr.r , clr.g , clr.b )
ENDIF
clr.r = Ambient.r ; clr.g = Ambient.g ; clr.b = Ambient.b
NEXT
DIM hMap[0] ; DIM tMap[0]
ENDFUNCTION

FUNCTION cB: value , minimum , maximum // in bounds checker
IF minimum > maximum THEN SWAP minimum , maximum
IF value < minimum THEN RETURN minimum
IF value > maximum THEN RETURN maximum
RETURN value
ENDFUNCTION

FUNCTION cBR#: value# , minimum# , maximum# // in bounds checker for floats
IF minimum > maximum THEN SWAP minimum , maximum
IF value < minimum THEN RETURN minimum
IF value > maximum THEN RETURN maximum
RETURN value#
ENDFUNCTION


Edit:
Habe grade gemerkt, dass ich die Quelldatei für die heightmap falsch angegeben hatte... :blink:
Kein Wunder dass da nix rauskam...
Mal schauen was daraus wird.

nabz32

Habe es verbessert und schonmal grob den Effekt hinbekommen, den ich haben will.
Ich werde morgen versuchen den Effekt zu verfeinern,
werde anstatt die ungenaue Höhendifferenzbestimmung ( hDif# ) eine genaue höhenDifferenzbestimmung basierend auf Gleitkommawert koordinaten machen um den genauen Verlauf entlang der Richtung des Lichtstrahls zu bekommen.
Code (glbasic) Select

// --------------------------------- //
// Project: 2DLight
// Start: Friday, January 02, 2015
// IDE Version: 12.312

CONSTANT LightsMax = 10
CONSTANT SpriteMax = 100
GLOBAL LightAngle#


TYPE vRGB
r% ; g% ; b%
ENDTYPE

TYPE light
color AS vRGB
range% // range of light ( Radius! )
kind% // kind of light ( other light reduction kinds till the end of the light range
exist%
x%
y%
ENDTYPE

TYPE sprite
srcTex$
srcH$
srcS$
iD%
x% ; y%
ENDTYPE

TYPE vec3D
x#
y#
z#
dX#
dY#
dZ#
ENDTYPE



GLOBAL LightMap[] AS vRGB
GLOBAL Ambient AS vRGB
GLOBAL Lights[] AS light


main()

FUNCTION dotP: vector1 AS vec3D , vector2 AS vec3D
RETURN vector1.dX * vector2.dX + vector1.dY * vector2.dY + vector1.dZ * vector2.dZ
ENDFUNCTION

FUNCTION magnitude: v AS vec3D
RETURN SQR( v.dX * v.dX + v.dY * v.dY + v.dZ * v.dZ )
ENDFUNCTION

FUNCTION newSprite AS sprite: s AS sprite , iDG , sT$ , sH$ , sS$ , x , y
s.srcTex$ = sT$ ; s.srcH$ = sH$ ; s.srcS$ = sS$ ; s.iD = iDG ; s.x = x ; s.y = y
ENDFUNCTION

FUNCTION newVector3D AS vec3D: v AS vec3D , x% , y% , z% , dX% , dY% , dZ%
v.x = x ; v.y = y ; v.z = z ; v.dX = dX ; v.dY = dY ; v.dZ = dZ
ENDFUNCTION

FUNCTION getAngleBetweenVec3D: v1 AS vec3D , v2 AS vec3D
RETURN dotP( v1 , v2 ) / ( magnitude( v1 ) * magnitude( v2 ) )
ENDFUNCTION

FUNCTION main:
LOCAL width% , height% , white AS vRGB , blue AS vRGB , red AS vRGB , ball AS sprite
LOCAL mX% , mY% , b1% , b2%
width = 320 ; height = 240
Ambient.r = 0 ; Ambient.g = 0 ; Ambient.b = 0
white.r = 255 ; white.g = 255 ; white.b = 255
blue.r = 120 ; blue.g = 120 ; blue.b = 255
red.r = 60 ; red.g = 255 ; red.b = 60
newSprite( ball , 100 , "bBall.bmp" , "bBallH.bmp" , "bBallS.bmp" , 160 , 120 )
SETCURRENTDIR("Media/Sprites") // go to media files
DIM LightMap[width][height] ; DIM Lights[LightsMax]
Lights[0].exist = TRUE ; Lights[0].x = 160 ; Lights[0].y = 120 ; Lights[0].range = 250 ; Lights[0].color = white
Lights[1].exist = TRUE ; Lights[1].x = 160 ; Lights[1].y = 120 ; Lights[1].range = 50 ; Lights[1].color = blue
Lights[2].exist = TRUE ; Lights[2].x = 60 ; Lights[2].y = 60 ; Lights[2].range = 50 ; Lights[2].color = white
WHILE NOT KEY( 30 )
MOUSESTATE mX , mY , b1 , b2
Lights[0].x = mX ; Lights[0].y = mY
updateLightMap( width , height , Ambient )
X_MAKE2D
drawLightMap( width , height )
drawLightSprite( ball )
PRINT LightAngle , 200 , 200
SHOWSCREEN
WEND
ENDFUNCTION

FUNCTION drawLightSprite: spr AS sprite
LOCAL w% , h% , w1% , h1% , w2% , h2% ,  tMap%[] , hMap%[] , x% , y% , value% , turn% , anIX# , anIZ# , hDif#
LOCAL hLD% , hRD% , hLU% , hRU% , ok% , anX# , anZ# , lDX# , lDY# , noEffect% , noXEffect% , noYEffect%
LOCAL hL# , hR# , hU# , hD#
LOCAL dist# , clr AS vRGB ,  v1 AS vec3D , v2 AS vec3D , vL AS vec3D
ok = LOADSPRITEMEM( spr.srcTex$ , w1 , h1 , tMap[] )
IF NOT ok THEN RETURN FALSE
ok = LOADSPRITEMEM( spr.srcH$ , w2 , h2 , hMap[] )
IF NOT ok THEN RETURN FALSE
IF w2 <> w1 OR h2 <> h1 THEN RETURN FALSE // hMap has to be the same size as the texture size for this to work...
w = w1 ; h = h1 ; clr.r = Ambient.r ; clr.g = Ambient.g ; clr.b = Ambient.b
LightAngle = ATAN( ( ( h / 2 ) + spr.y - Lights[0].y ) , ( ( w / 2.0 ) + spr.x - Lights[0].x ) )
FOR i = 0 TO BOUNDS( hMap[] , 0 ) - 1
x = MOD( i , w ) ; y = i / w ; value = hMap[ i ]
IF bAND(ASR(value,24), 0xff) <> 0x00 // not pink "alpha" color...
hLD = value
hRD = hMap[ cB( ( x + 1 ) , 0 , ( w - 1 ) ) + ( y * w ) ]
hLU = hMap[ x + ( cB( ( y + 1 ) , 0 , ( h - 1 ) ) * w ) ]
hRU = hMap[ cB( ( x + 1 ) , 0 , ( w - 1 ) ) + ( cB( ( y + 1 ) , 0 , ( h - 1 ) ) * w ) ]
IF hRD = 0xFFFF0080 THEN hRD = value ; IF hLU = 0xFFFF0080 THEN hLU = value  ; IF hRU = 0xFFFF0080 THEN hRU = value // not pink "alpha" color...
hLD = bAND( hLD , 0xff ) ; hRD = bAND( hRD , 0xff ) ; hLU = bAND( hLU , 0xff ) ; hRU = bAND( hRU , 0xff )
hL = hLD + ( hLU - hLD ) / 2.0 ; hR = hRD + ( hRU - hRD ) / 2.0
hU = hLU + ( hRU - hLU ) / 2.0 ; hD = hLD + ( hRD - hLD ) / 2.0
FOR i2 = 0 TO LightsMax - 1
IF Lights[i2].exist
lDX = Lights[i2].x - ( spr.x + ( w / 2.0 ) ) ; lDY = Lights[i2].y - ( spr.y + ( h / 2.0 )  )
IF lDX = 0 AND lDY > 0 ; hDif = hD - hU ; ENDIF
IF lDX = 0 AND lDY < 0 ; hDif = hU - hD ; ENDIF
IF lDX > 0 AND lDY = 0 ; hDif = hL - hR ; ENDIF
IF lDX < 0 AND lDY = 0 ; hDif = hR - hL ; ENDIF
IF lDX > 0 AND lDY > 0 ; hDif = hLD - hRU ; ENDIF
IF lDX < 0 AND lDY > 0 ; hDif = hRD - hLU ; ENDIF
IF lDX > 0 AND lDY < 0 ; hDif = hLU - hRD ; ENDIF
IF lDX < 0 AND lDY < 0 ; hDif = hRU - hLD ; ENDIF
newVector3D( v1 , spr.x + x , hLD , spr.y + y , lDX , hDif , lDY  )
newVector3D( vL , Lights[i2].x , 300 , Lights[i2].y , Lights[i2].x - ( spr.x + x ) , -300 , Lights[i2].y - ( spr.y + y ) )
anIX = getAngleBetweenVec3D( v1 , vL )
noEffect = FALSE ; noXEffect = FALSE ; noYEffect = FALSE
dist = SQR( POW( ( ( spr.x + x ) - Lights[i2].x ) , 2 ) + POW( ( ( spr.y + y ) - Lights[i2].y ) , 2 ) )
dist = Lights[i2].range - dist
IF anIX < 0 THEN anIX = 0
anIX = 1.0 - anIX
IF dist > 0
dist = dist / Lights[i2].range
dist = ( dist ) * anIX
dist = cBR( dist , 0 , 1.0 )
clr.r = clr.r + ( Lights[i2].color.r - clr.r ) *dist ; clr.g = clr.g + ( Lights[i2].color.g - clr.g ) * dist ; clr.b = clr.b + ( Lights[i2].color.b - clr.b ) * dist
ENDIF
ENDIF
NEXT
ENDIF
value = tMap[ i ]
IF bAND(ASR(value,24), 0xff) <> 0x00
clr.r = bAND( value, 0xff ) + ( clr.r - bAND( value, 0xff ) ) / 2.0
clr.g = bAND( ASR( value , 8 ) , 0xff ) + ( clr.g - bAND( ASR( value , 8 ) , 0xff ) ) / 2.0
clr.b = bAND( ASR( value , 16 ) , 0xff ) + ( clr.b - bAND( ASR( value , 16 ) , 0xff ) ) / 2.0
SETPIXEL spr.x + x , spr.y + y , RGB( clr.r , clr.g , clr.b )
ENDIF
clr.r = Ambient.r ; clr.g = Ambient.g ; clr.b = Ambient.b
NEXT
ENDFUNCTION

FUNCTION cB: value , minimum , maximum
IF minimum > maximum THEN SWAP minimum , maximum
IF value < minimum THEN RETURN minimum
IF value > maximum THEN RETURN maximum
RETURN value
ENDFUNCTION

FUNCTION cBR: value , minimum , maximum
IF minimum > maximum THEN SWAP minimum , maximum
IF value < minimum THEN RETURN minimum
IF value > maximum THEN RETURN maximum
RETURN value
ENDFUNCTION

FUNCTION updateLightMap: width% , height% , ambient AS vRGB
LOCAL lXL% , lXR% , lYU% , lYD% , dist# , scaleL#
FOR i = 0 TO width - 1
FOR i2 = 0 TO height - 1
LightMap[i][i2].r = ambient.r
LightMap[i][i2].g = ambient.g
LightMap[i][i2].b = ambient.b // Fill Lightmap with ambient light...
NEXT
NEXT
FOR i = 0 TO LightsMax - 1
IF Lights[i].exist
// IF Lights[i].x < 0 THEN Lights[i].x = 0 ; IF Lights[i].x > width - 1 THEN Lights[i].x = width - 1
// IF Lights[i].y < 0 THEN Lights[i].y = 0 ; IF Lights[i].y > height - 1 THEN Lights[i].y = height - 1
lXL = Lights[i].x - Lights[i].range ; lXR = Lights[i].x + Lights[i].range
IF lXL < 0 THEN lXL = 0 ; IF lXR > width - 1 THEN lXR = width - 1
lYD = Lights[i].y - Lights[i].range ; lYU = Lights[i].y + Lights[i].range
IF lYD < 0 THEN lYD = 0 ; IF lYU > height - 1 THEN lYU = height - 1
FOR i2 = lXL TO lXR
FOR i3 = lYD TO lYU
dist = SQR( POW( ( i2 - Lights[i].x ) , 2 ) + POW( ( i3 - Lights[i].y ) , 2 ) )
IF dist < Lights[i].range
scaleL = ( Lights[i].range - dist ) / Lights[i].range
LightMap[i2][i3].r = LightMap[i2][i3].r + ( Lights[i].color.r - LightMap[i2][i3].r ) * scaleL
LightMap[i2][i3].g = LightMap[i2][i3].g + ( Lights[i].color.g - LightMap[i2][i3].g ) * scaleL
LightMap[i2][i3].b = LightMap[i2][i3].b + ( Lights[i].color.b - LightMap[i2][i3].b ) * scaleL
ENDIF
NEXT
NEXT
ENDIF
NEXT
ENDFUNCTION


FUNCTION drawLightMap: width% , height% // for testing purpose, draw the lightmap only
FOR i = 0 TO width - 1
FOR i2 = 0 TO height - 1
SETPIXEL i , i2 , RGB( LightMap[i][i2].r , LightMap[i][i2].g , LightMap[i][i2].b )
NEXT
NEXT
ENDFUNCTION



Die benötigten Sprites sind angehängt, einfach in ein neues Projektverzeichniss in media\Sprites einfügen...
DrawLightMap und initLightMap habe ich nur zum Testen mit im Code.

nabz32

mache mich heute an die Berechnung der passenden Normalvektoren der Dreiecke, dabei werde ich für jedes zweierpaar dreiecke ( 1 Pixel ) einen Interpolierten Mittelvektor aus den beiden Normalvektoren bestimmen.

Marmor


Schranz0r

Quote from: nabz32 on 2015-Jan-03
mache mich heute an die Berechnung der passenden Normalvektoren der Dreiecke, dabei werde ich für jedes zweierpaar dreiecke ( 1 Pixel ) einen Interpolierten Mittelvektor aus den beiden Normalvektoren bestimmen.


Gesundheit!  ;)
I <3 DGArray's :D

PC:
AMD Ryzen 7 3800X 16@4.5GHz, 16GB Corsair Vengeance LPX DDR4-3200 RAM, ASUS Dual GeForce RTX™ 3060 OC Edition 12GB GDDR6, Windows 11 Pro 64Bit, MSi Tomahawk B350 Mainboard

nabz32

läuft nun schon besser das ganze,
nur habe ich das Problem, dass Das Licht wenn es im Objekt ist einen Schatten wirft.
Glaube das die Normalen falsch berechnet sind, werde nochmal reinschauen.
Hier das ganze bis jetzt:
Code (glbasic) Select

// --------------------------------- //
// Project: 2DLight
// Start: Friday, January 02, 2015
// IDE Version: 12.312

CONSTANT LightsMax = 10
CONSTANT SpriteMax = 100
GLOBAL LightAngle#

TYPE vRGB
r% ; g% ; b%
ENDTYPE

TYPE light
color AS vRGB
range% // range of light ( Radius! )
kind% // kind of light ( other light reduction kinds till the end of the light range
exist%
x%
y%
ENDTYPE

TYPE sprite
srcTex$
srcH$
srcS$
iD%
x% ; y%
ENDTYPE

TYPE vec3D
dX#
dY#
dZ#
ENDTYPE

GLOBAL LightMap[] AS vRGB
GLOBAL Ambient AS vRGB
GLOBAL Lights[] AS light



main()

FUNCTION dotP: vector1 AS vec3D , vector2 AS vec3D
RETURN vector1.dX * vector2.dX + vector1.dY * vector2.dY + vector1.dZ * vector2.dZ
ENDFUNCTION

FUNCTION crossP AS vec3D: v1 AS vec3D , v2 AS vec3D , n AS vec3D
n.dX = ( v1.dY * v2.dZ ) - ( v1.dZ * v2.dY )
n.dY = ( v1.dZ * v2.dX ) - ( v1.dX * v2.dZ )
n.dZ = ( v1.dX * v2.dY ) - ( v1.dY * v2.dX )
ENDFUNCTION

FUNCTION magnitude: v AS vec3D
RETURN SQR( v.dX * v.dX + v.dY * v.dY + v.dZ * v.dZ )
ENDFUNCTION

FUNCTION newSprite AS sprite: s AS sprite , iDG , sT$ , sH$ , sS$ , x , y
s.srcTex$ = sT$ ; s.srcH$ = sH$ ; s.srcS$ = sS$ ; s.iD = iDG ; s.x = x ; s.y = y
ENDFUNCTION

FUNCTION newVector3D AS vec3D: v AS vec3D , dX% , dY% , dZ%
v.dX = dX ; v.dY = dY ; v.dZ = dZ
ENDFUNCTION

FUNCTION getAngleBetweenVec3D: v1 AS vec3D , v2 AS vec3D
RETURN dotP( v1 , v2 ) / ( magnitude( v1 ) * magnitude( v2 ) )
ENDFUNCTION

FUNCTION main:
LOCAL width% , height% , white AS vRGB , blue AS vRGB , red AS vRGB , ball AS sprite , ball2 AS sprite
LOCAL mX% , mY% , b1% , b2%
width = 320 ; height = 240
Ambient.r = 0 ; Ambient.g = 0 ; Ambient.b = 0
white.r = 255 ; white.g = 255 ; white.b = 255
blue.r = 120 ; blue.g = 120 ; blue.b = 255
red.r = 60 ; red.g = 255 ; red.b = 60

newSprite( ball , 100 , "bBall.bmp" , "bBallH.bmp" , "bBallS.bmp" , 160 , 120 )
newSprite( ball2 , 101 , "bBall.bmp" , "bBallH2.bmp" , "bBallS.bmp" , 320 , 240 )
SETCURRENTDIR("Media/Sprites") // go to media files
DIM LightMap[width][height] ; DIM Lights[LightsMax]
Lights[0].exist = TRUE ; Lights[0].x = 160 ; Lights[0].y = 120 ; Lights[0].range = 250 ; Lights[0].color = white
Lights[1].exist = TRUE ; Lights[1].x = 300 ; Lights[1].y = 200 ; Lights[1].range = 450 ; Lights[1].color = blue
Lights[2].exist = TRUE ; Lights[2].x = 60 ; Lights[2].y = 60 ; Lights[2].range = 50 ; Lights[2].color = red
WHILE NOT KEY( 30 )
MOUSESTATE mX , mY , b1 , b2
Lights[0].x = mX ; Lights[0].y = mY
// updateLightMap( width , height , Ambient )
X_MAKE2D
// drawLightMap( width , height )
drawLightSprite( ball ) ; drawLightSprite( ball2 )
PRINT LightAngle , 200 , 200
SHOWSCREEN
WEND
ENDFUNCTION

FUNCTION drawLightSprite: spr AS sprite
LOCAL w% , h% , w1% , h1% , w2% , h2% ,  tMap%[] , hMap%[] , x% , y% , value% , turn% , anIX# , anIZ# , hDif#
LOCAL hLD% , hRD% , hLU% , hRU% , ok% , anX# , anZ# , lDX# , lDY# , lDXU# , lDYU#
LOCAL hL# , hR# , hU# , hD# , dAn#
LOCAL dist# , clr AS vRGB ,  v1 AS vec3D , v2 AS vec3D , vL AS vec3D
ok = LOADSPRITEMEM( spr.srcTex$ , w1 , h1 , tMap[] )
IF NOT ok THEN RETURN FALSE
ok = LOADSPRITEMEM( spr.srcH$ , w2 , h2 , hMap[] )
IF NOT ok THEN RETURN FALSE
IF w2 <> w1 OR h2 <> h1 THEN RETURN FALSE // hMap has to be the same size as the texture size for this to work...
w = w1 ; h = h1 ; clr.r = Ambient.r ; clr.g = Ambient.g ; clr.b = Ambient.b
LightAngle = ATAN( ( ( h / 2 ) + spr.y - Lights[0].y ) , ( ( w / 2.0 ) + spr.x - Lights[0].x ) )
FOR i = 0 TO BOUNDS( hMap[] , 0 ) - 1
x = MOD( i , w ) ; y = i / w ; value = hMap[ i ]
IF bAND(ASR(value,24), 0xff) <> 0x00 // not pink "alpha" color...
hLD = value
hRD = hMap[ cB( ( x + 1 ) , 0 , ( w - 1 ) ) + ( y * w ) ]
hLU = hMap[ x + ( cB( ( y + 1 ) , 0 , ( h - 1 ) ) * w ) ]
hRU = hMap[ cB( ( x + 1 ) , 0 , ( w - 1 ) ) + ( cB( ( y + 1 ) , 0 , ( h - 1 ) ) * w ) ]
IF hRD = 0xFFFF0080 THEN hRD = value ; IF hLU = 0xFFFF0080 THEN hLU = value  ; IF hRU = 0xFFFF0080 THEN hRU = value // not pink "alpha" color...
hLD = bAND( hLD , 0xff ) ; hRD = bAND( hRD , 0xff ) ; hLU = bAND( hLU , 0xff ) ; hRU = bAND( hRU , 0xff )
hL = hLD + ( hLU - hLD ) / 2.0 ; hR = hRD + ( hRU - hRD ) / 2.0
hU = hLU + ( hRU - hLU ) / 2.0 ; hD = hLD + ( hRD - hLD ) / 2.0
FOR i2 = 0 TO LightsMax - 1
IF Lights[i2].exist
lDX = Lights[i2].x - ( spr.x + ( w / 2.0 ) ) ; lDY = Lights[i2].y - ( spr.y + ( h / 2.0 )  )
lDXU = lDX / ABS( MAX( lDX , lDY ) ) ; lDYU = lDY / ABS( MAX( lDX , lDY ) )
getnormalVector(hLU , hRU , hLD , hRD , v1 )
newVector3D( vL , lDX , -1 , lDY )
anIX = getAngleBetweenVec3D( v1 , vL )
dist = SQR( POW( ( ( spr.x + x ) - Lights[i2].x ) , 2 ) + POW( ( ( spr.y + y ) - Lights[i2].y ) , 2 ) )
dist = Lights[i2].range - dist
anIX = 1.0 + anIX
IF anIX > 1.0 THEN anIX = 1.0
IF dist > 0
dist = dist / Lights[i2].range
dist = ( dist ) * anIX
// dist = cBR( dist , 0 , 1.0 )
clr.r = clr.r + ( Lights[i2].color.r - clr.r ) *dist ; clr.g = clr.g + ( Lights[i2].color.g - clr.g ) * dist ; clr.b = clr.b + ( Lights[i2].color.b - clr.b ) * dist
ENDIF
ENDIF
NEXT
ENDIF
value = tMap[ i ]
IF bAND(ASR(value,24), 0xff) <> 0x00
clr.r = bAND( value, 0xff ) + ( clr.r - bAND( value, 0xff ) ) / 2.0
clr.g = bAND( ASR( value , 8 ) , 0xff ) + ( clr.g - bAND( ASR( value , 8 ) , 0xff ) ) / 2.0
clr.b = bAND( ASR( value , 16 ) , 0xff ) + ( clr.b - bAND( ASR( value , 16 ) , 0xff ) ) / 2.0
SETPIXEL spr.x + x , spr.y + y , RGB( clr.r , clr.g , clr.b )
ENDIF
clr.r = Ambient.r ; clr.g = Ambient.g ; clr.b = Ambient.b
NEXT
ENDFUNCTION

FUNCTION getnormalVector AS vec3D: hLU% , hRU% , hLD% , hRD% , n AS vec3D
LOCAL P1 AS vec3D , P2 AS vec3D , P3 AS vec3D , n1 AS vec3D , n2 AS vec3D , c1 AS vec3D , c2 AS vec3D , c3 AS vec3D
IF ABS( ( hLU - hRD ) ) > ABS( ( hRU - hLD ) )// turn triangles...
P1.dX = 0 ; P1.dY = hLD ; P1.dZ = 0 ; P2.dX = 0 ; P2.dY = hLU ; P2.dZ = 1 ; P3.dX = 1 ; P3.dY = hRD ; P3.dZ = 0
crossP( P1 , P2 , c1 ) ; crossP( P2 , P3 , c2 ) ; crossP( P3 , P1 , c3 )
n1.dX = c1.dX + c2.dX + c3.dX
n1.dY = c1.dY + c2.dY + c3.dY
n1.dZ = c1.dZ + c2.dZ + c3.dZ
P1.dX = 1 ; P1.dY = hRU ; P1.dZ = 1 ; P2.dX = 1 ; P2.dY = hRD ; P2.dZ = 0 ; P3.dX = 0 ; P3.dY = hLU ; P3.dZ = 1
crossP( P1 , P2 , c1 ) ; crossP( P2 , P3 , c2 ) ; crossP( P3 , P1 , c3 )
n2.dX = c1.dX + c2.dX + c3.dX
n2.dY = c1.dY + c2.dY + c3.dY
n2.dZ = c1.dZ + c2.dZ + c3.dZ
n.dX = n1.dX + ( n2.dX - n1.dX ) / 2.0
n.dY = n1.dY + ( n2.dY - n1.dY ) / 2.0
n.dZ = n1.dZ + ( n2.dZ - n1.dZ ) / 2.0
ELSE
P1.dX = 0 ; P1.dY = hLU ; P1.dZ = 1 ; P2.dX = 1 ; P2.dY = hRU ; P2.dZ = 1 ; P3.dX = 0 ; P3.dY = hLD ; P3.dZ = 0
crossP( P1 , P2 , c1 ) ; crossP( P2 , P3 , c2 ) ; crossP( P3 , P1 , c3 )
n1.dX = c1.dX + c2.dX + c3.dX
n1.dY = c1.dY + c2.dY + c3.dY
n1.dZ = c1.dZ + c2.dZ + c3.dZ
P1.dX = 1 ; P1.dY = hRD ; P1.dZ = 0 ; P2.dX = 0 ; P2.dY = hLD ; P2.dZ = 0 ; P3.dX = 1 ; P3.dY = hRU ; P3.dZ = 1
crossP( P1 , P2 , c1 ) ; crossP( P2 , P3 , c2 ) ; crossP( P3 , P1 , c3 )
n2.dX = c1.dX + c2.dX + c3.dX
n2.dY = c1.dY + c2.dY + c3.dY
n2.dZ = c1.dZ + c2.dZ + c3.dZ
n.dX = n1.dX + ( n2.dX - n1.dX ) / 2.0
n.dY = n1.dY + ( n2.dY - n1.dY ) / 2.0
n.dZ = n1.dZ + ( n2.dZ - n1.dZ ) / 2.0
ENDIF
ENDFUNCTION

FUNCTION cB: value , minimum , maximum
IF minimum > maximum THEN SWAP minimum , maximum
IF value < minimum THEN RETURN minimum
IF value > maximum THEN RETURN maximum
RETURN value
ENDFUNCTION

FUNCTION cBR: value , minimum , maximum
IF minimum > maximum THEN SWAP minimum , maximum
IF value < minimum THEN RETURN minimum
IF value > maximum THEN RETURN maximum
RETURN value
ENDFUNCTION

FUNCTION updateLightMap: width% , height% , ambient AS vRGB
LOCAL lXL% , lXR% , lYU% , lYD% , dist# , scaleL#
FOR i = 0 TO width - 1
FOR i2 = 0 TO height - 1
LightMap[i][i2].r = ambient.r
LightMap[i][i2].g = ambient.g
LightMap[i][i2].b = ambient.b // Fill Lightmap with ambient light...
NEXT
NEXT
FOR i = 0 TO LightsMax - 1
IF Lights[i].exist
lXL = Lights[i].x - Lights[i].range ; lXR = Lights[i].x + Lights[i].range
IF lXL < 0 THEN lXL = 0 ; IF lXR > width - 1 THEN lXR = width - 1
lYD = Lights[i].y - Lights[i].range ; lYU = Lights[i].y + Lights[i].range
IF lYD < 0 THEN lYD = 0 ; IF lYU > height - 1 THEN lYU = height - 1
FOR i2 = lXL TO lXR
FOR i3 = lYD TO lYU
dist = SQR( POW( ( i2 - Lights[i].x ) , 2 ) + POW( ( i3 - Lights[i].y ) , 2 ) )
IF dist < Lights[i].range
scaleL = ( Lights[i].range - dist ) / Lights[i].range
LightMap[i2][i3].r = LightMap[i2][i3].r + ( Lights[i].color.r - LightMap[i2][i3].r ) * scaleL
LightMap[i2][i3].g = LightMap[i2][i3].g + ( Lights[i].color.g - LightMap[i2][i3].g ) * scaleL
LightMap[i2][i3].b = LightMap[i2][i3].b + ( Lights[i].color.b - LightMap[i2][i3].b ) * scaleL
ENDIF
NEXT
NEXT
ENDIF
NEXT
ENDFUNCTION

FUNCTION drawLightMap: width% , height% // for testing purpose, draw the lightmap only
FOR i = 0 TO width - 1
FOR i2 = 0 TO height - 1
SETPIXEL i , i2 , RGB( LightMap[i][i2].r , LightMap[i][i2].g , LightMap[i][i2].b )
NEXT
NEXT
ENDFUNCTION



Sieht schonmal fast richtig aus  :)
Man kann natürlich auch die Normalen in einer vec3D Array vorgenerieren um Leistung zu sparen.
Auch werde ich noch zwei Skalierungsfaktoren für die HeightMap hinzufügen um nicht soviele Normalvektoren speichern zu müssen.

Schranz0r

I <3 DGArray's :D

PC:
AMD Ryzen 7 3800X 16@4.5GHz, 16GB Corsair Vengeance LPX DDR4-3200 RAM, ASUS Dual GeForce RTX™ 3060 OC Edition 12GB GDDR6, Windows 11 Pro 64Bit, MSi Tomahawk B350 Mainboard

nabz32

Habe nurnoch die Höhe des Lichtvektors der Lichtgröße anpassen müssen, sieht jetzt deutlich besser aus.
Habe auch mal ne Heightmap für einen Basketball gebastelt =D


Und hier der Code: ( Habe ihn noch etwas aufgeräumt )

Code (glbasic) Select
// --------------------------------- //
// Project: 2DLight
// Start: Friday, January 02, 2015
// IDE Version: 12.312

CONSTANT LightsMax = 10
CONSTANT SpriteMax = 100

TYPE vRGB
r% ; g% ; b%
ENDTYPE

TYPE light
color AS vRGB
range% // range of light ( Radius! )
kind% // kind of light ( other light reduction kinds till the end of the light range
exist%
x%
y%
ENDTYPE

TYPE sprite
srcTex$
srcH$
srcS$
iD%
x% ; y%
ENDTYPE

TYPE vec3D
dX#
dY#
dZ#
ENDTYPE

GLOBAL LightMap[] AS vRGB
GLOBAL Ambient AS vRGB
GLOBAL Lights[] AS light



main()

FUNCTION dotP: vector1 AS vec3D , vector2 AS vec3D
RETURN vector1.dX * vector2.dX + vector1.dY * vector2.dY + vector1.dZ * vector2.dZ
ENDFUNCTION

FUNCTION crossP AS vec3D: v1 AS vec3D , v2 AS vec3D , n AS vec3D
n.dX = ( v1.dY * v2.dZ ) - ( v1.dZ * v2.dY )
n.dY = ( v1.dZ * v2.dX ) - ( v1.dX * v2.dZ )
n.dZ = ( v1.dX * v2.dY ) - ( v1.dY * v2.dX )
ENDFUNCTION

FUNCTION magnitude: v AS vec3D
RETURN SQR( v.dX * v.dX + v.dY * v.dY + v.dZ * v.dZ )
ENDFUNCTION

FUNCTION newSprite AS sprite: s AS sprite , iDG , sT$ , sH$ , sS$ , x , y
s.srcTex$ = sT$ ; s.srcH$ = sH$ ; s.srcS$ = sS$ ; s.iD = iDG ; s.x = x ; s.y = y
ENDFUNCTION

FUNCTION newVector3D AS vec3D: v AS vec3D , dX% , dY% , dZ%
v.dX = dX ; v.dY = dY ; v.dZ = dZ
ENDFUNCTION

FUNCTION getAngleBetweenVec3D: v1 AS vec3D , v2 AS vec3D
RETURN dotP( v1 , v2 ) / ( magnitude( v1 ) * magnitude( v2 ) )
ENDFUNCTION

FUNCTION new2DLight AS light: nr% , x% , y% , range% , kind% , r% , g% , b%
Lights[nr].exist = TRUE ; Lights[nr].x = x ; Lights[nr].y = y ; Lights[nr].range = range
Lights[nr].color.r = r ; Lights[nr].color.g = g ; Lights[nr].color.b = b ; Lights[nr].kind = kind
ENDFUNCTION

FUNCTION main:
LOCAL width% , height% , ball AS sprite , ball2 AS sprite
LOCAL mX% , mY% , b1% , b2%
width = 320 ; height = 240 // size of LightMap ( Just for testing )
Ambient.r = 0 ; Ambient.g = 0 ; Ambient.b = 0
DIM LightMap[width][height] ; DIM Lights[LightsMax]
SETCURRENTDIR("Media/Sprites") // go to media files
newSprite( ball , 100 , "bBall.bmp" , "bBallH.bmp" , "bBallS.bmp" , 160 , 120 )
newSprite( ball2 , 101 , "bBall.bmp" , "bBallH2.bmp" , "bBallS.bmp" , 320 , 240 )
new2DLight( 0 , 0 , 0 , 800 , 0 , 255 , 220 , 220 ) 
WHILE NOT KEY( 30 )
MOUSESTATE mX , mY , b1 , b2
Lights[0].x = mX ; Lights[0].y = mY
IF b2 = TRUE ; Lights[0].kind = 1 ; ELSE ; Lights[0].kind = 0 ; ENDIF
updateLightMap( width , height , Ambient )
X_MAKE2D
drawLightMap( width , height )
drawLightSprite( ball ) ; drawLightSprite( ball2 )
SHOWSCREEN
WEND
ENDFUNCTION

FUNCTION drawLightSprite: spr AS sprite
LOCAL w1% , h1% , w2% , h2% , tMap%[] , hMap%[] , x% , y% , value% , anIN#
LOCAL hLD% , hRD% , hLU% , hRU% , ok%
LOCAL dist# , clr AS vRGB ,  v1 AS vec3D , v2 AS vec3D , vL AS vec3D
ok = LOADSPRITEMEM( spr.srcTex$ , w1 , h1 , tMap[] )
IF NOT ok THEN RETURN FALSE
ok = LOADSPRITEMEM( spr.srcH$ , w2 , h2 , hMap[] )
IF NOT ok THEN RETURN FALSE
IF w2 <> w1 OR h2 <> h1 THEN RETURN FALSE // hMap has to be the same size as the texture size for this to work...
clr.r = Ambient.r ; clr.g = Ambient.g ; clr.b = Ambient.b
FOR i = 0 TO BOUNDS( hMap[] , 0 ) - 1
x = MOD( i , w1 ) ; y = i / w1 ; value = hMap[ i ]
IF bAND(ASR(value,24), 0xff) <> 0x00 // not pink "alpha" color...
hLD = value
hRD = hMap[ cB( ( x + 1 ) , 0 , ( w1 - 1 ) ) + ( y * w1 ) ]
hLU = hMap[ x + ( cB( ( y + 1 ) , 0 , ( h1 - 1 ) ) * w1 ) ]
hRU = hMap[ cB( ( x + 1 ) , 0 , ( w1 - 1 ) ) + ( cB( ( y + 1 ) , 0 , ( h1 - 1 ) ) * w1 ) ]
// check for pink "alpha" on the points around...
IF bAND(ASR(hRD,24), 0xff) = 0x00 ; hRD = 0 ; ELSE ; hRD = bAND( hRD , 0xff ) ; ENDIF
IF bAND(ASR(hLU,24), 0xff) = 0x00 ; hLU = 0 ; ELSE ; hLU = bAND( hLU , 0xff ) ; ENDIF
IF bAND(ASR(hRU,24), 0xff) = 0x00 ; hRU = 0 ; ELSE ; hRU = bAND( hRU , 0xff ) ; ENDIF
hLD = bAND( hLD , 0xff )
FOR i2 = 0 TO LightsMax - 1 // Go through all Lights and get an interpolated Light value based on Normals
IF Lights[i2].exist
dist = SQR( POW( ( ( spr.x + x ) - Lights[i2].x ) , 2 ) + POW( ( ( spr.y + y ) - Lights[i2].y ) , 2 ) )
dist = Lights[i2].range - dist
IF dist > 0
getnormalVector(hLU , hRU , hLD , hRD , v1 ) // Calculate the normal vector
newVector3D( vL , ( Lights[i2].x - ( spr.x + x ) ) , -Lights[i2].range / 2.0 , ( Lights[i2].y - ( spr.y + y ) ) ) // generate the Light Vector
anIN = getAngleBetweenVec3D( v1 , vL ) ; anIN = 1.0 + anIN ; IF anIN > 1.0 THEN anIN = 1.0
dist = dist / Lights[i2].range ; dist = ( dist ) * anIN
clr.r = clr.r + ( Lights[i2].color.r - clr.r ) *dist ; clr.g = clr.g + ( Lights[i2].color.g - clr.g ) * dist ; clr.b = clr.b + ( Lights[i2].color.b - clr.b ) * dist
ENDIF
ENDIF
NEXT
ENDIF
value = tMap[ i ] // Draw the Pixel by drawing the mean value of the texture pixel and Light Pixel
IF bAND(ASR(value,24), 0xff) <> 0x00
clr.r = bAND( value, 0xff ) + ( clr.r - bAND( value, 0xff ) ) / 2.0
clr.g = bAND( ASR( value , 8 ) , 0xff ) + ( clr.g - bAND( ASR( value , 8 ) , 0xff ) ) / 2.0
clr.b = bAND( ASR( value , 16 ) , 0xff ) + ( clr.b - bAND( ASR( value , 16 ) , 0xff ) ) / 2.0
SETPIXEL spr.x + x , spr.y + y , RGB( clr.r , clr.g , clr.b )
ENDIF
clr.r = Ambient.r ; clr.g = Ambient.g ; clr.b = Ambient.b
NEXT
ENDFUNCTION

FUNCTION getnormalVector AS vec3D: hLU% , hRU% , hLD% , hRD% , n AS vec3D
LOCAL P1 AS vec3D , P2 AS vec3D , P3 AS vec3D , n1 AS vec3D , n2 AS vec3D , c1 AS vec3D , c2 AS vec3D , c3 AS vec3D
IF ABS( ( hLU - hRD ) ) > ABS( ( hRU - hLD ) )// turn triangles...
P1.dX = 0 ; P1.dY = hLD ; P1.dZ = 0 ; P2.dX = 0 ; P2.dY = hLU ; P2.dZ = 1 ; P3.dX = 1 ; P3.dY = hRD ; P3.dZ = 0
crossP( P1 , P2 , c1 ) ; crossP( P2 , P3 , c2 ) ; crossP( P3 , P1 , c3 )
n1.dX = c1.dX + c2.dX + c3.dX
n1.dY = c1.dY + c2.dY + c3.dY
n1.dZ = c1.dZ + c2.dZ + c3.dZ
P1.dX = 1 ; P1.dY = hRU ; P1.dZ = 1 ; P2.dX = 1 ; P2.dY = hRD ; P2.dZ = 0 ; P3.dX = 0 ; P3.dY = hLU ; P3.dZ = 1
crossP( P1 , P2 , c1 ) ; crossP( P2 , P3 , c2 ) ; crossP( P3 , P1 , c3 )
n2.dX = c1.dX + c2.dX + c3.dX
n2.dY = c1.dY + c2.dY + c3.dY
n2.dZ = c1.dZ + c2.dZ + c3.dZ
n.dX = n1.dX + ( n2.dX - n1.dX ) / 2.0
n.dY = n1.dY + ( n2.dY - n1.dY ) / 2.0
n.dZ = n1.dZ + ( n2.dZ - n1.dZ ) / 2.0
ELSE
P1.dX = 0 ; P1.dY = hLU ; P1.dZ = 1 ; P2.dX = 1 ; P2.dY = hRU ; P2.dZ = 1 ; P3.dX = 0 ; P3.dY = hLD ; P3.dZ = 0
crossP( P1 , P2 , c1 ) ; crossP( P2 , P3 , c2 ) ; crossP( P3 , P1 , c3 )
n1.dX = c1.dX + c2.dX + c3.dX
n1.dY = c1.dY + c2.dY + c3.dY
n1.dZ = c1.dZ + c2.dZ + c3.dZ
P1.dX = 1 ; P1.dY = hRD ; P1.dZ = 0 ; P2.dX = 0 ; P2.dY = hLD ; P2.dZ = 0 ; P3.dX = 1 ; P3.dY = hRU ; P3.dZ = 1
crossP( P1 , P2 , c1 ) ; crossP( P2 , P3 , c2 ) ; crossP( P3 , P1 , c3 )
n2.dX = c1.dX + c2.dX + c3.dX
n2.dY = c1.dY + c2.dY + c3.dY
n2.dZ = c1.dZ + c2.dZ + c3.dZ
n.dX = n1.dX + ( n2.dX - n1.dX ) / 2.0
n.dY = n1.dY + ( n2.dY - n1.dY ) / 2.0
n.dZ = n1.dZ + ( n2.dZ - n1.dZ ) / 2.0
ENDIF
ENDFUNCTION

FUNCTION cB: value , minimum , maximum
IF minimum > maximum THEN SWAP minimum , maximum
IF value < minimum THEN RETURN minimum
IF value > maximum THEN RETURN maximum
RETURN value
ENDFUNCTION

FUNCTION cBR AS float: value# , minimum# , maximum#
IF minimum > maximum THEN SWAP minimum , maximum
IF value < minimum THEN RETURN minimum
IF value > maximum THEN RETURN maximum
RETURN value
ENDFUNCTION

FUNCTION updateLightMap: width% , height% , ambient AS vRGB
LOCAL lXL% , lXR% , lYU% , lYD% , dist# , scaleL#
FOR i = 0 TO width - 1
FOR i2 = 0 TO height - 1
LightMap[i][i2].r = ambient.r
LightMap[i][i2].g = ambient.g
LightMap[i][i2].b = ambient.b // Fill Lightmap with ambient light...
NEXT
NEXT
FOR i = 0 TO LightsMax - 1
IF Lights[i].exist
lXL = Lights[i].x - Lights[i].range ; lXR = Lights[i].x + Lights[i].range
IF lXL < 0 THEN lXL = 0 ; IF lXR > width - 1 THEN lXR = width - 1
lYD = Lights[i].y - Lights[i].range ; lYU = Lights[i].y + Lights[i].range
IF lYD < 0 THEN lYD = 0 ; IF lYU > height - 1 THEN lYU = height - 1
FOR i2 = lXL TO lXR
FOR i3 = lYD TO lYU
dist = SQR( POW( ( i2 - Lights[i].x ) , 2 ) + POW( ( i3 - Lights[i].y ) , 2 ) )
IF dist < Lights[i].range
scaleL = ( Lights[i].range - dist ) / Lights[i].range
LightMap[i2][i3].r = LightMap[i2][i3].r + ( Lights[i].color.r - LightMap[i2][i3].r ) * scaleL
LightMap[i2][i3].g = LightMap[i2][i3].g + ( Lights[i].color.g - LightMap[i2][i3].g ) * scaleL
LightMap[i2][i3].b = LightMap[i2][i3].b + ( Lights[i].color.b - LightMap[i2][i3].b ) * scaleL
ENDIF
NEXT
NEXT
ENDIF
NEXT
ENDFUNCTION

FUNCTION drawLightMap: width% , height% // for testing purpose, draw the lightmap only
FOR i = 0 TO width - 1
FOR i2 = 0 TO height - 1
SETPIXEL i , i2 , RGB( LightMap[i][i2].r , LightMap[i][i2].g , LightMap[i][i2].b )
NEXT
NEXT
ENDFUNCTION


Edit:
Media Dateien vergessen, nun im Anhang.

kanonet

Schöner Effekt, sieht gut aus! :booze:
Wie sieht da die Performance aus, könnte man das in größerem Maßstab live in einem Spiel nutzen?
Generell gibt es genau für solche Sachen Shader, könntest du dir auch mal anschauen (kann dir dabei helfen, die GLBasic Limitierungen zu beheben, wenn du willst). Allerdings wäre das dann nur Desktop-Plattform.
Lenovo Thinkpad T430u: Intel i5-3317U, 8GB DDR3, NVidia GeForce 620M, Micron RealSSD C400 @Win7 x64

nabz32

Shaderprogrammierung habe ich bis jetzt noch nie gemacht,
nur mal ein paar vorgefertigte in Darkbasic damals getestet...

Solange das Spiel eine niedrige Aufloesung hat, kein Problem von der Performance her
( wenn ich endlich mal dazu kommen wuerde die Normal maps vorzugenerieren und sie nicht in jedem Frame neu zu berechnen).
Wenn man diesen Effekt immer fuer den gesamten Bildausschnitt berechnet, waere es auch kein Problem wenn man richtig viele dieser Sprites nutzt ( 2D Z hinzufuegen, abfragen welcher sprite fuer diesen Pixel in Frage kommt ).
Dann haette man aber das Problem, dass die Sprites nicht drehbar waeren bzw. man muesste irgendwie in Software vor der Abfrage rotieren.

Eine andere moeglichkeit waere eine kleinere Heightmap und Normalmap fuer den Sprite, man muesste zwar wieder jeden Pixel abfragen, die Berechnung des Lichteinfalls wuerde aber nur fuer eine Gruppe von Pixeln berechnet.
Ist der sprite etwas pixelig hochgescaletes, wuerde dies sogar noch ohne Interpolation gut aussehen.

Wollte mir damit nur beweisen, dass ich so einen Effekt mit nem Sprite und ner HMap
hinbekomme.

Edit:
Die Anzahl der Lichtquellen bestimmt maßgeblich wie oft berechnet werden muss.