as per request spotlight example (#1146)

Co-authored-by: codifies <nospam@antispam.com>
This commit is contained in:
chriscamacho 2020-03-24 13:27:14 +00:00 committed by GitHub
parent c45fe62abc
commit efe359d613
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 332 additions and 1 deletions

View File

@ -456,7 +456,8 @@ SHADERS = \
shaders/shaders_eratosthenes \ shaders/shaders_eratosthenes \
shaders/shaders_basic_lighting \ shaders/shaders_basic_lighting \
shaders/shaders_fog \ shaders/shaders_fog \
shaders/shaders_simple_mask shaders/shaders_simple_mask \
shaders/shaders_spotlight
AUDIO = \ AUDIO = \
audio/audio_module_playing \ audio/audio_module_playing \

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -0,0 +1,52 @@
#version 100
precision mediump float;
#define MAX_SPOTS 4
#define RADIUS 256.0
#define INNER 200.0
// Inputs
// array of spotlight positions
uniform vec2 spots[MAX_SPOTS];
uniform float screenWidth; // width of the screen
void main()
{
float alpha;
// get the position of the current fragment (screen coordinates!)
vec2 pos = vec2(gl_FragCoord.x, gl_FragCoord.y);
// find out which spotlight is nearest
float d = 65000.0; // some high value
float di = 0.0;
for (int i = 0; i < MAX_SPOTS; i++)
{
di = distance(pos, spots[i]);
if (d > di) d = di;
}
// d now equals distance to nearest spot...
if (d > RADIUS) {
alpha = 1.0;
} else {
if (d < INNER) {
alpha = 0.0;
} else {
alpha = (d - INNER) / (RADIUS - INNER);
}
}
// right hand side of screen is dimly lit, could make the
// threshold value user definable.
if (pos.x > screenWidth/2.0 && alpha > 0.9) {
alpha = 0.9;
}
// could make the black out colour user definable...
gl_FragColor = vec4( 0, 0, 0, alpha);
}

View File

@ -0,0 +1,53 @@
#version 330
// Output fragment color
out vec4 finalColor;
#define MAX_SPOTS 4
#define RADIUS 256
#define INNER 200
// Inputs
// array of spotlight positions
uniform vec2 spots[MAX_SPOTS];
uniform float screenWidth; // width of the screen
void main()
{
float alpha;
// get the position of the current fragment (screen coordinates!)
vec2 pos = vec2(gl_FragCoord.x, gl_FragCoord.y);
// find out which spotlight is nearest
float d = 65000; // some high value
float di = 0;
for (int i = 0; i < MAX_SPOTS; i++)
{
di = distance(pos, spots[i]);
if (d > di) d = di;
}
// d now equals distance to nearest spot...
if (d > RADIUS) {
alpha = 1.0;
} else {
if (d < INNER) {
alpha = 0.0;
} else {
alpha = (d - INNER) / (RADIUS - INNER);
}
}
// right hand side of screen is dimly lit, could make the
// threshold value user definable.
if (pos.x>screenWidth/2.0 && alpha >0.9) {
alpha = 0.9;
}
// could make the black out colour user definable...
finalColor = vec4( 0, 0, 0, alpha);
}

View File

@ -0,0 +1,225 @@
/*
* Copyright (c) 2019 Chris Camacho (codifies - http://bedroomcoders.co.uk/)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
/* The shader makes alpha holes in the forground to give the apearance of a top
* down look at a spotlight casting a pool of light...
*
* The right hand side of the screen there is just enough light to see whats
* going on without the spot light, great for a stealth type game where you
* have to avoid the spotlights.
*
* The left hand side of the screen is in pitch dark except for where the spotlights
* are.
*
* Although this example doesn't scale like the letterbox example, you could integrate
* the two techniques, but by scaling the actual colour of the render texture rather
* than using alpha as a mask.
*/
#include <stddef.h>
#include <stdint.h>
#include "raylib.h"
#include "raymath.h"
#if defined(PLATFORM_DESKTOP)
#define GLSL_VERSION 330
#else // PLATFORM_RPI, PLATFORM_ANDROID, PLATFORM_WEB
#define GLSL_VERSION 100
#endif
// single digit only!
#define MAXSPOT 4
#define numStars 400
#define screenWidth 1280
#define screenHeight 720
// the stars in the star field have a position and velocity
typedef struct star {
Vector2 pos;
Vector2 vel;
} star;
void updateStar(star *s);
void resetStar(star *s);
int main(void)
{
// Initialization
//--------------------------------------------------------------------------------------
star stars[numStars];
for (int n=0; n < numStars; n++) {
resetStar(&stars[n]);
}
// progress all the stars on, so they don't all start in the centre
for (int m=0; m < screenWidth / 2.0; m++) {
for (int n=0; n<numStars; n++) {
updateStar(&stars[n]);
}
}
//SetConfigFlags(FLAG_FULLSCREEN_MODE);
InitWindow(screenWidth, screenHeight, "raylib - test");
Texture rayTex = LoadTexture("resources/raysan.png");
// frame counter
int frame = 0;
unsigned int spotLoc[MAXSPOT]; // shader locations
Vector2 spotPos[MAXSPOT]; // position and velocity
Vector2 spotVel[MAXSPOT];
// use default vert shader
Shader spotShader = LoadShader(0, FormatText("resources/shaders/glsl%i/spotlight.fs", GLSL_VERSION));
// get the locations of spots in the shader
char spotName[32] = "spots[x]\0";
for (int i = 0; i<MAXSPOT; i++) {
spotName[6] = '0' + i;
spotLoc[i] = GetShaderLocation(spotShader, spotName);
}
// tell the shader how wide the screen is so we can have
// a pitch black half and a dimly lit half.
{
unsigned int wLoc = GetShaderLocation(spotShader, "screenWidth");
float sw = screenWidth;
SetShaderValue(spotShader, wLoc, &sw, UNIFORM_FLOAT);
}
// randomise the locations and velocities of the spotlights
for (int i=0; i<MAXSPOT; i++) {
spotPos[i].x = GetRandomValue(128, screenWidth-128);
spotPos[i].y = GetRandomValue(128, screenHeight-128);
spotVel[i] = (Vector2){0, 0};
while (fabs(spotVel[i].x)+fabs(spotVel[i].y)<2) {
spotVel[i].x = GetRandomValue(-40,40)/10.0;
spotVel[i].y = GetRandomValue(-40,40)/10.0;
}
}
SetTargetFPS(60); // Set to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
frame ++;
// move the stars, resetting them if the go offscreen
for (int n=0; n<numStars; n++) {
updateStar(&stars[n]);
}
// update the spots, send them to the shader
for (int i=0; i<MAXSPOT; i++) {
spotPos[i].x += spotVel[i].x;
spotPos[i].y += spotVel[i].y;
if (spotPos[i].x < 128) spotVel[i].x = -spotVel[i].x;
if (spotPos[i].x > screenWidth-128) spotVel[i].x = -spotVel[i].x;
if (spotPos[i].y < 128) spotVel[i].y = -spotVel[i].y;
if (spotPos[i].y > screenHeight-128) spotVel[i].y = -spotVel[i].y;
SetShaderValue(spotShader, spotLoc[i], &spotPos[i].x, UNIFORM_VEC2);
}
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground((Color){0,32,128,255});
// stars and bobs
for (int n=0; n<numStars; n++) {
// single pixel is just too small these days!
DrawRectangle(stars[n].pos.x, stars[n].pos.y, 2, 2, WHITE);
}
for (int i=0; i<16; i++) {
DrawTexture(rayTex,
(screenWidth/2.0)+cos((frame+i*8)/51.45)*(screenWidth/2.2)-32,
(screenHeight/2.0)+sin((frame+i*8)/17.87)*(screenHeight/4.2),
WHITE);
}
// spot lights
BeginShaderMode(spotShader);
// instead of a blank rectangle you could render here
// a render texture of the full screen used to do screen
// scaling (slight adjustment to shader would be required
// to actually pay attention to the colour!)
DrawRectangle(0,0,screenWidth,screenHeight,WHITE);
EndShaderMode();
DrawFPS(10, 10);
EndDrawing();
//----------------------------------------------------------------------------------
}
// De-Initialization
//--------------------------------------------------------------------------------------
UnloadTexture(rayTex);
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}
void resetStar(star *s)
{
(*s).pos = (Vector2){screenWidth/2.0, screenHeight/2.0 };
do {
(*s).vel.x = (float)GetRandomValue(-1000,1000) / 100.0;
(*s).vel.y = (float)GetRandomValue(-1000,1000) / 100.0;
} while (!(fabs((*s).vel.x)+fabs((*s).vel.y)>1));
(*s).pos = Vector2Add( (*s).pos,
Vector2MultiplyV((*s).vel,(Vector2){8,8} ));
}
void updateStar(star *s)
{
(*s).pos = Vector2Add((*s).pos, (*s).vel);
if ((*s).pos.x < 0 || (*s).pos.x > screenWidth ||
(*s).pos.y < 0 || (*s).pos.y > screenHeight) {
resetStar(s);
}
}