Add api and example for mesh drawing.
This commit is contained in:
parent
ace572fead
commit
15ed58856b
7 changed files with 510 additions and 18 deletions
|
@ -0,0 +1,36 @@
|
|||
#version 330
|
||||
|
||||
// Input vertex attributes
|
||||
in vec3 vertexPosition;
|
||||
in vec2 vertexTexCoord;
|
||||
in vec3 vertexNormal;
|
||||
in vec4 vertexColor;
|
||||
|
||||
in mat4 instanceTransform;
|
||||
|
||||
// Input uniform values
|
||||
uniform mat4 mvp;
|
||||
uniform mat4 matNormal;
|
||||
|
||||
// Output vertex attributes (to fragment shader)
|
||||
out vec3 fragPosition;
|
||||
out vec2 fragTexCoord;
|
||||
out vec4 fragColor;
|
||||
out vec3 fragNormal;
|
||||
|
||||
// NOTE: Add here your custom variables
|
||||
|
||||
void main()
|
||||
{
|
||||
// Compute MVP for current instance
|
||||
mat4 mvpi = mvp*instanceTransform;
|
||||
|
||||
// Send vertex attributes to fragment shader
|
||||
fragPosition = vec3(mvpi*vec4(vertexPosition, 1.0));
|
||||
fragTexCoord = vertexTexCoord;
|
||||
fragColor = vertexColor;
|
||||
fragNormal = normalize(vec3(matNormal*vec4(vertexNormal, 1.0)));
|
||||
|
||||
// Calculate final vertex position
|
||||
gl_Position = mvpi*vec4(vertexPosition, 1.0);
|
||||
}
|
82
examples/shaders/mesh_instancing/glsl330/lighting.fs
Normal file
82
examples/shaders/mesh_instancing/glsl330/lighting.fs
Normal file
|
@ -0,0 +1,82 @@
|
|||
#version 330
|
||||
|
||||
// Input vertex attributes (from vertex shader)
|
||||
in vec3 fragPosition;
|
||||
in vec2 fragTexCoord;
|
||||
in vec4 fragColor;
|
||||
in vec3 fragNormal;
|
||||
|
||||
// Input uniform values
|
||||
uniform sampler2D texture0;
|
||||
uniform vec4 colDiffuse;
|
||||
|
||||
// Output fragment color
|
||||
out vec4 finalColor;
|
||||
|
||||
// NOTE: Add here your custom variables
|
||||
|
||||
#define MAX_LIGHTS 4
|
||||
#define LIGHT_DIRECTIONAL 0
|
||||
#define LIGHT_POINT 1
|
||||
|
||||
struct MaterialProperty {
|
||||
vec3 color;
|
||||
int useSampler;
|
||||
sampler2D sampler;
|
||||
};
|
||||
|
||||
struct Light {
|
||||
int enabled;
|
||||
int type;
|
||||
vec3 position;
|
||||
vec3 target;
|
||||
vec4 color;
|
||||
};
|
||||
|
||||
// Input lighting values
|
||||
uniform Light lights[MAX_LIGHTS];
|
||||
uniform vec4 ambient;
|
||||
uniform vec3 viewPos;
|
||||
|
||||
void main()
|
||||
{
|
||||
// Texel color fetching from texture sampler
|
||||
vec4 texelColor = texture(texture0, fragTexCoord);
|
||||
vec3 lightDot = vec3(0.0);
|
||||
vec3 normal = normalize(fragNormal);
|
||||
vec3 viewD = normalize(viewPos - fragPosition);
|
||||
vec3 specular = vec3(0.0);
|
||||
|
||||
// NOTE: Implement here your fragment shader code
|
||||
|
||||
for (int i = 0; i < MAX_LIGHTS; i++)
|
||||
{
|
||||
if (lights[i].enabled == 1)
|
||||
{
|
||||
vec3 light = vec3(0.0);
|
||||
|
||||
if (lights[i].type == LIGHT_DIRECTIONAL)
|
||||
{
|
||||
light = -normalize(lights[i].target - lights[i].position);
|
||||
}
|
||||
|
||||
if (lights[i].type == LIGHT_POINT)
|
||||
{
|
||||
light = normalize(lights[i].position - fragPosition);
|
||||
}
|
||||
|
||||
float NdotL = max(dot(normal, light), 0.0);
|
||||
lightDot += lights[i].color.rgb*NdotL;
|
||||
|
||||
float specCo = 0.0;
|
||||
if (NdotL > 0.0) specCo = pow(max(0.0, dot(viewD, reflect(-(light), normal))), 16.0); // 16 refers to shine
|
||||
specular += specCo;
|
||||
}
|
||||
}
|
||||
|
||||
finalColor = (texelColor*((colDiffuse + vec4(specular, 1.0))*vec4(lightDot, 1.0)));
|
||||
finalColor += texelColor*(ambient/10.0)*colDiffuse;
|
||||
|
||||
// Gamma correction
|
||||
finalColor = pow(finalColor, vec4(1.0/2.2));
|
||||
}
|
92
examples/shaders/mesh_instancing/light.go
Normal file
92
examples/shaders/mesh_instancing/light.go
Normal file
|
@ -0,0 +1,92 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"unsafe"
|
||||
|
||||
rl "github.com/gen2brain/raylib-go/raylib"
|
||||
)
|
||||
|
||||
type LightType int32
|
||||
|
||||
const (
|
||||
LightTypeDirectional LightType = iota
|
||||
LightTypePoint
|
||||
)
|
||||
|
||||
type Light struct {
|
||||
shader rl.Shader
|
||||
lightType LightType
|
||||
position rl.Vector3
|
||||
target rl.Vector3
|
||||
color rl.Color
|
||||
enabled int32
|
||||
|
||||
// shader locations
|
||||
enabledLoc int32
|
||||
typeLoc int32
|
||||
posLoc int32
|
||||
targetLoc int32
|
||||
colorLoc int32
|
||||
}
|
||||
|
||||
const maxLightsCount = 4
|
||||
|
||||
var lightCount = 0
|
||||
|
||||
func NewLight(
|
||||
lightType LightType,
|
||||
position, target rl.Vector3,
|
||||
color rl.Color,
|
||||
shader rl.Shader) Light {
|
||||
|
||||
light := Light{
|
||||
shader: shader,
|
||||
}
|
||||
|
||||
if lightCount < maxLightsCount {
|
||||
light.enabled = 1
|
||||
light.lightType = lightType
|
||||
light.position = position
|
||||
light.target = target
|
||||
light.color = color
|
||||
|
||||
light.enabledLoc = rl.GetShaderLocation(shader, fmt.Sprintf("lights[%d].enabled", lightCount))
|
||||
light.typeLoc = rl.GetShaderLocation(shader, fmt.Sprintf("lights[%d].type", lightCount))
|
||||
light.posLoc = rl.GetShaderLocation(shader, fmt.Sprintf("lights[%d].position", lightCount))
|
||||
light.targetLoc = rl.GetShaderLocation(shader, fmt.Sprintf("lights[%d].target", lightCount))
|
||||
light.colorLoc = rl.GetShaderLocation(shader, fmt.Sprintf("lights[%d].color", lightCount))
|
||||
light.UpdateValues()
|
||||
|
||||
lightCount++
|
||||
}
|
||||
|
||||
return light
|
||||
}
|
||||
|
||||
// Send light properties to shader
|
||||
func (lt *Light) UpdateValues() {
|
||||
// not pretty -_-
|
||||
// need nicer api
|
||||
sh := &reflect.SliceHeader{
|
||||
Len: 4,
|
||||
Cap: 4,
|
||||
}
|
||||
|
||||
// Send to shader light enabled state and type
|
||||
sh.Data = uintptr(unsafe.Pointer(<.enabled))
|
||||
rl.SetShaderValue(lt.shader, lt.enabledLoc, *(*[]float32)(unsafe.Pointer(sh)), rl.ShaderUniformInt)
|
||||
|
||||
// Send to shader light position values
|
||||
sh.Data = uintptr(unsafe.Pointer(<.lightType))
|
||||
rl.SetShaderValue(lt.shader, lt.posLoc, []float32{lt.position.X, lt.position.Y, lt.position.Z}, rl.ShaderUniformVec3)
|
||||
|
||||
// Send to shader light target target values
|
||||
rl.SetShaderValue(lt.shader, lt.targetLoc, []float32{lt.target.X, lt.target.Y, lt.target.Z}, rl.ShaderUniformVec3)
|
||||
|
||||
// Send to shader light color values
|
||||
rl.SetShaderValue(lt.shader, lt.colorLoc,
|
||||
[]float32{float32(lt.color.R) / 255, float32(lt.color.G) / 255, float32(lt.color.B) / 255, float32(lt.color.A) / 255},
|
||||
rl.ShaderUniformVec4)
|
||||
}
|
253
examples/shaders/mesh_instancing/main.go
Normal file
253
examples/shaders/mesh_instancing/main.go
Normal file
|
@ -0,0 +1,253 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
|
||||
rl "github.com/gen2brain/raylib-go/raylib"
|
||||
)
|
||||
|
||||
const MAX_INSTANCES = 100000
|
||||
|
||||
func main() {
|
||||
var (
|
||||
screenWidth = int32(800) // Framebuffer width
|
||||
screenHeight = int32(450) // Framebuffer height
|
||||
fps = 60 // Frames per second
|
||||
speed = 30 // Speed of jump animation
|
||||
groups = 2 // Count of separate groups jumping around
|
||||
amp = float32(10) // Maximum amplitude of jump
|
||||
variance = float32(0.8) // Global variance in jump height
|
||||
loop = float32(0.0) // Individual cube's computed loop timer
|
||||
textPositionY int32 = 300
|
||||
framesCounter = 0
|
||||
)
|
||||
|
||||
rl.SetConfigFlags(rl.FlagMsaa4xHint) // Enable Multi Sampling Anti Aliasing 4x (if available)
|
||||
rl.InitWindow(screenWidth, screenHeight, "raylib [shaders] example - mesh instancing")
|
||||
|
||||
// Define the camera to look into our 3d world
|
||||
camera := rl.Camera{
|
||||
Position: rl.NewVector3(-125.0, 125.0, -125.0),
|
||||
Target: rl.NewVector3(0.0, 0.0, 0.0),
|
||||
Up: rl.NewVector3(0.0, 1.0, 0.0),
|
||||
Fovy: 45.0,
|
||||
Projection: rl.CameraPerspective,
|
||||
}
|
||||
|
||||
cube := rl.GenMeshCube(1.0, 1.0, 1.0)
|
||||
|
||||
rotations := make([]rl.Matrix, MAX_INSTANCES) // Rotation state of instances
|
||||
rotationsInc := make([]rl.Matrix, MAX_INSTANCES) // Per-frame rotation animation of instances
|
||||
translations := make([]rl.Matrix, MAX_INSTANCES) // Locations of instances
|
||||
|
||||
// Scatter random cubes around
|
||||
for i := 0; i < MAX_INSTANCES; i++ {
|
||||
x := float32(rl.GetRandomValue(-50, 50))
|
||||
y := float32(rl.GetRandomValue(-50, 50))
|
||||
z := float32(rl.GetRandomValue(-50, 50))
|
||||
translations[i] = rl.MatrixTranslate(x, y, z)
|
||||
|
||||
x = float32(rl.GetRandomValue(0, 360))
|
||||
y = float32(rl.GetRandomValue(0, 360))
|
||||
z = float32(rl.GetRandomValue(0, 360))
|
||||
axis := rl.Vector3Normalize(rl.NewVector3(x, y, z))
|
||||
angle := float32(rl.GetRandomValue(0, 10)) * rl.Deg2rad
|
||||
|
||||
rotationsInc[i] = rl.MatrixRotate(axis, angle)
|
||||
rotations[i] = rl.MatrixIdentity()
|
||||
}
|
||||
|
||||
transforms := make([]rl.Matrix, MAX_INSTANCES)
|
||||
|
||||
shader := rl.LoadShader("glsl330/base_lighting_instanced.vs", "glsl330/lighting.fs")
|
||||
shader.UpdateLocation(rl.LocMatrixMvp, rl.GetShaderLocation(shader, "mvp"))
|
||||
shader.UpdateLocation(rl.LocVectorView, rl.GetShaderLocation(shader, "viewPos"))
|
||||
shader.UpdateLocation(rl.LocMatrixModel, rl.GetShaderLocationAttrib(shader, "instanceTransform"))
|
||||
|
||||
// ambient light level
|
||||
ambientLoc := rl.GetShaderLocation(shader, "ambient")
|
||||
rl.SetShaderValue(shader, ambientLoc, []float32{0.2, 0.2, 0.2, 1.0}, rl.ShaderUniformVec4)
|
||||
NewLight(LightTypeDirectional, rl.NewVector3(50.0, 50.0, 0.0), rl.Vector3Zero(), rl.White, shader)
|
||||
|
||||
material := rl.LoadMaterialDefault()
|
||||
material.Shader = shader
|
||||
mmap := material.GetMap(rl.MapDiffuse)
|
||||
mmap.Color = rl.Red
|
||||
|
||||
rl.SetCameraMode(camera, rl.CameraOrbital)
|
||||
|
||||
rl.SetTargetFPS(int32(fps))
|
||||
for !rl.WindowShouldClose() {
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
textPositionY = 300
|
||||
framesCounter++
|
||||
|
||||
if rl.IsKeyDown(rl.KeyUp) {
|
||||
amp += 0.5
|
||||
}
|
||||
if rl.IsKeyDown(rl.KeyDown) {
|
||||
if amp <= 1 {
|
||||
amp = 1
|
||||
} else {
|
||||
amp -= 1
|
||||
}
|
||||
}
|
||||
if rl.IsKeyDown(rl.KeyLeft) {
|
||||
if variance < 0 {
|
||||
variance = 0
|
||||
} else {
|
||||
variance -= 0.01
|
||||
}
|
||||
}
|
||||
if rl.IsKeyDown(rl.KeyRight) {
|
||||
if variance > 1 {
|
||||
variance = 1
|
||||
} else {
|
||||
variance += 0.01
|
||||
}
|
||||
}
|
||||
if rl.IsKeyDown(rl.KeyOne) {
|
||||
groups = 1
|
||||
}
|
||||
if rl.IsKeyDown(rl.KeyTwo) {
|
||||
groups = 2
|
||||
}
|
||||
if rl.IsKeyDown(rl.KeyThree) {
|
||||
groups = 3
|
||||
}
|
||||
if rl.IsKeyDown(rl.KeyFour) {
|
||||
groups = 4
|
||||
}
|
||||
if rl.IsKeyDown(rl.KeyFive) {
|
||||
groups = 5
|
||||
}
|
||||
if rl.IsKeyDown(rl.KeySix) {
|
||||
groups = 6
|
||||
}
|
||||
if rl.IsKeyDown(rl.KeySeven) {
|
||||
groups = 7
|
||||
}
|
||||
if rl.IsKeyDown(rl.KeyEight) {
|
||||
groups = 8
|
||||
}
|
||||
if rl.IsKeyDown(rl.KeyNine) {
|
||||
groups = 9
|
||||
}
|
||||
if rl.IsKeyDown(rl.KeyW) {
|
||||
groups = 7
|
||||
amp = 25
|
||||
speed = 18
|
||||
variance = float32(0.70)
|
||||
}
|
||||
if rl.IsKeyDown(rl.KeyEqual) {
|
||||
if float32(speed) <= float32(fps)*0.25 {
|
||||
speed = int(float32(fps) * 0.25)
|
||||
} else {
|
||||
speed = int(float32(speed) * 0.95)
|
||||
}
|
||||
}
|
||||
if rl.IsKeyDown(rl.KeyKpAdd) {
|
||||
if float32(speed) <= float32(fps)*0.25 {
|
||||
speed = int(float32(fps) * 0.25)
|
||||
} else {
|
||||
speed = int(float32(speed) * 0.95)
|
||||
}
|
||||
}
|
||||
if rl.IsKeyDown(rl.KeyMinus) {
|
||||
speed = int(math.Max(float64(speed)*1.02, float64(speed)+1))
|
||||
}
|
||||
if rl.IsKeyDown(rl.KeyKpSubtract) {
|
||||
speed = int(math.Max(float64(speed)*1.02, float64(speed)+1))
|
||||
}
|
||||
|
||||
// Update the light shader with the camera view position
|
||||
rl.SetShaderValue(shader, shader.GetLocation(rl.LocVectorView),
|
||||
[]float32{camera.Position.X, camera.Position.Y, camera.Position.Z}, rl.ShaderUniformVec3)
|
||||
|
||||
// Apply per-instance transformations
|
||||
for i := 0; i < MAX_INSTANCES; i++ {
|
||||
rotations[i] = rl.MatrixMultiply(rotations[i], rotationsInc[i])
|
||||
transforms[i] = rl.MatrixMultiply(rotations[i], translations[i])
|
||||
|
||||
// Get the animation cycle's framesCounter for this instance
|
||||
loop = float32((framesCounter+int(float32(i%groups)/float32(groups)*float32(speed)))%speed) / float32(speed)
|
||||
|
||||
// Calculate the y according to loop cycle
|
||||
y := float32(math.Sin(float64(loop)*rl.Pi*2)) * amp *
|
||||
((1 - variance) + (float32(variance) * float32(i%(groups*10)) / float32(groups*10)))
|
||||
|
||||
// Clamp to floor
|
||||
if y < 0 {
|
||||
y = 0
|
||||
}
|
||||
|
||||
transforms[i] = rl.MatrixMultiply(transforms[i], rl.MatrixTranslate(0.0, y, 0.0))
|
||||
}
|
||||
|
||||
rl.UpdateCamera(&camera) // Update camera
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
rl.BeginDrawing()
|
||||
{
|
||||
rl.ClearBackground(rl.RayWhite)
|
||||
|
||||
rl.BeginMode3D(camera)
|
||||
//rl.DrawMesh(cube, material, rl.MatrixIdentity())
|
||||
rl.DrawMeshInstanced(cube, material, transforms, MAX_INSTANCES)
|
||||
rl.EndMode3D()
|
||||
|
||||
rl.DrawText("A CUBE OF DANCING CUBES!", 490, 10, 20, rl.Maroon)
|
||||
rl.DrawText("PRESS KEYS:", 10, textPositionY, 20, rl.Black)
|
||||
|
||||
textPositionY += 25
|
||||
rl.DrawText("1 - 9", 10, textPositionY, 10, rl.Black)
|
||||
rl.DrawText(": Number of groups", 50, textPositionY, 10, rl.Black)
|
||||
rl.DrawText(fmt.Sprintf(": %d", groups), 160, textPositionY, 10, rl.Black)
|
||||
|
||||
textPositionY += 15
|
||||
rl.DrawText("UP", 10, textPositionY, 10, rl.Black)
|
||||
rl.DrawText(": increase amplitude", 50, textPositionY, 10, rl.Black)
|
||||
rl.DrawText(fmt.Sprintf(": %.2f", amp), 160, textPositionY, 10, rl.Black)
|
||||
|
||||
textPositionY += 15
|
||||
rl.DrawText("DOWN", 10, textPositionY, 10, rl.Black)
|
||||
rl.DrawText(": decrease amplitude", 50, textPositionY, 10, rl.Black)
|
||||
|
||||
textPositionY += 15
|
||||
rl.DrawText("LEFT", 10, textPositionY, 10, rl.Black)
|
||||
rl.DrawText(": decrease variance", 50, textPositionY, 10, rl.Black)
|
||||
rl.DrawText(fmt.Sprintf(": %.2f", variance), 160, textPositionY, 10, rl.Black)
|
||||
|
||||
textPositionY += 15
|
||||
rl.DrawText("RIGHT", 10, textPositionY, 10, rl.Black)
|
||||
rl.DrawText(": increase variance", 50, textPositionY, 10, rl.Black)
|
||||
|
||||
textPositionY += 15
|
||||
rl.DrawText("+/=", 10, textPositionY, 10, rl.Black)
|
||||
rl.DrawText(": increase speed", 50, textPositionY, 10, rl.Black)
|
||||
rl.DrawText(fmt.Sprintf(": %d = %f loops/sec", speed, float32(fps)/float32(speed)), 160, textPositionY, 10, rl.Black)
|
||||
|
||||
textPositionY += 15
|
||||
rl.DrawText("-", 10, textPositionY, 10, rl.Black)
|
||||
rl.DrawText(": decrease speed", 50, textPositionY, 10, rl.Black)
|
||||
|
||||
textPositionY += 15
|
||||
rl.DrawText("W", 10, textPositionY, 10, rl.Black)
|
||||
rl.DrawText(": Wild setup!", 50, textPositionY, 10, rl.Black)
|
||||
|
||||
rl.DrawFPS(10, 10)
|
||||
}
|
||||
rl.EndDrawing()
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
rl.CloseWindow() // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue