Updating Tetra3D addon for Blender 4.
The version of the GLTF exporter included with Blender 4 only supports separate GLTF + BIN + Textures, or GLB, so I'm updating Tetra3D to work with separate BIN files and removing the embedded GLTF option from the Tetra3D addon. Adding Material-level visibility. Updating a variety of demos to use separate GLTFs or GLBs. Adding Camera.RenderCube() to easily render a cube on-screen. Camera Debug frametimes have been adjusted to no longer be averaged over time, as this broken if a Camera was used to render multiple objects in a single frame.pull/31/head
100
camera.go
|
@ -15,21 +15,20 @@ import (
|
|||
|
||||
// DebugInfo is a struct that holds debugging information for a Camera's render pass. These values are reset when Camera.Clear() is called.
|
||||
type DebugInfo struct {
|
||||
AvgFrameTime time.Duration // Amount of CPU frame time spent transforming vertices and calling Image.DrawTriangles. Doesn't include time ebitengine spends flushing the command queue.
|
||||
AvgAnimationTime time.Duration // Amount of CPU frame time spent animating vertices.
|
||||
AvgLightTime time.Duration // Amount of CPU frame time spent lighting vertices.
|
||||
animationTime time.Duration
|
||||
lightTime time.Duration
|
||||
frameTime time.Duration
|
||||
frameCount int
|
||||
tickTime time.Time
|
||||
DrawnParts int // Number of draw calls, excluding those invisible or culled based on distance
|
||||
TotalParts int // Total number of draw calls
|
||||
BatchedParts int // Total batched number of draw calls
|
||||
DrawnTris int // Number of drawn triangles, excluding those hidden from backface culling
|
||||
TotalTris int // Total number of triangles
|
||||
LightCount int // Total number of lights
|
||||
ActiveLightCount int // Total active number of lights
|
||||
FrameTime time.Duration // Amount of CPU frame time spent transforming vertices and calling Image.DrawTriangles. Doesn't include time ebitengine spends flushing the command queue.
|
||||
AnimationTime time.Duration // Amount of CPU frame time spent animating vertices.
|
||||
LightTime time.Duration // Amount of CPU frame time spent lighting vertices.
|
||||
currentAnimationTime time.Duration
|
||||
currentLightTime time.Duration
|
||||
currentFrameTime time.Duration
|
||||
tickTime time.Time
|
||||
DrawnParts int // Number of draw calls, excluding those invisible or culled based on distance
|
||||
TotalParts int // Total number of draw calls
|
||||
BatchedParts int // Total batched number of draw calls
|
||||
DrawnTris int // Number of drawn triangles, excluding those hidden from backface culling
|
||||
TotalTris int // Total number of triangles
|
||||
LightCount int // Total number of lights
|
||||
ActiveLightCount int // Total active number of lights
|
||||
}
|
||||
|
||||
const (
|
||||
|
@ -762,25 +761,16 @@ func (camera *Camera) Clear() {
|
|||
camera.resultNormalTexture.Clear()
|
||||
}
|
||||
|
||||
if camera.DebugInfo.frameCount > 0 && time.Since(camera.DebugInfo.tickTime).Milliseconds() >= 100 {
|
||||
|
||||
if !camera.DebugInfo.tickTime.IsZero() {
|
||||
|
||||
camera.DebugInfo.AvgFrameTime = camera.DebugInfo.frameTime / time.Duration(camera.DebugInfo.frameCount)
|
||||
|
||||
camera.DebugInfo.AvgAnimationTime = camera.DebugInfo.animationTime / time.Duration(camera.DebugInfo.frameCount)
|
||||
|
||||
camera.DebugInfo.AvgLightTime = camera.DebugInfo.lightTime / time.Duration(camera.DebugInfo.frameCount)
|
||||
|
||||
}
|
||||
if time.Since(camera.DebugInfo.tickTime).Milliseconds() >= 1000 {
|
||||
|
||||
camera.DebugInfo.FrameTime = camera.DebugInfo.currentFrameTime
|
||||
camera.DebugInfo.AnimationTime = camera.DebugInfo.currentAnimationTime
|
||||
camera.DebugInfo.LightTime = camera.DebugInfo.currentLightTime
|
||||
camera.DebugInfo.tickTime = time.Now()
|
||||
camera.DebugInfo.frameTime = 0
|
||||
camera.DebugInfo.animationTime = 0
|
||||
camera.DebugInfo.lightTime = 0
|
||||
camera.DebugInfo.frameCount = 0
|
||||
|
||||
}
|
||||
camera.DebugInfo.currentFrameTime = 0
|
||||
camera.DebugInfo.currentAnimationTime = 0
|
||||
camera.DebugInfo.currentLightTime = 0
|
||||
camera.DebugInfo.DrawnParts = 0
|
||||
camera.DebugInfo.BatchedParts = 0
|
||||
camera.DebugInfo.TotalParts = 0
|
||||
|
@ -1017,6 +1007,10 @@ func (camera *Camera) Render(scene *Scene, lights []ILight, models ...*Model) {
|
|||
|
||||
for meshPart, modelSlice := range model.DynamicBatchModels {
|
||||
|
||||
if !meshPart.isVisible() {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, child := range modelSlice {
|
||||
|
||||
if !child.visible {
|
||||
|
@ -1063,6 +1057,11 @@ func (camera *Camera) Render(scene *Scene, lights []ILight, models ...*Model) {
|
|||
modelIsTransparent := false
|
||||
|
||||
for _, mp := range model.Mesh.MeshParts {
|
||||
|
||||
if !mp.isVisible() {
|
||||
continue
|
||||
}
|
||||
|
||||
if model.isTransparent(mp) {
|
||||
transparents = append(transparents, renderPair{model, mp})
|
||||
modelIsTransparent = true
|
||||
|
@ -1166,7 +1165,7 @@ func (camera *Camera) Render(scene *Scene, lights []ILight, models ...*Model) {
|
|||
light.beginModel(model)
|
||||
}
|
||||
|
||||
camera.DebugInfo.lightTime += time.Since(t)
|
||||
camera.DebugInfo.currentLightTime += time.Since(t)
|
||||
|
||||
}
|
||||
|
||||
|
@ -1210,7 +1209,7 @@ func (camera *Camera) Render(scene *Scene, lights []ILight, models ...*Model) {
|
|||
|
||||
}
|
||||
|
||||
camera.DebugInfo.lightTime += time.Since(t)
|
||||
camera.DebugInfo.currentLightTime += time.Since(t)
|
||||
|
||||
}
|
||||
|
||||
|
@ -1700,9 +1699,7 @@ func (camera *Camera) Render(scene *Scene, lights []ILight, models ...*Model) {
|
|||
|
||||
}
|
||||
|
||||
camera.DebugInfo.frameTime += time.Since(frametimeStart)
|
||||
|
||||
camera.DebugInfo.frameCount++
|
||||
camera.DebugInfo.currentFrameTime += time.Since(frametimeStart)
|
||||
|
||||
}
|
||||
|
||||
|
@ -1716,8 +1713,6 @@ func packFloat(input1, input2, precision float32) float32 {
|
|||
type DrawSprite3dSettings struct {
|
||||
// The image to render
|
||||
Image *ebiten.Image
|
||||
// Options for drawing the sprite; defaults to nil, which is default settings.
|
||||
Options *ebiten.DrawTrianglesShaderOptions
|
||||
// How much to offset the depth - useful if you want the object to appear at a position,
|
||||
// but in front of or behind other objects. Negative is towards the camera, positive is away.
|
||||
// The offset ranges from 0 to 1.
|
||||
|
@ -1737,12 +1732,12 @@ var spriteRender3DIndices = []uint16{
|
|||
2, 3, 0,
|
||||
}
|
||||
|
||||
// DrawSprite3D draws an image on the screen in 2D, but at the screen position of the 3D world position provided,
|
||||
// RenderSprite3D draws an image on the screen in 2D, but at the screen position of the 3D world position provided,
|
||||
// and with depth intersection.
|
||||
// This allows you to render 2D elements "at" a 3D position, and can be very useful in situations where you want
|
||||
// a sprite to render at 100% size and no perspective or skewing, but still look like it's in the 3D space (like in
|
||||
// a game with a fixed camera viewpoint).
|
||||
func (camera *Camera) DrawSprite3D(screen *ebiten.Image, renderSettings ...DrawSprite3dSettings) {
|
||||
func (camera *Camera) RenderSprite3D(screen *ebiten.Image, renderSettings ...DrawSprite3dSettings) {
|
||||
|
||||
// TODO: Replace this with a more performant alternative, where we minimize shader / texture switches.
|
||||
|
||||
|
@ -1800,6 +1795,25 @@ func (camera *Camera) DrawSprite3D(screen *ebiten.Image, renderSettings ...DrawS
|
|||
|
||||
}
|
||||
|
||||
var renderCube = NewModel("render cube", NewCubeMesh())
|
||||
|
||||
// RenderCube quickly and easily renders a cube with the position and scale desired.
|
||||
// The Camera must be present in a scene to perform this function.
|
||||
func (camera *Camera) RenderCube(position Vector, scale Vector, color Color, shadelessness bool) {
|
||||
|
||||
// TODO: Optimize this with perhaps background cubes that are dynamically batched so they could be rendered in one
|
||||
// Render call.
|
||||
|
||||
if scene := camera.Scene(); scene != nil {
|
||||
renderCube.SetLocalPositionVec(position)
|
||||
renderCube.SetLocalScaleVec(scale.Scale(0.5))
|
||||
renderCube.Color = color
|
||||
renderCube.Mesh.Materials()[0].Shadeless = shadelessness
|
||||
camera.Render(scene, nil, renderCube)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// DrawDebugRenderInfo draws render debug information (like number of drawn objects, number of drawn triangles, frame time, etc)
|
||||
// at the top-left of the provided screen *ebiten.Image, using the textScale and color provided.
|
||||
// Note that the frame-time mentioned here is purely the time that Tetra3D spends sending render commands to the command queue.
|
||||
|
@ -1807,13 +1821,13 @@ func (camera *Camera) DrawSprite3D(screen *ebiten.Image, renderSettings ...DrawS
|
|||
// visible outside of debugging and profiling, like with pprof.
|
||||
func (camera *Camera) DrawDebugRenderInfo(screen *ebiten.Image, textScale float64, color Color) {
|
||||
|
||||
m := camera.DebugInfo.AvgFrameTime.Round(time.Microsecond).Microseconds()
|
||||
m := camera.DebugInfo.FrameTime.Round(time.Microsecond).Microseconds()
|
||||
ft := fmt.Sprintf("%.2fms", float32(m)/1000)
|
||||
|
||||
m = camera.DebugInfo.AvgAnimationTime.Round(time.Microsecond).Microseconds()
|
||||
m = camera.DebugInfo.AnimationTime.Round(time.Microsecond).Microseconds()
|
||||
at := fmt.Sprintf("%.2fms", float32(m)/1000)
|
||||
|
||||
m = camera.DebugInfo.AvgLightTime.Round(time.Microsecond).Microseconds()
|
||||
m = camera.DebugInfo.LightTime.Round(time.Microsecond).Microseconds()
|
||||
lt := fmt.Sprintf("%.2fms", float32(m)/1000)
|
||||
|
||||
sectorName := "<Sector Rendering Off>"
|
||||
|
|
10
dae.go
|
@ -135,8 +135,9 @@ func DefaultDaeLoadOptions() *DaeLoadOptions {
|
|||
|
||||
// LoadDAEFile takes a filepath to a .dae model file, and returns a *Library populated with the .dae file's objects and meshes.
|
||||
// Animations will not be loaded from DAE files, as DAE exports through Blender only support one animation per object (so it's generally
|
||||
// advised to use the GLTF or GLB format instead). Cameras exported in the DAE file will be turned into simple Nodes in Tetra3D, as
|
||||
// there's not enough information to instantiate a tetra3d.Camera. If the call couldn't complete for any reason, like due to a malformed DAE file,
|
||||
// advised to use the GLTF or GLB format instead).
|
||||
// Cameras exported in the DAE file will be turned into simple Nodes in Tetra3D, as there's not enough information to instantiate a tetra3d.Camera.
|
||||
// If the call couldn't complete for any reason, like due to a malformed DAE file,
|
||||
// it will return an error.
|
||||
func LoadDAEFile(path string, options *DaeLoadOptions) (*Library, error) {
|
||||
|
||||
|
@ -150,8 +151,9 @@ func LoadDAEFile(path string, options *DaeLoadOptions) (*Library, error) {
|
|||
|
||||
// LoadDAEData takes a []byte consisting of the contents of a DAE file, and returns a *Library populated with the .dae file's objects and meshes.
|
||||
// Animations will not be loaded from DAE files, as DAE exports through Blender only support one animation per object (so it's generally
|
||||
// advised to use the GLTF or GLB format instead). Cameras exported in the DAE file will be turned into simple Nodes in Tetra3D, as
|
||||
// there's not enough information to instantiate a tetra3d.Camera. If the call couldn't complete for any reason, like due to a malformed DAE file,
|
||||
// advised to use the GLTF or GLB format instead).
|
||||
// Cameras exported in the DAE file will be turned into simple Nodes in Tetra3D, as there's not enough information to instantiate a tetra3d.Camera.
|
||||
// If the call couldn't complete for any reason, like due to a malformed DAE file,
|
||||
// it will return an error.
|
||||
func LoadDAEData(data []byte, options *DaeLoadOptions) (*Library, error) {
|
||||
|
||||
|
|
Before Width: | Height: | Size: 255 B After Width: | Height: | Size: 255 B |
|
@ -0,0 +1,416 @@
|
|||
{
|
||||
"asset":{
|
||||
"generator":"Khronos glTF Blender I/O v4.0.43",
|
||||
"version":"2.0"
|
||||
},
|
||||
"extensionsUsed":[
|
||||
"KHR_lights_punctual"
|
||||
],
|
||||
"extensionsRequired":[
|
||||
"KHR_lights_punctual"
|
||||
],
|
||||
"extensions":{
|
||||
"KHR_lights_punctual":{
|
||||
"lights":[
|
||||
{
|
||||
"color":[
|
||||
1,
|
||||
1,
|
||||
1
|
||||
],
|
||||
"intensity":7.957747154594767,
|
||||
"type":"point",
|
||||
"name":"Light"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"scene":0,
|
||||
"scenes":[
|
||||
{
|
||||
"extras":{
|
||||
"t3dExportOnSave__":1,
|
||||
"t3dExportFormat__":0,
|
||||
"t3dCameraResolution__":[
|
||||
640,
|
||||
360
|
||||
],
|
||||
"t3dExportFilepath__":"",
|
||||
"t3dPackTextures__":false,
|
||||
"t3dExportCameras__":true,
|
||||
"t3dExportLights__":true,
|
||||
"t3dRenderResolutionW__":640,
|
||||
"t3dRenderResolutionH__":360,
|
||||
"t3dSectorRendering__":false,
|
||||
"t3dSectorRenderDepth__":0,
|
||||
"t3dPlaybackFPS__":60,
|
||||
"t3dAnimationSampling__":true,
|
||||
"t3dAnimationInterpolation__":true,
|
||||
"t3dPerspectiveCorrectedTextureMapping__":false,
|
||||
"t3dMaxLightCount__":0,
|
||||
"t3dSectorDetection__":0,
|
||||
"t3dCollections__":{
|
||||
"Collection":{
|
||||
"objects":[
|
||||
"Room",
|
||||
"Light",
|
||||
"Camera",
|
||||
"Heart"
|
||||
],
|
||||
"offset":[
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
]
|
||||
}
|
||||
},
|
||||
"t3dWorlds__":{
|
||||
"World":{
|
||||
"ambient color":[
|
||||
0.05087608844041824,
|
||||
0.05087608844041824,
|
||||
0.05087608844041824,
|
||||
1.0
|
||||
],
|
||||
"ambient energy":1.0,
|
||||
"clear color":[
|
||||
0.007000000216066837,
|
||||
0.00800000037997961,
|
||||
0.009999999776482582,
|
||||
1.0
|
||||
],
|
||||
"fog mode":"OFF",
|
||||
"dithered transparency":0.0,
|
||||
"fog curve":"LINEAR",
|
||||
"fog color":[
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
1.0
|
||||
],
|
||||
"fog range start":0.0,
|
||||
"fog range end":1.0
|
||||
}
|
||||
},
|
||||
"t3dCurrentWorld__":"World",
|
||||
"t3dView3DCameraData__":[
|
||||
{
|
||||
"clip_start":0.009999999776482582,
|
||||
"clip_end":1000.0,
|
||||
"location":[
|
||||
0.0,
|
||||
14.718420028686523,
|
||||
12.718420028686523
|
||||
],
|
||||
"rotation":[
|
||||
[
|
||||
1.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
[
|
||||
0.0,
|
||||
0.7071068286895752,
|
||||
0.7071067690849304
|
||||
],
|
||||
[
|
||||
0.0,
|
||||
-0.7071067690849304,
|
||||
0.7071068286895752
|
||||
]
|
||||
],
|
||||
"fovY":39.597752709049864,
|
||||
"perspective":true
|
||||
}
|
||||
]
|
||||
},
|
||||
"name":"Scene",
|
||||
"nodes":[
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
]
|
||||
}
|
||||
],
|
||||
"nodes":[
|
||||
{
|
||||
"extras":{
|
||||
"t3dOriginalLocalPosition__":[
|
||||
0.0,
|
||||
0.0,
|
||||
2.0
|
||||
]
|
||||
},
|
||||
"mesh":0,
|
||||
"name":"Room",
|
||||
"translation":[
|
||||
0,
|
||||
2,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"extensions":{
|
||||
"KHR_lights_punctual":{
|
||||
"light":0
|
||||
}
|
||||
},
|
||||
"extras":{
|
||||
"t3dOriginalLocalPosition__":[
|
||||
0.0,
|
||||
0.0,
|
||||
2.0
|
||||
]
|
||||
},
|
||||
"name":"Light",
|
||||
"rotation":[
|
||||
-0.28416627645492554,
|
||||
0.7269423007965088,
|
||||
0.34203392267227173,
|
||||
0.5232754945755005
|
||||
],
|
||||
"translation":[
|
||||
0,
|
||||
2,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"camera":0,
|
||||
"extras":{
|
||||
"t3dOriginalLocalPosition__":[
|
||||
0.0,
|
||||
-12.718420028686523,
|
||||
14.718420028686523
|
||||
]
|
||||
},
|
||||
"name":"Camera",
|
||||
"rotation":[
|
||||
-0.3826834261417389,
|
||||
0,
|
||||
0,
|
||||
0.9238795638084412
|
||||
],
|
||||
"translation":[
|
||||
0,
|
||||
14.718420028686523,
|
||||
12.718420028686523
|
||||
]
|
||||
},
|
||||
{
|
||||
"extras":{
|
||||
"t3dVisible__":0,
|
||||
"t3dBoundsType__":1,
|
||||
"t3dOriginalLocalPosition__":[
|
||||
0.5,
|
||||
-0.5,
|
||||
0.5
|
||||
]
|
||||
},
|
||||
"mesh":1,
|
||||
"name":"Heart",
|
||||
"translation":[
|
||||
0.5,
|
||||
0.5,
|
||||
0.5
|
||||
]
|
||||
}
|
||||
],
|
||||
"cameras":[
|
||||
{
|
||||
"name":"Camera",
|
||||
"perspective":{
|
||||
"aspectRatio":1.7777777777777777,
|
||||
"yfov":0.39959652046304894,
|
||||
"zfar":100,
|
||||
"znear":0.10000000149011612
|
||||
},
|
||||
"type":"perspective"
|
||||
}
|
||||
],
|
||||
"materials":[
|
||||
{
|
||||
"name":"Room",
|
||||
"pbrMetallicRoughness":{
|
||||
"metallicFactor":0,
|
||||
"roughnessFactor":0.5
|
||||
}
|
||||
}
|
||||
],
|
||||
"meshes":[
|
||||
{
|
||||
"extras":{
|
||||
"t3dVertexColorNames__":[
|
||||
"Col"
|
||||
],
|
||||
"t3dActiveVertexColorIndex__":0
|
||||
},
|
||||
"name":"Cube",
|
||||
"primitives":[
|
||||
{
|
||||
"attributes":{
|
||||
"COLOR_0":0,
|
||||
"POSITION":1,
|
||||
"NORMAL":2,
|
||||
"TEXCOORD_0":3
|
||||
},
|
||||
"indices":4,
|
||||
"material":0
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name":"Cube.001",
|
||||
"primitives":[
|
||||
{
|
||||
"attributes":{
|
||||
"POSITION":5,
|
||||
"NORMAL":6,
|
||||
"TEXCOORD_0":7
|
||||
},
|
||||
"indices":8
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"accessors":[
|
||||
{
|
||||
"bufferView":0,
|
||||
"componentType":5123,
|
||||
"count":196,
|
||||
"normalized":true,
|
||||
"type":"VEC4"
|
||||
},
|
||||
{
|
||||
"bufferView":1,
|
||||
"componentType":5126,
|
||||
"count":196,
|
||||
"max":[
|
||||
2,
|
||||
2,
|
||||
2
|
||||
],
|
||||
"min":[
|
||||
-2,
|
||||
-2,
|
||||
-2
|
||||
],
|
||||
"type":"VEC3"
|
||||
},
|
||||
{
|
||||
"bufferView":2,
|
||||
"componentType":5126,
|
||||
"count":196,
|
||||
"type":"VEC3"
|
||||
},
|
||||
{
|
||||
"bufferView":3,
|
||||
"componentType":5126,
|
||||
"count":196,
|
||||
"type":"VEC2"
|
||||
},
|
||||
{
|
||||
"bufferView":4,
|
||||
"componentType":5123,
|
||||
"count":636,
|
||||
"type":"SCALAR"
|
||||
},
|
||||
{
|
||||
"bufferView":5,
|
||||
"componentType":5126,
|
||||
"count":24,
|
||||
"max":[
|
||||
0.25,
|
||||
0.25,
|
||||
0.25
|
||||
],
|
||||
"min":[
|
||||
-0.25,
|
||||
-0.25,
|
||||
-0.25
|
||||
],
|
||||
"type":"VEC3"
|
||||
},
|
||||
{
|
||||
"bufferView":6,
|
||||
"componentType":5126,
|
||||
"count":24,
|
||||
"type":"VEC3"
|
||||
},
|
||||
{
|
||||
"bufferView":7,
|
||||
"componentType":5126,
|
||||
"count":24,
|
||||
"type":"VEC2"
|
||||
},
|
||||
{
|
||||
"bufferView":8,
|
||||
"componentType":5123,
|
||||
"count":36,
|
||||
"type":"SCALAR"
|
||||
}
|
||||
],
|
||||
"bufferViews":[
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":1568,
|
||||
"byteOffset":0,
|
||||
"target":34962
|
||||
},
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":2352,
|
||||
"byteOffset":1568,
|
||||
"target":34962
|
||||
},
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":2352,
|
||||
"byteOffset":3920,
|
||||
"target":34962
|
||||
},
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":1568,
|
||||
"byteOffset":6272,
|
||||
"target":34962
|
||||
},
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":1272,
|
||||
"byteOffset":7840,
|
||||
"target":34963
|
||||
},
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":288,
|
||||
"byteOffset":9112,
|
||||
"target":34962
|
||||
},
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":288,
|
||||
"byteOffset":9400,
|
||||
"target":34962
|
||||
},
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":192,
|
||||
"byteOffset":9688,
|
||||
"target":34962
|
||||
},
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":72,
|
||||
"byteOffset":9880,
|
||||
"target":34963
|
||||
}
|
||||
],
|
||||
"buffers":[
|
||||
{
|
||||
"byteLength":9952,
|
||||
"uri":"scene.bin"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -2,6 +2,7 @@ package main
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"embed"
|
||||
|
||||
_ "embed"
|
||||
|
||||
|
@ -14,11 +15,8 @@ import (
|
|||
"github.com/hajimehoshi/ebiten/v2/inpututil"
|
||||
)
|
||||
|
||||
//go:embed heart.png
|
||||
var heartImg []byte
|
||||
|
||||
//go:embed scene.gltf
|
||||
var scene []byte
|
||||
//go:embed assets
|
||||
var assets embed.FS
|
||||
|
||||
type Game struct {
|
||||
Scene *tetra3d.Scene
|
||||
|
@ -41,7 +39,7 @@ func NewGame() *Game {
|
|||
|
||||
func (g *Game) Init() {
|
||||
|
||||
scene, err := tetra3d.LoadGLTFData(scene, nil)
|
||||
scene, err := tetra3d.LoadGLTFFile(assets, "assets/scene.gltf", nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -49,6 +47,11 @@ func (g *Game) Init() {
|
|||
|
||||
g.Camera = g.Scene.Root.Get("Camera").(*tetra3d.Camera)
|
||||
|
||||
heartImg, err := assets.ReadFile("assets/heart.png")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
reader := bytes.NewReader(heartImg)
|
||||
newImg, _, err := ebitenutil.NewImageFromReader(reader)
|
||||
if err != nil {
|
||||
|
@ -104,7 +107,7 @@ func (g *Game) Draw(screen *ebiten.Image) {
|
|||
g.Camera.RenderScene(g.Scene)
|
||||
|
||||
// Draw the sprite after the rest of the scene.
|
||||
g.Camera.DrawSprite3D(
|
||||
g.Camera.RenderSprite3D(
|
||||
g.Camera.ColorTexture(),
|
||||
tetra3d.DrawSprite3dSettings{
|
||||
Image: g.HeartSprite,
|
||||
|
|
0
examples/animatedTextures/character.png → examples/animatedTextures/assets/character.png
Executable file → Normal file
Before Width: | Height: | Size: 288 B After Width: | Height: | Size: 288 B |
Before Width: | Height: | Size: 295 B After Width: | Height: | Size: 295 B |
|
@ -1,6 +1,7 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"embed"
|
||||
_ "embed"
|
||||
|
||||
"github.com/solarlune/tetra3d"
|
||||
|
@ -23,8 +24,8 @@ type Game struct {
|
|||
Character *tetra3d.Model
|
||||
}
|
||||
|
||||
//go:embed animatedTextures.gltf
|
||||
var libraryData []byte
|
||||
//go:embed assets
|
||||
var assets embed.FS
|
||||
|
||||
func NewGame() *Game {
|
||||
game := &Game{}
|
||||
|
@ -36,7 +37,7 @@ func NewGame() *Game {
|
|||
|
||||
func (g *Game) Init() {
|
||||
|
||||
library, err := tetra3d.LoadGLTFData(libraryData, nil)
|
||||
library, err := tetra3d.LoadGLTFFile(assets, "assets/animatedTextures.glb", nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
|
Before Width: | Height: | Size: 195 B After Width: | Height: | Size: 195 B |
|
@ -1,6 +1,7 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"embed"
|
||||
_ "embed"
|
||||
|
||||
"github.com/solarlune/tetra3d"
|
||||
|
@ -19,8 +20,8 @@ type Game struct {
|
|||
System examples.BasicSystemHandler
|
||||
}
|
||||
|
||||
//go:embed animations.gltf
|
||||
var gltf []byte
|
||||
//go:embed assets
|
||||
var assets embed.FS
|
||||
|
||||
func NewGame() *Game {
|
||||
game := &Game{}
|
||||
|
@ -30,7 +31,7 @@ func NewGame() *Game {
|
|||
|
||||
func (g *Game) Init() {
|
||||
|
||||
library, err := tetra3d.LoadGLTFData(gltf, nil)
|
||||
library, err := tetra3d.LoadGLTFFile(assets, "assets/animations.glb", nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ type Game struct {
|
|||
System examples.BasicSystemHandler
|
||||
}
|
||||
|
||||
//go:embed autobatch.gltf
|
||||
//go:embed autobatch.glb
|
||||
var libraryData []byte
|
||||
|
||||
func NewGame() *Game {
|
||||
|
|
Before Width: | Height: | Size: 459 B After Width: | Height: | Size: 459 B |
Before Width: | Height: | Size: 670 B After Width: | Height: | Size: 670 B |
Before Width: | Height: | Size: 350 B After Width: | Height: | Size: 350 B |
|
@ -1,6 +1,7 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"embed"
|
||||
_ "embed"
|
||||
|
||||
"github.com/solarlune/tetra3d"
|
||||
|
@ -11,8 +12,8 @@ import (
|
|||
"github.com/hajimehoshi/ebiten/v2/inpututil"
|
||||
)
|
||||
|
||||
//go:embed baking.gltf
|
||||
var gltfData []byte
|
||||
//go:embed assets
|
||||
var assetData embed.FS
|
||||
|
||||
type Game struct {
|
||||
Library *tetra3d.Library
|
||||
|
@ -39,7 +40,7 @@ const (
|
|||
|
||||
func (g *Game) Init() {
|
||||
|
||||
library, err := tetra3d.LoadGLTFData(gltfData, nil)
|
||||
library, err := tetra3d.LoadGLTFFile(assetData, "assets/baking.glb", nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ type Game struct {
|
|||
BG *ebiten.Image
|
||||
}
|
||||
|
||||
//go:embed blendmodes.gltf
|
||||
//go:embed blendmodes.glb
|
||||
var gltfData []byte
|
||||
|
||||
//go:embed bg.png
|
||||
|
|
|
@ -13,7 +13,7 @@ import (
|
|||
"github.com/hajimehoshi/ebiten/v2/inpututil"
|
||||
)
|
||||
|
||||
//go:embed bounds.gltf
|
||||
//go:embed bounds.glb
|
||||
var gltfData []byte
|
||||
|
||||
type Game struct {
|
||||
|
|
|
@ -1,542 +0,0 @@
|
|||
{
|
||||
"asset":{
|
||||
"generator":"Khronos glTF Blender I/O v3.5.21",
|
||||
"version":"2.0"
|
||||
},
|
||||
"extensionsUsed":[
|
||||
"KHR_lights_punctual"
|
||||
],
|
||||
"extensionsRequired":[
|
||||
"KHR_lights_punctual"
|
||||
],
|
||||
"extensions":{
|
||||
"KHR_lights_punctual":{
|
||||
"lights":[
|
||||
{
|
||||
"color":[
|
||||
1,
|
||||
1,
|
||||
1
|
||||
],
|
||||
"intensity":79.57747154594767,
|
||||
"type":"point",
|
||||
"name":"Light"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"scene":0,
|
||||
"scenes":[
|
||||
{
|
||||
"extras":{
|
||||
"t3dExportFormat__":2,
|
||||
"t3dExportOnSave__":1,
|
||||
"t3dRenderResolutionH__":360,
|
||||
"t3dCollections__":{
|
||||
"Collection":{
|
||||
"objects":[
|
||||
"Cube",
|
||||
"Light",
|
||||
"Shallow",
|
||||
"Cube.001",
|
||||
"Cube.002",
|
||||
"Orthographic",
|
||||
"Wide Angle",
|
||||
"Cube.003",
|
||||
"Cube.004",
|
||||
"Cube.005",
|
||||
"Super Wide Angle",
|
||||
"Cube.006",
|
||||
"Cube.007"
|
||||
],
|
||||
"offset":[
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
]
|
||||
}
|
||||
},
|
||||
"t3dWorlds__":{
|
||||
"World":{
|
||||
"ambient color":[
|
||||
0.05087608844041824,
|
||||
0.05087608844041824,
|
||||
0.05087608844041824,
|
||||
1.0
|
||||
],
|
||||
"ambient energy":1.0
|
||||
}
|
||||
},
|
||||
"t3dCurrentWorld__":"World"
|
||||
},
|
||||
"name":"Scene",
|
||||
"nodes":[
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
10,
|
||||
11,
|
||||
12
|
||||
]
|
||||
}
|
||||
],
|
||||
"nodes":[
|
||||
{
|
||||
"extras":{
|
||||
"t3dOriginalLocalPosition__":[
|
||||
4.25,
|
||||
0.0,
|
||||
0.0
|
||||
]
|
||||
},
|
||||
"mesh":0,
|
||||
"name":"Cube",
|
||||
"translation":[
|
||||
4.25,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"extensions":{
|
||||
"KHR_lights_punctual":{
|
||||
"light":0
|
||||
}
|
||||
},
|
||||
"extras":{
|
||||
"t3dOriginalLocalPosition__":[
|
||||
-0.03555774688720703,
|
||||
-3.2212681770324707,
|
||||
1.8544291257858276
|
||||
]
|
||||
},
|
||||
"name":"Light",
|
||||
"rotation":[
|
||||
-0.28416627645492554,
|
||||
0.7269423007965088,
|
||||
0.34203392267227173,
|
||||
0.5232754945755005
|
||||
],
|
||||
"translation":[
|
||||
-0.03555774688720703,
|
||||
1.8544291257858276,
|
||||
3.2212681770324707
|
||||
]
|
||||
},
|
||||
{
|
||||
"camera":0,
|
||||
"extras":{
|
||||
"t3dFovY__":0.6911112070083618,
|
||||
"t3dOriginalLocalPosition__":[
|
||||
0.0,
|
||||
-15.501559257507324,
|
||||
-2.416654069747892e-06
|
||||
]
|
||||
},
|
||||
"name":"Shallow",
|
||||
"translation":[
|
||||
0,
|
||||
-2.416654069747892e-06,
|
||||
15.501559257507324
|
||||
]
|
||||
},
|
||||
{
|
||||
"extras":{
|
||||
"t3dOriginalLocalPosition__":[
|
||||
-4.25,
|
||||
0.0,
|
||||
0.0
|
||||
]
|
||||
},
|
||||
"mesh":0,
|
||||
"name":"Cube.001",
|
||||
"translation":[
|
||||
-4.25,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"extras":{
|
||||
"t3dOriginalLocalPosition__":[
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
]
|
||||
},
|
||||
"mesh":0,
|
||||
"name":"Cube.002"
|
||||
},
|
||||
{
|
||||
"camera":1,
|
||||
"extras":{
|
||||
"t3dFovY__":0.6911112070083618,
|
||||
"t3dOriginalLocalPosition__":[
|
||||
0.0,
|
||||
-15.986564636230469,
|
||||
-2.416654069747892e-06
|
||||
]
|
||||
},
|
||||
"name":"Orthographic",
|
||||
"translation":[
|
||||
0,
|
||||
-2.416654069747892e-06,
|
||||
15.986564636230469
|
||||
]
|
||||
},
|
||||
{
|
||||
"camera":2,
|
||||
"extras":{
|
||||
"t3dFovY__":1.8901524543762207,
|
||||
"t3dOriginalLocalPosition__":[
|
||||
0.0,
|
||||
-5.786786079406738,
|
||||
-2.416654069747892e-06
|
||||
]
|
||||
},
|
||||
"name":"Wide Angle",
|
||||
"translation":[
|
||||
0,
|
||||
-2.416654069747892e-06,
|
||||
5.786786079406738
|
||||
]
|
||||
},
|
||||
{
|
||||
"extras":{
|
||||
"t3dOriginalLocalPosition__":[
|
||||
3.0,
|
||||
-3.0,
|
||||
0.0
|
||||
]
|
||||
},
|
||||
"mesh":0,
|
||||
"name":"Cube.003",
|
||||
"scale":[
|
||||
0.5,
|
||||
0.5,
|
||||
0.5
|
||||
],
|
||||
"translation":[
|
||||
3,
|
||||
0,
|
||||
3
|
||||
]
|
||||
},
|
||||
{
|
||||
"extras":{
|
||||
"t3dOriginalLocalPosition__":[
|
||||
-3.0,
|
||||
-3.0,
|
||||
0.0
|
||||
]
|
||||
},
|
||||
"mesh":0,
|
||||
"name":"Cube.004",
|
||||
"scale":[
|
||||
0.5,
|
||||
0.5,
|
||||
0.5
|
||||
],
|
||||
"translation":[
|
||||
-3,
|
||||
0,
|
||||
3
|
||||
]
|
||||
},
|
||||
{
|
||||
"extras":{
|
||||
"t3dOriginalLocalPosition__":[
|
||||
0.0,
|
||||
0.0,
|
||||
3.0
|
||||
]
|
||||
},
|
||||
"mesh":1,
|
||||
"name":"Cube.005",
|
||||
"translation":[
|
||||
0,
|
||||
3,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"camera":3,
|
||||
"extras":{
|
||||
"t3dFovY__":1.8901524543762207,
|
||||
"t3dOriginalLocalPosition__":[
|
||||
0.0,
|
||||
-4.786786079406738,
|
||||
-2.416654069747892e-06
|
||||
]
|
||||
},
|
||||
"name":"Super Wide Angle",
|
||||
"translation":[
|
||||
0,
|
||||
-2.416654069747892e-06,
|
||||
4.786786079406738
|
||||
]
|
||||
},
|
||||
{
|
||||
"extras":{
|
||||
"t3dOriginalLocalPosition__":[
|
||||
-2.0,
|
||||
-5.0,
|
||||
0.0
|
||||
]
|
||||
},
|
||||
"mesh":0,
|
||||
"name":"Cube.006",
|
||||
"scale":[
|
||||
0.5,
|
||||
0.5,
|
||||
0.5
|
||||
],
|
||||
"translation":[
|
||||
-2,
|
||||
0,
|
||||
5
|
||||
]
|
||||
},
|
||||
{
|
||||
"extras":{
|
||||
"t3dOriginalLocalPosition__":[
|
||||
1.9999998807907104,
|
||||
-5.0,
|
||||
0.0
|
||||
]
|
||||
},
|
||||
"mesh":0,
|
||||
"name":"Cube.007",
|
||||
"scale":[
|
||||
0.5,
|
||||
0.5,
|
||||
0.5
|
||||
],
|
||||
"translation":[
|
||||
1.9999998807907104,
|
||||
0,
|
||||
5
|
||||
]
|
||||
}
|
||||
],
|
||||
"cameras":[
|
||||
{
|
||||
"extras":{
|
||||
"t3dFOV__":23
|
||||
},
|
||||
"name":"Shallow",
|
||||
"perspective":{
|
||||
"aspectRatio":1.7777777777777777,
|
||||
"yfov":0.40142571174612823,
|
||||
"zfar":100,
|
||||
"znear":0.10000000149011612
|
||||
},
|
||||
"type":"perspective"
|
||||
},
|
||||
{
|
||||
"name":"Orthographic",
|
||||
"orthographic":{
|
||||
"xmag":5.25,
|
||||
"ymag":2.953125,
|
||||
"zfar":21.70000457763672,
|
||||
"znear":0.10000000149011612
|
||||
},
|
||||
"type":"orthographic"
|
||||
},
|
||||
{
|
||||
"extras":{
|
||||
"t3dFOV__":90
|
||||
},
|
||||
"name":"Wide",
|
||||
"perspective":{
|
||||
"aspectRatio":1.7777777777777777,
|
||||
"yfov":1.5707962410233096,
|
||||
"zfar":100,
|
||||
"znear":0.10000000149011612
|
||||
},
|
||||
"type":"perspective"
|
||||
},
|
||||
{
|
||||
"extras":{
|
||||
"t3dFOV__":90
|
||||
},
|
||||
"name":"Super Wide Angle",
|
||||
"perspective":{
|
||||
"aspectRatio":1.7777777777777777,
|
||||
"yfov":2.6354470672831827,
|
||||
"zfar":100,
|
||||
"znear":0.10000000149011612
|
||||
},
|
||||
"type":"perspective"
|
||||
}
|
||||
],
|
||||
"materials":[
|
||||
{
|
||||
"extras":{
|
||||
"t3dMaterialShadeless__":0
|
||||
},
|
||||
"name":"Material",
|
||||
"pbrMetallicRoughness":{
|
||||
"baseColorFactor":[
|
||||
0.800000011920929,
|
||||
0.800000011920929,
|
||||
0.800000011920929,
|
||||
1
|
||||
],
|
||||
"metallicFactor":0,
|
||||
"roughnessFactor":0.5
|
||||
}
|
||||
}
|
||||
],
|
||||
"meshes":[
|
||||
{
|
||||
"name":"Cube",
|
||||
"primitives":[
|
||||
{
|
||||
"attributes":{
|
||||
"POSITION":0,
|
||||
"TEXCOORD_0":1,
|
||||
"NORMAL":2
|
||||
},
|
||||
"indices":3,
|
||||
"material":0
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name":"Cube.001",
|
||||
"primitives":[
|
||||
{
|
||||
"attributes":{
|
||||
"POSITION":4,
|
||||
"TEXCOORD_0":5,
|
||||
"NORMAL":6
|
||||
},
|
||||
"indices":3,
|
||||
"material":0
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"accessors":[
|
||||
{
|
||||
"bufferView":0,
|
||||
"componentType":5126,
|
||||
"count":24,
|
||||
"max":[
|
||||
1,
|
||||
1,
|
||||
1
|
||||
],
|
||||
"min":[
|
||||
-1,
|
||||
-1,
|
||||
-1
|
||||
],
|
||||
"type":"VEC3"
|
||||
},
|
||||
{
|
||||
"bufferView":1,
|
||||
"componentType":5126,
|
||||
"count":24,
|
||||
"type":"VEC2"
|
||||
},
|
||||
{
|
||||
"bufferView":2,
|
||||
"componentType":5126,
|
||||
"count":24,
|
||||
"type":"VEC3"
|
||||
},
|
||||
{
|
||||
"bufferView":3,
|
||||
"componentType":5123,
|
||||
"count":36,
|
||||
"type":"SCALAR"
|
||||
},
|
||||
{
|
||||
"bufferView":4,
|
||||
"componentType":5126,
|
||||
"count":24,
|
||||
"max":[
|
||||
0.5,
|
||||
0.5,
|
||||
0.5
|
||||
],
|
||||
"min":[
|
||||
-0.5,
|
||||
-0.5,
|
||||
-0.5
|
||||
],
|
||||
"type":"VEC3"
|
||||
},
|
||||
{
|
||||
"bufferView":5,
|
||||
"componentType":5126,
|
||||
"count":24,
|
||||
"type":"VEC2"
|
||||
},
|
||||
{
|
||||
"bufferView":6,
|
||||
"componentType":5126,
|
||||
"count":24,
|
||||
"type":"VEC3"
|
||||
}
|
||||
],
|
||||
"bufferViews":[
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":288,
|
||||
"byteOffset":0,
|
||||
"target":34962
|
||||
},
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":192,
|
||||
"byteOffset":288,
|
||||
"target":34962
|
||||
},
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":288,
|
||||
"byteOffset":480,
|
||||
"target":34962
|
||||
},
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":72,
|
||||
"byteOffset":768,
|
||||
"target":34963
|
||||
},
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":288,
|
||||
"byteOffset":840,
|
||||
"target":34962
|
||||
},
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":192,
|
||||
"byteOffset":1128,
|
||||
"target":34962
|
||||
},
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":288,
|
||||
"byteOffset":1320,
|
||||
"target":34962
|
||||
}
|
||||
],
|
||||
"buffers":[
|
||||
{
|
||||
"byteLength":1608,
|
||||
"uri":"data:application/octet-stream;base64,AACAPwAAgD8AAIC/AACAPwAAgD8AAIC/AACAPwAAgD8AAIC/AACAPwAAgL8AAIC/AACAPwAAgL8AAIC/AACAPwAAgL8AAIC/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgL8AAIA/AACAPwAAgL8AAIA/AACAPwAAgL8AAIA/AACAvwAAgD8AAIC/AACAvwAAgD8AAIC/AACAvwAAgD8AAIC/AACAvwAAgL8AAIC/AACAvwAAgL8AAIC/AACAvwAAgL8AAIC/AACAvwAAgD8AAIA/AACAvwAAgD8AAIA/AACAvwAAgD8AAIA/AACAvwAAgL8AAIA/AACAvwAAgL8AAIA/AACAvwAAgL8AAIA/AAAgPwAAAD8AACA/AAAAPwAAID8AAAA/AADAPgAAAD8AAMA+AAAAPwAAwD4AAAA/AAAgPwAAgD4AACA/AACAPgAAID8AAIA+AADAPgAAgD4AAMA+AACAPgAAwD4AAIA+AAAgPwAAQD8AACA/AABAPwAAYD8AAAA/AAAAPgAAAD8AAMA+AABAPwAAwD4AAEA/AAAgPwAAAAAAACA/AACAPwAAYD8AAIA+AAAAPgAAgD4AAMA+AAAAAAAAwD4AAIA/AAAAAAAAAAAAAIC/AAAAAAAAgD8AAACAAACAPwAAAAAAAACAAAAAAAAAgL8AAACAAAAAAAAAAAAAAIC/AACAPwAAAAAAAACAAAAAAAAAAAAAAIA/AAAAAAAAgD8AAACAAACAPwAAAAAAAACAAAAAAAAAgL8AAACAAAAAAAAAAAAAAIA/AACAPwAAAAAAAACAAACAvwAAAAAAAACAAAAAAAAAAAAAAIC/AAAAAAAAgD8AAACAAAAAAAAAgL8AAACAAACAvwAAAAAAAACAAAAAAAAAAAAAAIC/AAAAAAAAAAAAAIA/AACAvwAAAAAAAACAAAAAAAAAgD8AAACAAAAAAAAAgL8AAACAAAAAAAAAAAAAAIA/AACAvwAAAAAAAACAAQAOABQAAQAUAAcACgAGABIACgASABYAFwATAAwAFwAMABAADwADAAkADwAJABUABQACAAgABQAIAAsAEQANAAAAEQAAAAQAAAAAPwAAAD8AAAC/AAAAPwAAAD8AAAC/AAAAPwAAAD8AAAC/AAAAPwAAAL8AAAC/AAAAPwAAAL8AAAC/AAAAPwAAAL8AAAC/AAAAPwAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAPwAAAL8AAAA/AAAAPwAAAL8AAAA/AAAAPwAAAL8AAAA/AAAAvwAAAD8AAAC/AAAAvwAAAD8AAAC/AAAAvwAAAD8AAAC/AAAAvwAAAL8AAAC/AAAAvwAAAL8AAAC/AAAAvwAAAL8AAAC/AAAAvwAAAD8AAAA/AAAAvwAAAD8AAAA/AAAAvwAAAD8AAAA/AAAAvwAAAL8AAAA/AAAAvwAAAL8AAAA/AAAAvwAAAL8AAAA/AAAgPwAAAD8AACA/AAAAPwAAID8AAAA/AADAPgAAAD8AAMA+AAAAPwAAwD4AAAA/AAAgPwAAgD4AACA/AACAPgAAID8AAIA+AADAPgAAgD4AAMA+AACAPgAAwD4AAIA+AAAgPwAAQD8AACA/AABAPwAAYD8AAAA/AAAAPgAAAD8AAMA+AABAPwAAwD4AAEA/AAAgPwAAAAAAACA/AACAPwAAYD8AAIA+AAAAPgAAgD4AAMA+AAAAAAAAwD4AAIA/AAAAAAAAAAAAAIC/AAAAAAAAgD8AAACAAACAPwAAAAAAAACAAAAAAAAAgL8AAACAAAAAAAAAAAAAAIC/AACAPwAAAAAAAACAAAAAAAAAAAAAAIA/AAAAAAAAgD8AAACAAACAPwAAAAAAAACAAAAAAAAAgL8AAACAAAAAAAAAAAAAAIA/AACAPwAAAAAAAACAAACAvwAAAAAAAACAAAAAAAAAAAAAAIC/AAAAAAAAgD8AAACAAAAAAAAAgL8AAACAAACAvwAAAAAAAACAAAAAAAAAAAAAAIC/AAAAAAAAAAAAAIA/AACAvwAAAAAAAACAAAAAAAAAgD8AAACAAAAAAAAAgL8AAACAAAAAAAAAAAAAAIA/AACAvwAAAAAAAACA"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -13,7 +13,7 @@ import (
|
|||
"github.com/hajimehoshi/ebiten/v2/inpututil"
|
||||
)
|
||||
|
||||
//go:embed cameraTest.gltf
|
||||
//go:embed cameraTest.glb
|
||||
var shapes []byte
|
||||
|
||||
type Game struct {
|
||||
|
|
72
gltf.go
|
@ -4,9 +4,11 @@ import (
|
|||
"bytes"
|
||||
"encoding/json"
|
||||
"image"
|
||||
"io"
|
||||
"io/fs"
|
||||
"log"
|
||||
"math"
|
||||
"os"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
|
@ -36,6 +38,9 @@ type GLTFLoadOptions struct {
|
|||
|
||||
// If top-level objects in collections should be renamed according to their instance objects.
|
||||
RenameCollectionObjects bool
|
||||
|
||||
rootFilename string
|
||||
externalBufferFileSystem fs.FS // The file system to use for loading external buffers; automatically set if you use LoadGLTFFile().
|
||||
}
|
||||
|
||||
// DefaultGLTFLoadOptions creates an instance of GLTFLoadOptions with some sensible defaults.
|
||||
|
@ -48,32 +53,48 @@ func DefaultGLTFLoadOptions() *GLTFLoadOptions {
|
|||
}
|
||||
}
|
||||
|
||||
// LoadGLTFFile loads a .gltf or .glb file from the filepath given, using a provided GLTFLoadOptions struct to alter how the file is loaded.
|
||||
// Passing nil for loadOptions will load the file using default load options. Unlike with DAE files, Animations (including armature-based
|
||||
// animations) and Cameras (assuming they are exported in the GLTF file) will be parsed properly.
|
||||
// LoadGLTFFile loads a .gltf or .glb file from the file system given using the filename provided.
|
||||
// The provided GLTFLoadOptions struct alters how the file is loaded.
|
||||
// Passing nil for gltfLoadOptions will load the file using default load options.
|
||||
// LoadGLTFFile properly handles .gltf + .bin file pairs.
|
||||
// LoadGLTFFile will return a Library, and an error if the process fails.
|
||||
func LoadGLTFFile(path string, loadOptions *GLTFLoadOptions) (*Library, error) {
|
||||
func LoadGLTFFile(fileSystem fs.FS, filename string, gltfLoadOptions *GLTFLoadOptions) (*Library, error) {
|
||||
|
||||
fileData, err := os.ReadFile(path)
|
||||
file, err := fileSystem.Open(filename)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return LoadGLTFData(fileData, loadOptions)
|
||||
byteString, err := io.ReadAll(file)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if gltfLoadOptions == nil {
|
||||
gltfLoadOptions = DefaultGLTFLoadOptions()
|
||||
}
|
||||
|
||||
gltfLoadOptions.externalBufferFileSystem = fileSystem
|
||||
gltfLoadOptions.rootFilename = filename
|
||||
|
||||
return LoadGLTFData(byteString, gltfLoadOptions)
|
||||
|
||||
}
|
||||
|
||||
// LoadGLTFData loads a .gltf or .glb file from the byte data given, using a provided GLTFLoadOptions struct to alter how the file is loaded.
|
||||
// Passing nil for loadOptions will load the file using default load options. Unlike with DAE files, Animations (including armature-based
|
||||
// animations) and Cameras (assuming they are exported in the GLTF file) will be parsed properly.
|
||||
// LoadGLTFFile will not work by default with external byte information buffers (i.e. .gltf and .glb file pairs)
|
||||
// as the buffer is referenced in .gltf as just a filename. To handle this properly, load the .gltf file using LoadGLTFFile().
|
||||
// LoadGLTFFile will return a Library, and an error if the process fails.
|
||||
func LoadGLTFData(data []byte, gltfLoadOptions *GLTFLoadOptions) (*Library, error) {
|
||||
|
||||
decoder := gltf.NewDecoder(bytes.NewReader(data))
|
||||
|
||||
doc := gltf.NewDocument()
|
||||
|
||||
decoder := gltf.NewDecoder(bytes.NewReader(data))
|
||||
|
||||
err := decoder.Decode(doc)
|
||||
|
||||
if err != nil {
|
||||
|
@ -82,6 +103,31 @@ func LoadGLTFData(data []byte, gltfLoadOptions *GLTFLoadOptions) (*Library, erro
|
|||
|
||||
if gltfLoadOptions == nil {
|
||||
gltfLoadOptions = DefaultGLTFLoadOptions()
|
||||
} else if gltfLoadOptions.externalBufferFileSystem != nil {
|
||||
|
||||
for _, buffer := range doc.Buffers {
|
||||
|
||||
// We need to load this buffer
|
||||
if buffer.URI != "" && len(buffer.Data) == 0 {
|
||||
|
||||
// We get the base directory for the loaded filename
|
||||
dir, _ := path.Split(gltfLoadOptions.rootFilename)
|
||||
|
||||
openedFile, err := gltfLoadOptions.externalBufferFileSystem.Open(path.Join(dir, buffer.URI))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
bytesData, err := io.ReadAll(openedFile)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
buffer.Data = bytesData
|
||||
continue
|
||||
// decoder = gltf.NewDecoderFS(bytes.NewReader(data), gltfLoadOptions.externalBufferFileSystem)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
library := NewLibrary()
|
||||
|
@ -139,9 +185,15 @@ func LoadGLTFData(data []byte, gltfLoadOptions *GLTFLoadOptions) (*Library, erro
|
|||
|
||||
}
|
||||
|
||||
exportFormat := 0 // 0 = GLB, 1 = GLTF Separate
|
||||
|
||||
if format, exists := globalExporterSettings["t3dExportFormat__"]; exists {
|
||||
exportFormat = int(format.(float64))
|
||||
}
|
||||
|
||||
if et, exists := globalExporterSettings["t3dPackTextures__"]; exists {
|
||||
t3dExport = true
|
||||
exportedTextures = et.(bool)
|
||||
exportedTextures = et.(bool) && exportFormat == 0
|
||||
}
|
||||
|
||||
if col, exists := globalExporterSettings["t3dCollections__"]; exists {
|
||||
|
|
|
@ -54,6 +54,7 @@ type Material struct {
|
|||
Fogless bool // If the material should be fogless or not
|
||||
Blend ebiten.Blend // Blend mode to use when rendering the material (i.e. additive, multiplicative, etc)
|
||||
BillboardMode int // Billboard mode
|
||||
Visible bool // Whether the material is visible or not
|
||||
|
||||
// fragmentShader represents a shader used to render the material with. This shader is activated after rendering
|
||||
// to the depth texture, but before compositing the finished render to the screen after fog.
|
||||
|
@ -101,6 +102,7 @@ func NewMaterial(name string) *Material {
|
|||
FragmentShaderOptions: &ebiten.DrawTrianglesShaderOptions{},
|
||||
FragmentShaderOn: true,
|
||||
Blend: ebiten.BlendSourceOver,
|
||||
Visible: true,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -132,6 +134,7 @@ func (material *Material) Clone() *Material {
|
|||
for k, v := range newMat.FragmentShaderOptions.Uniforms {
|
||||
newMat.FragmentShaderOptions.Uniforms[k] = v
|
||||
}
|
||||
newMat.Visible = material.Visible
|
||||
|
||||
return newMat
|
||||
}
|
||||
|
|
|
@ -228,6 +228,7 @@ func (matrix Matrix4) Transposed() Matrix4 {
|
|||
|
||||
// }
|
||||
|
||||
// Inverted returns an inverted version of the Matrix4.
|
||||
// The ultimate sin; I'm just going to copy this code for inverting a 4x4 Matrix and call it a day.
|
||||
// This code was obtained from https://stackoverflow.com/questions/1148309/inverting-a-4x4-matrix,
|
||||
// and is like 200x faster than my old inversion code, whaaaaa
|
||||
|
|
9
mesh.go
|
@ -736,7 +736,7 @@ func (vs *VertexSelection) ForEachIndex(forEach func(index int)) {
|
|||
}
|
||||
}
|
||||
|
||||
// NewCubeMesh creates a new Cube Mesh and gives it a new material (suitably named "Cube").
|
||||
// NewCubeMesh creates a new 2x2x2 Cube Mesh and gives it a new material (suitably named "Cube").
|
||||
func NewCubeMesh() *Mesh {
|
||||
|
||||
mesh := NewMesh("Cube",
|
||||
|
@ -1513,6 +1513,13 @@ func (part *MeshPart) primaryDimensions() (float64, float64) {
|
|||
|
||||
}
|
||||
|
||||
func (p *MeshPart) isVisible() bool {
|
||||
if p.Material != nil {
|
||||
return p.Material.Visible
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
type VertexInfo struct {
|
||||
ID int
|
||||
X, Y, Z float64
|
||||
|
|
2
model.go
|
@ -584,7 +584,7 @@ func (model *Model) ProcessVertices(vpMatrix Matrix4, camera *Camera, meshPart *
|
|||
|
||||
mesh.vertexTransforms[tri.VertexIndices[i]] = vpMatrix.MultVecW(vertPos)
|
||||
|
||||
camera.DebugInfo.animationTime += time.Since(t)
|
||||
camera.DebugInfo.currentAnimationTime += time.Since(t)
|
||||
|
||||
skinnedTriCenter = skinnedTriCenter.Add(vertPos)
|
||||
|
||||
|
|
|
@ -303,6 +303,7 @@ The following is a rough to-do list (tasks with checks have been implemented):
|
|||
- [x] -- Sectors - The general idea is that the camera can be set up to only render sectors that it's in / neighboring (up to a customizeable depth)
|
||||
- [ ] -- -- Some method to have objects appear in multiple Sectors, but not others?
|
||||
- [ ] -- Occlusion culling - this should be possible using octrees to determine if an object is visible before rendering it; see: https://www.gamedeveloper.com/programming/occlusion-culling-algorithms
|
||||
- [ ] -- -- Something to reduce overdraw
|
||||
- [X] **Debug**
|
||||
- [X] -- Debug text: overall render time, FPS, render call count, vertex count, triangle count, skipped triangle count
|
||||
- [X] -- Wireframe debug rendering
|
||||
|
|
59
tetra3d.py
|
@ -20,22 +20,21 @@ bl_info = {
|
|||
}
|
||||
|
||||
objectTypes = [
|
||||
("MESH", "Mesh", "A standard, visible mesh object", 0, 0),
|
||||
("GRID", "Grid", "A grid object; not visualized or 'physically present'. The vertices in Blender become grid points in Tetra3D; the edges become their connections", 0, 1),
|
||||
("MESH", "Mesh", "A standard, visible mesh object.", 0, 0),
|
||||
("GRID", "Grid", "A grid object; not visualized or 'physically present'. The vertices in Blender become grid points in Tetra3D; the edges become their connections.", 0, 1),
|
||||
]
|
||||
|
||||
boundsTypes = [
|
||||
("NONE", "No Bounds", "No collision will be created for this object.", 0, 0),
|
||||
("AABB", "AABB", "An AABB (axis-aligned bounding box). If the size isn't customized, it will be big enough to fully contain the mesh of the current object. Currently buggy when resolving intersections between AABB or other Triangle Nodes", 0, 1),
|
||||
("CAPSULE", "Capsule", "A capsule, which can rotate. If the radius and height are not set, it will have a radius and height to fully contain the current object", 0, 2),
|
||||
("SPHERE", "Sphere", "A sphere. If the radius is not custom set, it will have a large enough radius to fully contain the provided object", 0, 3),
|
||||
("TRIANGLES", "Triangle Mesh", "A triangle mesh bounds type. Only works on mesh-type objects (i.e. an Empty won't generate a BoundingTriangles). Accurate, but slow. Currently buggy when resolving intersections between AABB or other Triangle Nodes", 0, 4),
|
||||
("AABB", "AABB", "An AABB (axis-aligned bounding box). If the size isn't customized, it will be big enough to fully contain the mesh of the current object. Currently buggy when resolving intersections between AABB or other Triangle Nodes.", 0, 1),
|
||||
("CAPSULE", "Capsule", "A capsule, which can rotate. If the radius and height are not set, it will have a radius and height to fully contain the current object.", 0, 2),
|
||||
("SPHERE", "Sphere", "A sphere. If the radius is not custom set, it will have a large enough radius to fully contain the provided object.", 0, 3),
|
||||
("TRIANGLES", "Triangle Mesh", "A triangle mesh bounds type. Only works on mesh-type objects (i.e. an Empty won't generate a BoundingTriangles). Accurate, but slow. Currently buggy when resolving intersections between AABB or other Triangle Nodes.", 0, 4),
|
||||
]
|
||||
|
||||
gltfExportTypes = [
|
||||
("GLB", ".glb", "Exports a single file, with all data packed in binary form. Most efficient and portable, but more difficult to edit later", 0, 0),
|
||||
("GLTF_SEPARATE", ".gltf + .bin + textures", "Exports multiple files, with separate JSON, binary and texture data. Easiest to edit later - Note that Tetra3D doesn't support this properly currently", 0, 1),
|
||||
("GLTF_EMBEDDED", ".gltf", "Exports a single file, with all data packed in JSON. Less efficient than binary, but easier to edit later", 0, 2),
|
||||
("GLB", ".glb", "Exports a single file, with all data packed in binary form. Textures can be packed into the file. Most efficient and portable, but more difficult to edit later.", 0, 0),
|
||||
("GLTF_SEPARATE", ".gltf + .bin + external textures", "Exports multiple files, with separate JSON, binary and texture data. Easiest to edit later.", 0, 1),
|
||||
]
|
||||
|
||||
sectorDetectionType = [
|
||||
|
@ -44,10 +43,10 @@ sectorDetectionType = [
|
|||
]
|
||||
|
||||
materialBlendModes = [
|
||||
("DEFAULT", "Default", "Blends the destination by the material's color modulated by the material's alpha value. The default alpha-blending composite mode. Also known as BlendSourceOver", 0, 0),
|
||||
("ADDITIVE", "Additive", "Adds the material's color to the destination. Also known as BlendLighter", 0, 1),
|
||||
("MULTIPLY", "Multiply", "Multiplies the material's color by the destination. Known as Multiply compositing using a custom Blend object", 0, 2),
|
||||
("CLEAR", "Clear", "Anywhere the material draws is cleared instead; useful to 'punch through' a scene to show the blank alpha zero. Also known as BlendClear", 0, 3),
|
||||
("DEFAULT", "Default", "Blends the destination by the material's color modulated by the material's alpha value. The default alpha-blending composite mode. Also known as BlendSourceOver.", 0, 0),
|
||||
("ADDITIVE", "Additive", "Adds the material's color to the destination. Also known as BlendLighter.", 0, 1),
|
||||
("MULTIPLY", "Multiply", "Multiplies the material's color by the destination. Known as Multiply compositing using a custom Blend object.", 0, 2),
|
||||
("CLEAR", "Clear", "Anywhere the material draws is cleared instead; useful to 'punch through' a scene to show the blank alpha zero. Also known as BlendClear.", 0, 3),
|
||||
]
|
||||
|
||||
materialBillboardModes = [
|
||||
|
@ -59,22 +58,22 @@ materialBillboardModes = [
|
|||
|
||||
materialLightingModes = [
|
||||
("DEFAULT", "Default", "Default lighting; light is dependent on normal of lit faces.", 0, 0),
|
||||
("NORMAL", "Point Towards Lights", "Lighting acts as though faces always face light sources. Particularly useful for billboarded 2D sprites", 0, 1),
|
||||
("NORMAL", "Point Towards Lights", "Lighting acts as though faces always face light sources. Particularly useful for billboarded 2D sprites.", 0, 1),
|
||||
("DOUBLE", "Double-Sided", "Double-sided lighting; lighting is dependent on normal of lit faces, but on both sides of a face.", 0, 2),
|
||||
]
|
||||
|
||||
worldFogCompositeModes = [
|
||||
("OFF", "Off", "No fog. Object colors aren't changed with distance from the camera", 0, 0),
|
||||
("ADDITIVE", "Additive", "Additive fog - this fog mode brightens objects in the distance, with full effect being adding the color given to the object's color at maximum distance (according to the camera's far range)", 0, 1),
|
||||
("SUBTRACT", "Subtractive", "Subtractive fog - this fog mode darkens objects in the distance, with full effect being subtracting the object's color by the fog color at maximum distance (according to the camera's far range)", 0, 2),
|
||||
("OVERWRITE", "Overwrite", "Overwrite fog - this fog mode overwrites the object's color with the fog color, with maximum distance being the camera's far distance", 0, 3),
|
||||
("OFF", "Off", "No fog. Object colors aren't changed with distance from the camera.", 0, 0),
|
||||
("ADDITIVE", "Additive", "Additive fog - this fog mode brightens objects in the distance, with full effect being adding the color given to the object's color at maximum distance (according to the camera's far range).", 0, 1),
|
||||
("SUBTRACT", "Subtractive", "Subtractive fog - this fog mode darkens objects in the distance, with full effect being subtracting the object's color by the fog color at maximum distance (according to the camera's far range).", 0, 2),
|
||||
("OVERWRITE", "Overwrite", "Overwrite fog - this fog mode overwrites the object's color with the fog color, with maximum distance being the camera's far distance.", 0, 3),
|
||||
("TRANSPARENT", "Transparent", "Transparent fog - this fog mode fades the object out over distance, such that at maximum distance / fog range, the object is wholly transparent.", 0, 4),
|
||||
]
|
||||
|
||||
worldFogCurveTypes = [
|
||||
("LINEAR", "Smooth", "Smooth fog (Ease: Linear); this goes from 0% in the near range to 100% in the far range evenly", "LINCURVE", 0),
|
||||
("OUTCIRC", "Dense", "Dense fog (Ease: Out Circ); fog will increase aggressively in the near range, ramping up to 100% at the far range", "SPHERECURVE", 1),
|
||||
("INCIRC", "Light", "Light fog (Ease: In Circ); fog will increase aggressively towards the far range, ramping up to 100% at the far range", "SHARPCURVE", 2),
|
||||
("LINEAR", "Smooth", "Smooth fog (Ease: Linear); this goes from 0% in the near range to 100% in the far range evenly.", "LINCURVE", 0),
|
||||
("OUTCIRC", "Dense", "Dense fog (Ease: Out Circ); fog will increase aggressively in the near range, ramping up to 100% at the far range.", "SPHERECURVE", 1),
|
||||
("INCIRC", "Light", "Light fog (Ease: In Circ); fog will increase aggressively towards the far range, ramping up to 100% at the far range.", "SHARPCURVE", 2),
|
||||
]
|
||||
|
||||
gamePropTypes = [
|
||||
|
@ -89,9 +88,9 @@ gamePropTypes = [
|
|||
]
|
||||
|
||||
batchModes = [
|
||||
("OFF", "Off", "No automatic batching", 0, 0),
|
||||
("DYNAMIC", "Dynamic Batching", "Dynamic batching based off of one material (the first one)", 0, 1),
|
||||
("STATIC", "Static Merging", "Static merging; merged objects cannot move or deviate in any way. After automatic static merging, the merged models will be automatically set to invisible", 0, 2),
|
||||
("OFF", "Off", "No automatic batching.", 0, 0),
|
||||
("DYNAMIC", "Dynamic Batching", "Dynamic batching based off of one material (the first one).", 0, 1),
|
||||
("STATIC", "Static Merging", "Static merging; merged objects cannot move or deviate in any way. After automatic static merging, the merged models will be automatically set to invisible.", 0, 2),
|
||||
]
|
||||
|
||||
def filepathSet(self, value):
|
||||
|
@ -798,6 +797,7 @@ class MATERIAL_PT_tetra3d(bpy.types.Panel):
|
|||
row.prop(context.material, "t3dMaterialFogless__")
|
||||
row = self.layout.row()
|
||||
row.prop(context.material, "use_backface_culling")
|
||||
row.prop(context.material, "t3dVisible__")
|
||||
row = self.layout.row()
|
||||
row.label(text="Transparency Mode:")
|
||||
row.prop(context.material, "blend_method", text="")
|
||||
|
@ -931,7 +931,10 @@ class RENDER_PT_tetra3d(bpy.types.Panel):
|
|||
row.prop(context.scene, "t3dExportFormat__")
|
||||
|
||||
box = self.layout.box()
|
||||
box.prop(context.scene, "t3dPackTextures__")
|
||||
row = box.row()
|
||||
row.active = context.scene.t3dExportFormat__ == "GLB"
|
||||
row.prop(context.scene, "t3dPackTextures__")
|
||||
|
||||
box.prop(context.scene, "t3dExportCameras__")
|
||||
box.prop(context.scene, "t3dExportLights__")
|
||||
box.prop(context.scene, "t3dPerspectiveCorrectedTextureMapping__")
|
||||
|
@ -1017,7 +1020,7 @@ def export():
|
|||
|
||||
if scene.t3dExportFormat__ == "GLB":
|
||||
ending = ".glb"
|
||||
elif scene.t3dExportFormat__ == "GLTF_SEPARATE" or scene.t3dExportFormat__ == "GLTF_EMBEDDED":
|
||||
elif scene.t3dExportFormat__ == "GLTF_SEPARATE":
|
||||
ending = ".gltf"
|
||||
|
||||
newPath = os.path.splitext(blendPath)[0] + ending
|
||||
|
@ -1921,7 +1924,7 @@ def register():
|
|||
bpy.types.Scene.t3dExportFilepath__ = bpy.props.StringProperty(name="Export Filepath", description="Filepath to export GLTF file. If left blank, it will export to the same directory as the blend file and will have the same filename; in this case, if the blend file has not been saved, nothing will happen",
|
||||
default="", subtype="FILE_PATH", get=getExportFilepath, set=setExportFilepath)
|
||||
|
||||
bpy.types.Scene.t3dExportFormat__ = bpy.props.EnumProperty(items=gltfExportTypes, name="Export Format", description="What format to export the file in", default="GLTF_EMBEDDED",
|
||||
bpy.types.Scene.t3dExportFormat__ = bpy.props.EnumProperty(items=gltfExportTypes, name="Export Format", description="What format to export the file in", default="GLB",
|
||||
get=getExportFormat, set=setExportFormat)
|
||||
|
||||
bpy.types.Scene.t3dExportCameras__ = bpy.props.BoolProperty(name="Export Cameras", description="Whether Blender should export cameras to the GLTF file", default=True,
|
||||
|
@ -1978,6 +1981,7 @@ def register():
|
|||
bpy.types.Material.t3dCustomDepthOn__ = bpy.props.BoolProperty(name="Custom Depth", description="Whether custom depth offsetting should be enabled", default=False)
|
||||
bpy.types.Material.t3dCustomDepthValue__ = bpy.props.FloatProperty(name="Depth Offset Value", description="How far in world units the material should offset when rendering (negative values are closer to the camera, positive values are further)")
|
||||
bpy.types.Material.t3dMaterialLightingMode__ = bpy.props.EnumProperty(items=materialLightingModes, name="Lighting mode", description="How materials should be lit", default="DEFAULT")
|
||||
bpy.types.Material.t3dVisible__ = bpy.props.BoolProperty(name="Visible", description="Whether this material is visible", default=True)
|
||||
|
||||
bpy.types.Material.t3dAutoUV__ = bpy.props.BoolProperty(name="Auto UV-Map", description="If the UV map of the faces that use this material should automatically be Cube Projection UV mapped when exiting edit mode")
|
||||
bpy.types.Material.t3dAutoUVUnitSize__ = bpy.props.FloatProperty(name="Unit Size", description="How many Blender Units equates to one texture size", default=4.0, update=autoUVChange, step=5)
|
||||
|
@ -2084,6 +2088,7 @@ def unregister():
|
|||
del bpy.types.Material.t3dAutoUV__
|
||||
del bpy.types.Material.t3dAutoUVUnitSize__
|
||||
del bpy.types.Material.t3dAutoUVRotation__
|
||||
del bpy.types.Material.t3dVisible__
|
||||
|
||||
del bpy.types.World.t3dClearColor__
|
||||
del bpy.types.World.t3dFogColor__
|
||||
|
|