From c56fb4bbf1cd8db1c351dfe9fed25bea01631a84 Mon Sep 17 00:00:00 2001 From: luboslenco Date: Mon, 14 Oct 2019 21:21:11 +0200 Subject: [PATCH] Restore old grease pencil code --- Shaders/grease_pencil/grease_pencil.frag.glsl | 9 + Shaders/grease_pencil/grease_pencil.json | 25 +++ Shaders/grease_pencil/grease_pencil.vert.glsl | 13 ++ Sources/armory/data/GreasePencilData.hx | 178 ++++++++++++++++++ Sources/armory/object/GreasePencilObject.hx | 55 ++++++ blender/arm/exporter.py | 101 +++++++++- 6 files changed, 376 insertions(+), 5 deletions(-) create mode 100644 Shaders/grease_pencil/grease_pencil.frag.glsl create mode 100644 Shaders/grease_pencil/grease_pencil.json create mode 100644 Shaders/grease_pencil/grease_pencil.vert.glsl create mode 100644 Sources/armory/data/GreasePencilData.hx create mode 100644 Sources/armory/object/GreasePencilObject.hx diff --git a/Shaders/grease_pencil/grease_pencil.frag.glsl b/Shaders/grease_pencil/grease_pencil.frag.glsl new file mode 100644 index 00000000..8f33f41f --- /dev/null +++ b/Shaders/grease_pencil/grease_pencil.frag.glsl @@ -0,0 +1,9 @@ +#version 450 + +in vec4 color; + +out vec4 fragColor; + +void main() { + fragColor = color; +} diff --git a/Shaders/grease_pencil/grease_pencil.json b/Shaders/grease_pencil/grease_pencil.json new file mode 100644 index 00000000..a5033acf --- /dev/null +++ b/Shaders/grease_pencil/grease_pencil.json @@ -0,0 +1,25 @@ +{ + "contexts": [ + { + "name": "grease_pencil", + "depth_write": false, + "compare_mode": "always", + "cull_mode": "none", + "blend_source": "source_alpha", + "blend_destination": "inverse_source_alpha", + "blend_operation": "add", + "alpha_blend_source": "source_alpha", + "alpha_blend_destination": "inverse_source_alpha", + "alpha_blend_operation": "add", + "links": [ + { + "name": "VP", + "link": "_viewProjectionMatrix" + } + ], + "texture_params": [], + "vertex_shader": "grease_pencil.vert.glsl", + "fragment_shader": "grease_pencil.frag.glsl" + } + ] +} diff --git a/Shaders/grease_pencil/grease_pencil.vert.glsl b/Shaders/grease_pencil/grease_pencil.vert.glsl new file mode 100644 index 00000000..91b2dd4b --- /dev/null +++ b/Shaders/grease_pencil/grease_pencil.vert.glsl @@ -0,0 +1,13 @@ +#version 450 + +in vec3 pos; +in vec4 col; + +out vec4 color; + +uniform mat4 VP; + +void main() { + color = col; + gl_Position = VP * vec4(pos.xyz, 1.0); +} diff --git a/Sources/armory/data/GreasePencilData.hx b/Sources/armory/data/GreasePencilData.hx new file mode 100644 index 00000000..09bfd04a --- /dev/null +++ b/Sources/armory/data/GreasePencilData.hx @@ -0,0 +1,178 @@ +package armory.data; + +import kha.graphics4.VertexBuffer; +import kha.graphics4.IndexBuffer; +import kha.graphics4.Usage; +import kha.graphics4.VertexStructure; +import kha.graphics4.VertexData; +import kha.graphics4.PipelineState; +import kha.graphics4.CompareMode; +import kha.graphics4.CullMode; +import kha.graphics4.ConstantLocation; +import iron.math.Vec4; +import iron.object.Transform; +import iron.data.SceneFormat; +import iron.data.ShaderData; +import iron.data.ShaderData.ShaderContext; + +class GreasePencilData extends Data { + + public var name:String; + public var raw:TGreasePencilData; + public var layers:Array; + + public static var shaderData:ShaderData = null; + public static var structure:VertexStructure = null; + public static var usage:Usage; + public static var frameEnd = 0; + static var first = true; + + public function new(raw:TGreasePencilData, done:GreasePencilData->Void) { + super(); + + this.raw = raw; + this.name = raw.name; + + if (structure == null) { + structure = new VertexStructure(); + structure.add("pos", VertexData.Float3); + structure.add("col", VertexData.Float4); + usage = Usage.StaticUsage; + } + + if (first) { + first = false; + var shaderName:Array = raw.shader.split("/"); + Data.getShader(shaderName[0], shaderName[1], null, function(b:ShaderData) { + shaderData = b; + makeLayers(done); + }); + } + else makeLayers(done); + } + + function makeLayers(done:GreasePencilData->Void) { + layers = []; + for (l in raw.layers) { + layers.push(new GreasePencilLayer(l)); + } + done(this); + } + + public static function parse(name:String, id:String, done:GreasePencilData->Void) { + Data.getSceneRaw(name, function(format:TSceneFormat) { + var raw:TGreasePencilData = Data.getGreasePencilRawByName(format.grease_pencil_datas, id); + if (raw == null) { + trace('Grease pencil data "$id" not found!'); + done(null); + } + new GreasePencilData(raw, done); + }); + } + + public static function getContext(name:String):ShaderContext { + return shaderData.getContext(name); + } +} + +class GreasePencilLayer { + public var name:String; + public var frames:Array; + public var currentFrame = 0; + + public function new(l:TGreasePencilLayer) { + name = l.name; + frames = []; + for (f in l.frames) { + frames.push(new GreasePencilFrame(f)); + } + } +} + +class GreasePencilFrame { + public var vertexBuffer:VertexBuffer; + public var vertexStrokeBuffer:VertexBuffer; + public var indexBuffer:IndexBuffer; + public var raw:TGreasePencilFrame; + public var numVertices:Int; + + public function new(f:TGreasePencilFrame) { + raw = f; + var va = f.vertex_array.values; + var cola = f.col_array.values; + var colfilla = f.colfill_array.values; + var indices = f.index_array.values; + + numVertices = Std.int(va.length / 3); + + // Fill + vertexBuffer = new VertexBuffer(numVertices, GreasePencilData.structure, GreasePencilData.usage); + var vertices = vertexBuffer.lock(); + var di = -1; + for (i in 0...numVertices) { + vertices.set(++di, va[i * 3]); // Positions + vertices.set(++di, va[i * 3 + 1]); + vertices.set(++di, va[i * 3 + 2]); + vertices.set(++di, colfilla[i * 4]); // Fill color + vertices.set(++di, colfilla[i * 4 + 1]); + vertices.set(++di, colfilla[i * 4 + 2]); + vertices.set(++di, colfilla[i * 4 + 3]); + } + vertexBuffer.unlock(); + + indexBuffer = new IndexBuffer(indices.length, GreasePencilData.usage); + var indicesA = indexBuffer.lock(); + for (i in 0...indicesA.length) indicesA[i] = indices[i]; + indexBuffer.unlock(); + + // Stroke + vertexStrokeBuffer = new VertexBuffer(numVertices, GreasePencilData.structure, GreasePencilData.usage); + vertices = vertexStrokeBuffer.lock(); + di = -1; + for (i in 0...numVertices) { + vertices.set(++di, va[i * 3]); // Positions + vertices.set(++di, va[i * 3 + 1]); + vertices.set(++di, va[i * 3 + 2]); + vertices.set(++di, cola[i * 4]); // Stroke color + vertices.set(++di, cola[i * 4 + 1]); + vertices.set(++di, cola[i * 4 + 2]); + vertices.set(++di, cola[i * 4 + 3]); + } + vertexStrokeBuffer.unlock(); + + // Store max frame number of all layers + if (GreasePencilData.frameEnd < raw.frame_number) { + GreasePencilData.frameEnd = raw.frame_number; + } + } + + public function delete() { + vertexBuffer.delete(); + } +} + +typedef TGreasePencilFormat = { + @:optional var grease_pencil_datas:Array; + @:optional var grease_pencil_ref:String; +} + +typedef TGreasePencilData = { + var name:String; + var layers:Array; + var shader:String; +} + +typedef TGreasePencilLayer = { + var name:String; + var opacity:Float; + var frames:Array; +} + +typedef TGreasePencilFrame = { + var frame_number:Int; + var vertex_array:TVertexArray; + var col_array:TVertexArray; + var colfill_array:TVertexArray; + var index_array:TIndexArray; + var num_stroke_points:Uint32Array; +} diff --git a/Sources/armory/object/GreasePencilObject.hx b/Sources/armory/object/GreasePencilObject.hx new file mode 100644 index 00000000..d0658cf4 --- /dev/null +++ b/Sources/armory/object/GreasePencilObject.hx @@ -0,0 +1,55 @@ +package armory.object; + +class GreasePencilObject { + + static var gpFrame = 0; + + public function drawGreasePencil(params:Array, root:Object) { + var gp = Scene.active.greasePencil; + if (gp == null) return; + + var g = currentRenderTarget; + var lamp = getLamp(currentLampIndex); + var context = GreasePencilData.getContext(params[0]); + g.setPipeline(context.pipeState); + Uniforms.setConstants(g, context, null, camera, lamp, null); + + // Draw layers + for (layer in gp.layers) { + // Next frame + if (layer.frames.length - 1 > layer.currentFrame && gpFrame >= layer.frames[layer.currentFrame + 1].raw.frame_number) { + layer.currentFrame++; + } + var frame = layer.frames[layer.currentFrame]; + if (frame.numVertices > 0) { + + // Stroke + #if (js && kha_webgl) + // TODO: Construct triangulated lines from points instead + g.setVertexBuffer(frame.vertexStrokeBuffer); + kha.SystemImpl.gl.lineWidth(3); + var start = 0; + for (i in frame.raw.num_stroke_points) { + kha.SystemImpl.gl.drawArrays(js.html.webgl.GL.LINE_STRIP, start, i); + start += i; + } + #end + + // Fill + g.setVertexBuffer(frame.vertexBuffer); + g.setIndexBuffer(frame.indexBuffer); + g.drawIndexedVertices(); + } + } + + gpFrame++; + + // Reset timeline + if (gpFrame > GreasePencilData.frameEnd) { + gpFrame = 0; + for (layer in gp.layers) layer.currentFrame = 0; + } + + end(g); + } +} diff --git a/blender/arm/exporter.py b/blender/arm/exporter.py index aaaf46f4..8b34ed34 100755 --- a/blender/arm/exporter.py +++ b/blender/arm/exporter.py @@ -1062,7 +1062,7 @@ class ArmoryExporter: cdata[i3 ] = col[0] cdata[i3 + 1] = col[1] cdata[i3 + 2] = col[2] - + mats = exportMesh.materials poly_map = [] for i in range(max(len(mats), 1)): @@ -1071,14 +1071,14 @@ class ArmoryExporter: poly_map[poly.material_index].append(poly) o['index_arrays'] = [] - + # map polygon indices to triangle loops tri_loops = {} for loop in exportMesh.loop_triangles: if loop.polygon_index not in tri_loops: tri_loops[loop.polygon_index] = [] tri_loops[loop.polygon_index].append(loop) - + for index, polys in enumerate(poly_map): tris = 0 for poly in polys: @@ -1736,6 +1736,17 @@ class ArmoryExporter: self.post_export_world(w, o) self.output['world_datas'].append(o) + def export_grease_pencils(self): + for gpRef in bpy.data.grease_pencils: + fp = self.get_meshes_file_path('greasepencil_' + gpRef.name) + assets.add(fp) + self.output['grease_pencil_ref'] = 'greasepencil_' + gpRef.name + '/' + gpRef.name + assets.add_shader_pass('grease_pencil') + gpo = self.post_export_grease_pencil(gpRef) + gp_obj = {} + gp_obj['grease_pencil_datas'] = [gpo] + arm.utils.write_arm(fp, gp_obj) + def is_compress(self): return ArmoryExporter.compress_enabled @@ -1971,6 +1982,7 @@ class ArmoryExporter: self.export_particle_systems() self.output['world_datas'] = [] self.export_worlds() + self.export_grease_pencils() self.export_tilesheets() if self.scene.world is not None: @@ -2246,7 +2258,7 @@ class ArmoryExporter: col_mask = '' for b in bobject.arm_rb_collision_filter_mask: col_mask = ('1' if b else '0') + col_mask - + x['parameters'] = [str(shape), str(body_mass), str(rb.friction), str(rb.restitution), str(int(col_group, 2)), str(int(col_mask, 2)) ] lx = bobject.arm_rb_linear_factor[0] ly = bobject.arm_rb_linear_factor[1] @@ -2423,7 +2435,7 @@ class ArmoryExporter: bobject_eval = bobject.evaluated_get(self.depsgraph) if apply_modifiers else bobject exportMesh = bobject_eval.to_mesh() - + with open(nav_filepath, 'w') as f: for v in exportMesh.vertices: f.write("v %.4f " % (v.co[0] * bobject_eval.scale.x)) @@ -2585,6 +2597,85 @@ class ArmoryExporter: po['strength'] = strength o['probe'] = po + def post_export_grease_pencil(self, gp): + o = {} + o['name'] = gp.name + o['layers'] = [] + for layer in gp.layers: + o['layers'].append(self.export_grease_pencil_layer(layer)) + o['shader'] = 'grease_pencil/grease_pencil' + return o + + def export_grease_pencil_layer(self, layer): + lo = {} + lo['name'] = layer.info + lo['opacity'] = layer.opacity + lo['frames'] = [] + for frame in layer.frames: + if frame.frame_number > self.scene.frame_end: + break + lo['frames'].append(self.export_grease_pencil_frame(frame)) + return lo + + def export_grease_pencil_frame(self, frame): + va = [] + cola = [] + colfilla = [] + indices = [] + num_stroke_points = [] + index_offset = 0 + for stroke in frame.strokes: + for point in stroke.points: + va.append(point.co[0]) + va.append(point.co[1]) + va.append(point.co[2]) + # TODO: store index to color pallete only, this is wasteful + if stroke.color != None: + cola.append(stroke.color.color[0]) + cola.append(stroke.color.color[1]) + cola.append(stroke.color.color[2]) + cola.append(stroke.color.alpha) + colfilla.append(stroke.color.fill_color[0]) + colfilla.append(stroke.color.fill_color[1]) + colfilla.append(stroke.color.fill_color[2]) + colfilla.append(stroke.color.fill_alpha) + else: + cola.append(0.0) + cola.append(0.0) + cola.append(0.0) + cola.append(0.0) + colfilla.append(0.0) + colfilla.append(0.0) + colfilla.append(0.0) + colfilla.append(0.0) + for triangle in stroke.triangles: + indices.append(triangle.v1 + index_offset) + indices.append(triangle.v2 + index_offset) + indices.append(triangle.v3 + index_offset) + num_stroke_points.append(len(stroke.points)) + index_offset += len(stroke.points) + fo = {} + # TODO: merge into array of vertex arrays + fo['vertex_array'] = {} + fo['vertex_array']['attrib'] = 'pos' + fo['vertex_array']['size'] = 3 + fo['vertex_array']['values'] = va + fo['col_array'] = {} + fo['col_array']['attrib'] = 'col' + fo['col_array']['size'] = 4 + fo['col_array']['values'] = cola + fo['colfill_array'] = {} + fo['colfill_array']['attrib'] = 'colfill' + fo['colfill_array']['size'] = 4 + fo['colfill_array']['values'] = colfilla + fo['index_array'] = {} + fo['index_array']['material'] = 0 + fo['index_array']['size'] = 3 + fo['index_array']['values'] = indices + fo['num_stroke_points'] = num_stroke_points + fo['frame_number'] = frame.frame_number + return fo + # https://blender.stackexchange.com/questions/70629 def mod_equal(self, mod1, mod2): return all([getattr(mod1, prop, True) == getattr(mod2, prop, False) for prop in mod1.bl_rna.properties.keys()])