Add api and example for mesh drawing.

This commit is contained in:
jackji 2021-06-22 21:37:46 +08:00
parent ace572fead
commit 15ed58856b
7 changed files with 510 additions and 18 deletions

View file

@ -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);
}

View 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));
}

View 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(&lt.enabled))
rl.SetShaderValue(lt.shader, lt.enabledLoc, *(*[]float32)(unsafe.Pointer(sh)), rl.ShaderUniformInt)
// Send to shader light position values
sh.Data = uintptr(unsafe.Pointer(&lt.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)
}

View 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
//--------------------------------------------------------------------------------------
}

View file

@ -400,6 +400,16 @@ func DrawBillboardRec(camera Camera, texture Texture2D, sourceRec Rectangle, cen
C.DrawBillboardRec(*ccamera, *ctexture, *csourceRec, *ccenter, *csize, *ctint)
}
// DrawMesh - Draw a single mesh
func DrawMesh(mesh Mesh, material Material, transform Matrix) {
C.DrawMesh(*mesh.cptr(), *material.cptr(), *transform.cptr())
}
// DrawMeshInstanced - Draw mesh with instanced rendering
func DrawMeshInstanced(mesh Mesh, material Material, transforms []Matrix, instances int) {
C.DrawMeshInstanced(*mesh.cptr(), *material.cptr(), transforms[0].cptr(), C.int(instances))
}
// GetMeshBoundingBox - Compute mesh bounding box limits
func GetMeshBoundingBox(mesh Mesh) BoundingBox {
cmesh := mesh.cptr()

View file

@ -716,8 +716,10 @@ const (
)
// Shader location point type
type LocationPointType int32
const (
LocVertexPosition = iota
LocVertexPosition LocationPointType = iota
LocVertexTexcoord01
LocVertexTexcoord02
LocVertexNormal
@ -746,8 +748,10 @@ const (
)
// Material map type
type MaterialMapType int32
const (
MapAlbedo = iota
MapAlbedo MaterialMapType = iota
MapMetalness
MapNormal
MapRoughness
@ -830,6 +834,11 @@ func newMaterialFromPointer(ptr unsafe.Pointer) Material {
return *(*Material)(ptr)
}
// GetMap - Get pointer to MaterialMap by map type
func (mt Material) GetMap(index MaterialMapType) *MaterialMap {
return (*MaterialMap)(unsafe.Pointer(uintptr(unsafe.Pointer(mt.Maps)) + uintptr(index)*uintptr(unsafe.Sizeof(MaterialMap{}))))
}
// MaterialMap type
type MaterialMap struct {
// Texture
@ -920,6 +929,16 @@ func newShaderFromPointer(ptr unsafe.Pointer) Shader {
return *(*Shader)(ptr)
}
// GetLocation - Get shader value's location
func (sh Shader) GetLocation(index LocationPointType) int32 {
return *(*int32)(unsafe.Pointer(uintptr(unsafe.Pointer(sh.Locs)) + uintptr(index*4)))
}
// UpdateLocation - Update shader value's location
func (sh Shader) UpdateLocation(index LocationPointType, loc int32) {
*(*int32)(unsafe.Pointer(uintptr(unsafe.Pointer(sh.Locs)) + uintptr(index*4))) = loc
}
// CharInfo - Font character info
type CharInfo struct {
// Character value (Unicode)

View file

@ -673,22 +673,22 @@ func MatrixScale(x, y, z float32) Matrix {
func MatrixMultiply(left, right Matrix) Matrix {
var result Matrix
result.M0 = right.M0*left.M0 + right.M1*left.M4 + right.M2*left.M8 + right.M3*left.M12
result.M1 = right.M0*left.M1 + right.M1*left.M5 + right.M2*left.M9 + right.M3*left.M13
result.M2 = right.M0*left.M2 + right.M1*left.M6 + right.M2*left.M10 + right.M3*left.M14
result.M3 = right.M0*left.M3 + right.M1*left.M7 + right.M2*left.M11 + right.M3*left.M15
result.M4 = right.M4*left.M0 + right.M5*left.M4 + right.M6*left.M8 + right.M7*left.M12
result.M5 = right.M4*left.M1 + right.M5*left.M5 + right.M6*left.M9 + right.M7*left.M13
result.M6 = right.M4*left.M2 + right.M5*left.M6 + right.M6*left.M10 + right.M7*left.M14
result.M7 = right.M4*left.M3 + right.M5*left.M7 + right.M6*left.M11 + right.M7*left.M15
result.M8 = right.M8*left.M0 + right.M9*left.M4 + right.M10*left.M8 + right.M11*left.M12
result.M9 = right.M8*left.M1 + right.M9*left.M5 + right.M10*left.M9 + right.M11*left.M13
result.M10 = right.M8*left.M2 + right.M9*left.M6 + right.M10*left.M10 + right.M11*left.M14
result.M11 = right.M8*left.M3 + right.M9*left.M7 + right.M10*left.M11 + right.M11*left.M15
result.M12 = right.M12*left.M0 + right.M13*left.M4 + right.M14*left.M8 + right.M15*left.M12
result.M13 = right.M12*left.M1 + right.M13*left.M5 + right.M14*left.M9 + right.M15*left.M13
result.M14 = right.M12*left.M2 + right.M13*left.M6 + right.M14*left.M10 + right.M15*left.M14
result.M15 = right.M12*left.M3 + right.M13*left.M7 + right.M14*left.M11 + right.M15*left.M15
result.M0 = left.M0*right.M0 + left.M1*right.M4 + left.M2*right.M8 + left.M3*right.M12
result.M1 = left.M0*right.M1 + left.M1*right.M5 + left.M2*right.M9 + left.M3*right.M13
result.M2 = left.M0*right.M2 + left.M1*right.M6 + left.M2*right.M10 + left.M3*right.M14
result.M3 = left.M0*right.M3 + left.M1*right.M7 + left.M2*right.M11 + left.M3*right.M15
result.M4 = left.M4*right.M0 + left.M5*right.M4 + left.M6*right.M8 + left.M7*right.M12
result.M5 = left.M4*right.M1 + left.M5*right.M5 + left.M6*right.M9 + left.M7*right.M13
result.M6 = left.M4*right.M2 + left.M5*right.M6 + left.M6*right.M10 + left.M7*right.M14
result.M7 = left.M4*right.M3 + left.M5*right.M7 + left.M6*right.M11 + left.M7*right.M15
result.M8 = left.M8*right.M0 + left.M9*right.M4 + left.M10*right.M8 + left.M11*right.M12
result.M9 = left.M8*right.M1 + left.M9*right.M5 + left.M10*right.M9 + left.M11*right.M13
result.M10 = left.M8*right.M2 + left.M9*right.M6 + left.M10*right.M10 + left.M11*right.M14
result.M11 = left.M8*right.M3 + left.M9*right.M7 + left.M10*right.M11 + left.M11*right.M15
result.M12 = left.M12*right.M0 + left.M13*right.M4 + left.M14*right.M8 + left.M15*right.M12
result.M13 = left.M12*right.M1 + left.M13*right.M5 + left.M14*right.M9 + left.M15*right.M13
result.M14 = left.M12*right.M2 + left.M13*right.M6 + left.M14*right.M10 + left.M15*right.M14
result.M15 = left.M12*right.M3 + left.M13*right.M7 + left.M14*right.M11 + left.M15*right.M15
return result
}